var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _BaseCommand_noBaseOptions;
import { existsSync } from 'fs';
import { join, relative, resolve } from 'path';
import process from 'process';
import { format } from 'util';
import { DefaultLogger, Project } from '@netlify/build-info';
import { NodeFS, NoopLogger } from '@netlify/build-info/node';
// @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module '@net... Remove this comment to see the full error message
import { resolveConfig } from '@netlify/config';
import { Command, Option } from 'commander';
// @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'debu... Remove this comment to see the full error message
import debug from 'debug';
import { findUp } from 'find-up';
import inquirer from 'inquirer';
// @ts-expect-error TS(7016) FIXME: Could not find a declaration file for module 'inqu... Remove this comment to see the full error message
import inquirerAutocompletePrompt from 'inquirer-autocomplete-prompt';
import merge from 'lodash/merge.js';
import { NetlifyAPI } from 'netlify';
import { getAgent } from '../lib/http-agent.js';
import { NETLIFY_CYAN, USER_AGENT, chalk, error, exit, getToken, log, version, normalizeConfig, padLeft, pollForToken, sortOptions, warn, } from '../utils/command-helpers.js';
import getGlobalConfig from '../utils/get-global-config.js';
import { getSiteByName } from '../utils/get-site.js';
import openBrowser from '../utils/open-browser.js';
import StateConfig from '../utils/state-config.js';
import { identify, reportError, track } from '../utils/telemetry/index.js';
// load the autocomplete plugin
inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt);
/** Netlify CLI client id. Lives in bot@netlify.com */
// TODO: setup client for multiple environments
const CLIENT_ID = 'd6f37de6614df7ae58664cfca524744d73807a377f5ee71f1a254f78412e3750';
const NANO_SECS_TO_MSECS = 1e6;
/** The fallback width for the help terminal */
const FALLBACK_HELP_CMD_WIDTH = 80;
const HELP_$ = NETLIFY_CYAN('$');
/** indent on commands or description on the help page */
const HELP_INDENT_WIDTH = 2;
/** separator width between term and description */
const HELP_SEPARATOR_WIDTH = 5;
/**
 * A list of commands where we don't have to perform the workspace selection at.
 * Those commands work with the system or are not writing any config files that need to be
 * workspace aware.
 */
const COMMANDS_WITHOUT_WORKSPACE_OPTIONS = new Set(['api', 'recipes', 'completion', 'status', 'switch', 'login', 'lm']);
/** Formats a help list correctly with the correct indent */
const formatHelpList = (textArray) => textArray.join('\n').replace(/^/gm, ' '.repeat(HELP_INDENT_WIDTH));
/** Get the duration between a start time and the current time */
const getDuration = (startTime) => {
    const durationNs = process.hrtime.bigint() - startTime;
    return Math.round(Number(durationNs / BigInt(NANO_SECS_TO_MSECS)));
};
/**
 * Retrieves a workspace package based of the filter flag that is provided.
 * If the filter flag does not match a workspace package or is not defined then it will prompt with an autocomplete to select a package
 */
async function selectWorkspace(project, filter) {
    // don't show prompt for workspace selection if there is only one package
    if (project.workspace?.packages && project.workspace.packages.length === 1) {
        return project.workspace.packages[0].path;
    }
    const selected = project.workspace?.packages.find((pkg) => {
        if (project.relativeBaseDirectory &&
            project.relativeBaseDirectory.length !== 0 &&
            pkg.path.startsWith(project.relativeBaseDirectory)) {
            return true;
        }
        return (pkg.name && pkg.name === filter) || pkg.path === filter;
    });
    if (!selected) {
        log();
        log(chalk.cyan(`We've detected multiple sites inside your repository`));
        const { result } = await inquirer.prompt({
            name: 'result',
            // @ts-expect-error TS(2769) FIXME: No overload matches this call.
            type: 'autocomplete',
            message: 'Select the site you want to work with',
            // @ts-expect-error TS(7006) FIXME: Parameter '_' implicitly has an 'any' type.
            source: (/** @type {string} */ _, input = '') => (project.workspace?.packages || [])
                .filter((pkg) => pkg.path.includes(input))
                .map((pkg) => ({
                name: `${pkg.name ? `${chalk.bold(pkg.name)}  ` : ''}${pkg.path}  ${chalk.dim(`--filter ${pkg.name || pkg.path}`)}`,
                value: pkg.path,
            })),
        });
        return result;
    }
    return selected.path;
}
async function getRepositoryRoot(cwd) {
    const res = await findUp('.git', { cwd, type: 'directory' });
    if (res) {
        return join(res, '..');
    }
}
/** Base command class that provides tracking and config initialization */
class BaseCommand extends Command {
    constructor() {
        super(...arguments);
        this.analytics = { startTime: process.hrtime.bigint() };
        /**
         * The working directory that is used for reading the `netlify.toml` file and storing the state.
         * In a monorepo context this must not be the process working directory and can be an absolute path to the
         * Package/Site that should be worked in.
         */
        // here we actually want to disable the lint rule as its value is set
        // eslint-disable-next-line workspace/no-process-cwd
        this.workingDir = process.cwd();
        _BaseCommand_noBaseOptions.set(this, false
        /** don't show help options on command overview (mostly used on top commands like `addons` where options only apply on children) */
        );
        /** The examples list for the command (used inside doc generation and help page) */
        this.examples = [];
    }
    /**
     * IMPORTANT this function will be called for each command!
     * Don't do anything expensive in there.
     */
    createCommand(name) {
        const base = new BaseCommand(name)
            // If  --silent or --json flag passed disable logger
            .addOption(new Option('--json', 'Output return values as JSON').hideHelp(true))
            .addOption(new Option('--silent', 'Silence CLI output').hideHelp(true))
            .addOption(new Option('--cwd <cwd>').hideHelp(true))
            .addOption(new Option('-o, --offline').hideHelp(true))
            .addOption(new Option('--auth <token>', 'Netlify auth token').hideHelp(true))
            .addOption(new Option('--httpProxy [address]', 'Old, prefer --http-proxy. Proxy server address to route requests through.')
            .default(process.env.HTTP_PROXY || process.env.HTTPS_PROXY)
            .hideHelp(true))
            .addOption(new Option('--httpProxyCertificateFilename [file]', 'Old, prefer --http-proxy-certificate-filename. Certificate file to use when connecting using a proxy server.')
            .default(process.env.NETLIFY_PROXY_CERTIFICATE_FILENAME)
            .hideHelp(true))
            .addOption(new Option('--http-proxy-certificate-filename [file]', 'Certificate file to use when connecting using a proxy server')
            .default(process.env.NETLIFY_PROXY_CERTIFICATE_FILENAME)
            .hideHelp(true))
            .addOption(new Option('--httpProxy [address]', 'Proxy server address to route requests through.')
            .default(process.env.HTTP_PROXY || process.env.HTTPS_PROXY)
            .hideHelp(true))
            .option('--debug', 'Print debugging information');
        // only add the `--filter` option to commands that are workspace aware
        if (!COMMANDS_WITHOUT_WORKSPACE_OPTIONS.has(name)) {
            base.option('--filter <app>', 'For monorepos, specify the name of the application to run the command in');
        }
        return base.hook('preAction', async (_parentCommand, actionCommand) => {
            if (actionCommand.opts()?.debug) {
                process.env.DEBUG = '*';
            }
            debug(`${name}:preAction`)('start');
            this.analytics = { startTime: process.hrtime.bigint() };
            await this.init(actionCommand);
            debug(`${name}:preAction`)('end');
        });
    }
    /** don't show help options on command overview (mostly used on top commands like `addons` where options only apply on children) */
    noHelpOptions() {
        __classPrivateFieldSet(this, _BaseCommand_noBaseOptions, true, "f");
        return this;
    }
    /** Set examples for the command  */
    addExamples(examples) {
        this.examples = examples;
        return this;
    }
    /** Overrides the help output of commander with custom styling */
    createHelp() {
        const help = super.createHelp();
        help.commandUsage = (command) => {
            const term = this.name() === 'netlify'
                ? `${HELP_$} ${command.name()} [COMMAND]`
                : `${HELP_$} ${command.parent?.name()} ${command.name()} ${command.usage()}`;
            return padLeft(term, HELP_INDENT_WIDTH);
        };
        // eslint-disable-next-line unicorn/consistent-function-scoping
        const getCommands = (command) => {
            const parentCommand = this.name() === 'netlify' ? command : command.parent;
            return (parentCommand?.commands
                .filter((cmd) => {
                if (cmd._hidden)
                    return false;
                // the root command
                if (this.name() === 'netlify') {
                    // don't include subcommands on the main page
                    return !cmd.name().includes(':');
                }
                return cmd.name().startsWith(`${command.name()}:`);
            })
                // eslint-disable-next-line id-length
                .sort((a, b) => a.name().localeCompare(b.name())) || []);
        };
        help.longestSubcommandTermLength = (command) => getCommands(command).reduce((max, cmd) => Math.max(max, cmd.name().length), 0);
        /** override the longestOptionTermLength to react on hide options flag */
        help.longestOptionTermLength = (command, helper) => 
        // @ts-expect-error TS(2551) FIXME: Property 'noBaseOptions' does not exist on type 'C... Remove this comment to see the full error message
        (command.noBaseOptions === false &&
            helper.visibleOptions(command).reduce((max, option) => Math.max(max, helper.optionTerm(option).length), 0)) ||
            0;
        help.formatHelp = (command, helper) => {
            const parentCommand = this.name() === 'netlify' ? command : command.parent;
            const termWidth = helper.padWidth(command, helper);
            const helpWidth = helper.helpWidth || FALLBACK_HELP_CMD_WIDTH;
            // formats a term correctly
            const formatItem = (term, description, isCommand = false) => {
                const bang = isCommand ? `${HELP_$} ` : '';
                if (description) {
                    const pad = termWidth + HELP_SEPARATOR_WIDTH;
                    const fullText = `${bang}${term.padEnd(pad - (isCommand ? 2 : 0))}${chalk.grey(description)}`;
                    return helper.wrap(fullText, helpWidth - HELP_INDENT_WIDTH, pad);
                }
                return `${bang}${term}`;
            };
            let output = [];
            // Description
            const [topDescription, ...commandDescription] = (helper.commandDescription(command) || '').split('\n');
            if (topDescription.length !== 0) {
                output = [...output, topDescription, ''];
            }
            // on the parent help command the version should be displayed
            if (this.name() === 'netlify') {
                output = [...output, chalk.bold('VERSION'), formatHelpList([formatItem(USER_AGENT)]), ''];
            }
            // Usage
            output = [...output, chalk.bold('USAGE'), helper.commandUsage(command), ''];
            // Arguments
            const argumentList = helper
                .visibleArguments(command)
                .map((argument) => formatItem(helper.argumentTerm(argument), helper.argumentDescription(argument)));
            if (argumentList.length !== 0) {
                output = [...output, chalk.bold('ARGUMENTS'), formatHelpList(argumentList), ''];
            }
            if (__classPrivateFieldGet(command, _BaseCommand_noBaseOptions, "f") === false) {
                // Options
                const optionList = helper
                    .visibleOptions(command)
                    .sort(sortOptions)
                    .map((option) => formatItem(helper.optionTerm(option), helper.optionDescription(option)));
                if (optionList.length !== 0) {
                    output = [...output, chalk.bold('OPTIONS'), formatHelpList(optionList), ''];
                }
            }
            // Description
            if (commandDescription.length !== 0) {
                output = [...output, chalk.bold('DESCRIPTION'), formatHelpList(commandDescription), ''];
            }
            // Aliases
            // @ts-expect-error TS(2551) FIXME: Property '_aliases' does not exist on type 'Comman... Remove this comment to see the full error message
            if (command._aliases.length !== 0) {
                // @ts-expect-error TS(2551) FIXME: Property '_aliases' does not exist on type 'Comman... Remove this comment to see the full error message
                const aliases = command._aliases.map((alias) => formatItem(`${parentCommand.name()} ${alias}`, null, true));
                output = [...output, chalk.bold('ALIASES'), formatHelpList(aliases), ''];
            }
            if (command.examples.length !== 0) {
                output = [
                    ...output,
                    chalk.bold('EXAMPLES'),
                    formatHelpList(command.examples.map((example) => `${HELP_$} ${example}`)),
                    '',
                ];
            }
            const commandList = getCommands(command).map((cmd) => formatItem(cmd.name(), helper.subcommandDescription(cmd).split('\n')[0], true));
            if (commandList.length !== 0) {
                output = [...output, chalk.bold('COMMANDS'), formatHelpList(commandList), ''];
            }
            return [...output, ''].join('\n');
        };
        return help;
    }
    /** Will be called on the end of an action to track the metrics */
    async onEnd(error_) {
        const { payload = {}, startTime } = this.analytics;
        const duration = getDuration(startTime);
        const status = error_ === undefined ? 'success' : 'error';
        const command = Array.isArray(this.args) ? this.args[0] : this.name();
        debug(`${this.name()}:onEnd`)(`Command: ${command}. Status: ${status}. Duration: ${duration}ms`);
        try {
            await track('command', {
                ...payload,
                command,
                duration,
                status,
            });
        }
        catch { }
        if (error_ !== undefined) {
            error(error_ instanceof Error ? error_ : format(error_), { exit: false });
            exit(1);
        }
    }
    async authenticate(tokenFromFlag) {
        const [token] = await getToken(tokenFromFlag);
        if (token) {
            return token;
        }
        return this.expensivelyAuthenticate();
    }
    async expensivelyAuthenticate() {
        const webUI = process.env.NETLIFY_WEB_UI || 'https://app.netlify.com';
        log(`Logging into your Netlify account...`);
        // Create ticket for auth
        const ticket = await this.netlify.api.createTicket({
            clientId: CLIENT_ID,
        });
        // Open browser for authentication
        const authLink = `${webUI}/authorize?response_type=ticket&ticket=${ticket.id}`;
        log(`Opening ${authLink}`);
        // @ts-expect-error TS(2345) FIXME: Argument of type '{ url: string; }' is not assigna... Remove this comment to see the full error message
        await openBrowser({ url: authLink });
        const accessToken = await pollForToken({
            api: this.netlify.api,
            ticket,
        });
        const { email, full_name: name, id: userId } = await this.netlify.api.getCurrentUser();
        const userData = merge(this.netlify.globalConfig.get(`users.${userId}`), {
            id: userId,
            name,
            email,
            auth: {
                token: accessToken,
                github: {
                    user: undefined,
                    token: undefined,
                },
            },
        });
        // Set current userId
        this.netlify.globalConfig.set('userId', userId);
        // Set user data
        this.netlify.globalConfig.set(`users.${userId}`, userData);
        await identify({
            name,
            email,
            userId,
        });
        await track('user_login', {
            email,
        });
        // Log success
        log();
        log(`${chalk.greenBright('You are now logged into your Netlify account!')}`);
        log();
        log(`Run ${chalk.cyanBright('netlify status')} for account details`);
        log();
        log(`To see all available commands run: ${chalk.cyanBright('netlify help')}`);
        log();
        return accessToken;
    }
    /** Adds some data to the analytics payload */
    setAnalyticsPayload(payload) {
        this.analytics = {
            ...this.analytics,
            payload: { ...this.analytics.payload, ...payload },
        };
    }
    /**
     * Initializes the options and parses the configuration needs to be called on start of a command function
     */
    async init(actionCommand) {
        debug(`${actionCommand.name()}:init`)('start');
        const flags = actionCommand.opts();
        // here we actually want to use the process.cwd as we are setting the workingDir
        // eslint-disable-next-line workspace/no-process-cwd
        this.workingDir = flags.cwd ? resolve(flags.cwd) : process.cwd();
        // ==================================================
        // Create a Project and run the Heuristics to detect
        // if we are running inside a monorepo or not.
        // ==================================================
        // retrieve the repository root
        const rootDir = await getRepositoryRoot();
        // Get framework, add to analytics payload for every command, if a framework is set
        const fs = new NodeFS();
        // disable logging inside the project and FS if not in debug mode
        fs.logger = actionCommand.opts()?.debug ? new DefaultLogger('debug') : new NoopLogger();
        this.project = new Project(fs, this.workingDir, rootDir)
            .setEnvironment(process.env)
            .setNodeVersion(process.version)
            // eslint-disable-next-line promise/prefer-await-to-callbacks
            .setReportFn((err, reportConfig) => {
            reportError(err, {
                severity: reportConfig?.severity || 'error',
                metadata: reportConfig?.metadata,
            });
        });
        const frameworks = await this.project.detectFrameworks();
        let packageConfig = flags.config ? resolve(flags.config) : undefined;
        // check if we have detected multiple projects inside which one we have to perform our operations.
        // only ask to select one if on the workspace root
        if (!COMMANDS_WITHOUT_WORKSPACE_OPTIONS.has(actionCommand.name()) &&
            this.project.workspace?.packages.length &&
            this.project.workspace.isRoot) {
            this.workspacePackage = await selectWorkspace(this.project, actionCommand.opts().filter);
            this.workingDir = join(this.project.jsWorkspaceRoot, this.workspacePackage);
        }
        if (this.project.workspace?.packages.length && !this.project.workspace.isRoot) {
            // set the package path even though we are not in the workspace root
            // as the build command will set the process working directory to the workspace root
            this.workspacePackage = this.project.relativeBaseDirectory;
        }
        this.jsWorkspaceRoot = this.project.jsWorkspaceRoot;
        // detect if a toml exists in this package.
        const tomlFile = join(this.workingDir, 'netlify.toml');
        if (!packageConfig && existsSync(tomlFile)) {
            packageConfig = tomlFile;
        }
        // ==================================================
        // Retrieve Site id and build state from the state.json
        // ==================================================
        const state = new StateConfig(this.workingDir);
        const [token] = await getToken(flags.auth);
        const apiUrlOpts = {
            userAgent: USER_AGENT,
        };
        if (process.env.NETLIFY_API_URL) {
            const apiUrl = new URL(process.env.NETLIFY_API_URL);
            apiUrlOpts.scheme = apiUrl.protocol.slice(0, -1);
            apiUrlOpts.host = apiUrl.host;
            apiUrlOpts.pathPrefix =
                process.env.NETLIFY_API_URL === `${apiUrl.protocol}//${apiUrl.host}` ? '/api/v1' : apiUrl.pathname;
        }
        // ==================================================
        // Start retrieving the configuration through the
        // configuration file and the API
        // ==================================================
        const cachedConfig = await actionCommand.getConfig({
            cwd: flags.cwd ? this.workingDir : this.jsWorkspaceRoot || this.workingDir,
            repositoryRoot: rootDir,
            packagePath: this.workspacePackage,
            // The config flag needs to be resolved from the actual process working directory
            configFilePath: packageConfig,
            state,
            token,
            ...apiUrlOpts,
        });
        const { buildDir, config, configPath, env, repositoryRoot, siteInfo } = cachedConfig;
        env.NETLIFY_CLI_VERSION = { sources: ['internal'], value: version };
        const normalizedConfig = normalizeConfig(config);
        const agent = await getAgent({
            httpProxy: flags.httpProxy,
            certificateFile: flags.httpProxyCertificateFilename,
        });
        const apiOpts = { ...apiUrlOpts, agent };
        // TODO: remove typecast once we have proper types for the API
        const api = new NetlifyAPI(token || '', apiOpts);
        // If a user passes a site name as an option instead of a site ID to options.site, the siteInfo object
        // will only have the property siteInfo.id. Checking for one of the other properties ensures that we can do
        // a re-call of the api.getSite() that is done in @netlify/config so we have the proper site object in all
        // commands.
        // options.site as a site name (and not just site id) was introduced for the deploy command, so users could
        // deploy by name along with by id
        let siteData = siteInfo;
        if (!siteData.url && flags.site) {
            siteData = await getSiteByName(api, flags.site);
        }
        const globalConfig = await getGlobalConfig();
        // ==================================================
        // Perform analytics reporting
        // ==================================================
        const frameworkIDs = frameworks?.map((framework) => framework.id);
        if (frameworkIDs?.length !== 0) {
            this.setAnalyticsPayload({ frameworks: frameworkIDs });
        }
        this.setAnalyticsPayload({
            monorepo: Boolean(this.project.workspace),
            packageManager: this.project.packageManager?.name,
            buildSystem: this.project.buildSystems.map(({ id }) => id),
        });
        // set the project and the netlify api object on the command,
        // to be accessible inside each command.
        actionCommand.project = this.project;
        actionCommand.workingDir = this.workingDir;
        actionCommand.workspacePackage = this.workspacePackage;
        actionCommand.jsWorkspaceRoot = this.jsWorkspaceRoot;
        // Either an existing configuration file from `@netlify/config` or a file path
        // that should be used for creating it.
        const configFilePath = configPath || join(this.workingDir, 'netlify.toml');
        actionCommand.netlify = {
            // api methods
            api,
            apiOpts,
            // The absolute repository root (detected through @netlify/config)
            repositoryRoot,
            configFilePath,
            relConfigFilePath: relative(repositoryRoot, configFilePath),
            // current site context
            site: {
                root: buildDir,
                configPath,
                get id() {
                    return state.get('siteId');
                },
                set id(id) {
                    state.set('siteId', id);
                },
            },
            // Site information retrieved using the API (api.getSite())
            siteInfo: siteData,
            // Configuration from netlify.[toml/yml]
            config: normalizedConfig,
            // Used to avoid calling @netlify/config again
            cachedConfig,
            // global cli config
            globalConfig,
            // state of current site dir
            state,
        };
        debug(`${this.name()}:init`)('end');
    }
    /** Find and resolve the Netlify configuration */
    async getConfig(config) {
        // the flags that are passed to the command like `--debug` or `--offline`
        const flags = this.opts();
        try {
            return await resolveConfig({
                config: config.configFilePath,
                packagePath: config.packagePath,
                repositoryRoot: config.repositoryRoot,
                cwd: config.cwd,
                context: flags.context || process.env.CONTEXT || this.getDefaultContext(),
                debug: flags.debug,
                siteId: flags.siteId || (typeof flags.site === 'string' && flags.site) || config.state.get('siteId'),
                token: config.token,
                mode: 'cli',
                host: config.host,
                pathPrefix: config.pathPrefix,
                scheme: config.scheme,
                offline: config.offline ?? flags.offline,
                siteFeatureFlagPrefix: 'cli',
            });
        }
        catch (error_) {
            // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
            const isUserError = error_.customErrorInfo !== undefined && error_.customErrorInfo.type === 'resolveConfig';
            // If we're failing due to an error thrown by us, it might be because the token we're using is invalid.
            // To account for that, we try to retrieve the config again, this time without a token, to avoid making
            // any API calls.
            //
            // @todo Replace this with a mechanism for calling `resolveConfig` with more granularity (i.e. having
            // the option to say that we don't need API data.)
            if (isUserError && !config.offline && config.token) {
                if (flags.debug) {
                    // @ts-expect-error TS(2345) FIXME: Argument of type 'unknown' is not assignable to pa... Remove this comment to see the full error message
                    error(error_, { exit: false });
                    warn('Failed to resolve config, falling back to offline resolution');
                }
                // recursive call with trying to resolve offline
                return this.getConfig({ ...config, offline: true });
            }
            // @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
            const message = isUserError ? error_.message : error_.stack;
            error(message, { exit: true });
        }
    }
    /**
     * get a path inside the `.netlify` project folder
     */
    getPathInProject(...paths) {
        return join(this.workspacePackage || '', '.netlify', ...paths);
    }
    /**
     * Returns the context that should be used in case one hasn't been explicitly
     * set. The default context is `dev` most of the time, but some commands may
     * wish to override that.
     */
    getDefaultContext() {
        return this.name() === 'serve' ? 'production' : 'dev';
    }
    /**
     * Retrieve feature flags for this site
     */
    getFeatureFlag(flagName) {
        return this.netlify.siteInfo.feature_flags?.[flagName] || null;
    }
}
_BaseCommand_noBaseOptions = new WeakMap();
export default BaseCommand;