/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import yargs from 'yargs/yargs';
import { hideBin } from 'yargs/helpers';
import process from 'node:process';
import { mcpCommand } from '../commands/mcp.js';
import { extensionsCommand } from '../commands/extensions.js';
import { skillsCommand } from '../commands/skills.js';
import { hooksCommand } from '../commands/hooks.js';
import { setGeminiMdFilename as setServerGeminiMdFilename, getCurrentGeminiMdFilename, ApprovalMode, DEFAULT_GEMINI_EMBEDDING_MODEL, DEFAULT_FILE_FILTERING_OPTIONS, DEFAULT_MEMORY_FILE_FILTERING_OPTIONS, FileDiscoveryService, WRITE_FILE_TOOL_NAME, SHELL_TOOL_NAMES, SHELL_TOOL_NAME, resolveTelemetrySettings, FatalConfigError, getPty, EDIT_TOOL_NAME, debugLogger, loadServerHierarchicalMemory, WEB_FETCH_TOOL_NAME, ASK_USER_TOOL_NAME, getVersion, PREVIEW_GEMINI_MODEL_AUTO, coreEvents, GEMINI_MODEL_ALIAS_AUTO, getAdminErrorMessage, isHeadlessMode, Config, applyAdminAllowlist, getAdminBlockedMcpServersMessage, } from '@google/gemini-cli-core';
import { saveModelChange, loadSettings, } from './settings.js';
import { loadSandboxConfig } from './sandboxConfig.js';
import { resolvePath } from '../utils/resolvePath.js';
import { RESUME_LATEST } from '../utils/sessionUtils.js';
import { isWorkspaceTrusted } from './trustedFolders.js';
import { createPolicyEngineConfig, resolveWorkspacePolicyState, } from './policy.js';
import { ExtensionManager } from './extension-manager.js';
import { McpServerEnablementManager } from './mcp/mcpServerEnablement.js';
import { requestConsentNonInteractive } from './extensions/consent.js';
import { promptForSetting } from './extensions/extensionSettings.js';
import { runExitCleanup } from '../utils/cleanup.js';
export async function parseArguments(settings) {
    const rawArgv = hideBin(process.argv);
    const startupMessages = [];
    const yargsInstance = yargs(rawArgv)
        .locale('en')
        .scriptName('gemini')
        .usage('Usage: gemini [options] [command]\n\nGemini CLI - Defaults to interactive mode. Use -p/--prompt for non-interactive (headless) mode.')
        .option('debug', {
        alias: 'd',
        type: 'boolean',
        description: 'Run in debug mode (open debug console with F12)',
        default: false,
    })
        .command('$0 [query..]', 'Launch Gemini CLI', (yargsInstance) => yargsInstance
        .positional('query', {
        description: 'Initial prompt. Runs in interactive mode by default; use -p/--prompt for non-interactive.',
    })
        .option('model', {
        alias: 'm',
        type: 'string',
        nargs: 1,
        description: `Model`,
    })
        .option('prompt', {
        alias: 'p',
        type: 'string',
        nargs: 1,
        description: 'Run in non-interactive (headless) mode with the given prompt. Appended to input on stdin (if any).',
    })
        .option('prompt-interactive', {
        alias: 'i',
        type: 'string',
        nargs: 1,
        description: 'Execute the provided prompt and continue in interactive mode',
    })
        .option('sandbox', {
        alias: 's',
        type: 'boolean',
        description: 'Run in sandbox?',
    })
        .option('yolo', {
        alias: 'y',
        type: 'boolean',
        description: 'Automatically accept all actions (aka YOLO mode, see https://www.youtube.com/watch?v=xvFZjo5PgG0 for more details)?',
        default: false,
    })
        .option('approval-mode', {
        type: 'string',
        nargs: 1,
        choices: ['default', 'auto_edit', 'yolo', 'plan'],
        description: 'Set the approval mode: default (prompt for approval), auto_edit (auto-approve edit tools), yolo (auto-approve all tools), plan (read-only mode)',
    })
        .option('policy', {
        type: 'array',
        string: true,
        nargs: 1,
        description: 'Additional policy files or directories to load (comma-separated or multiple --policy)',
        coerce: (policies) => 
        // Handle comma-separated values
        policies.flatMap((p) => p
            .split(',')
            .map((s) => s.trim())
            .filter(Boolean)),
    })
        .option('acp', {
        type: 'boolean',
        description: 'Starts the agent in ACP mode',
    })
        .option('experimental-acp', {
        type: 'boolean',
        description: 'Starts the agent in ACP mode (deprecated, use --acp instead)',
    })
        .option('allowed-mcp-server-names', {
        type: 'array',
        string: true,
        nargs: 1,
        description: 'Allowed MCP server names',
        coerce: (mcpServerNames) => 
        // Handle comma-separated values
        mcpServerNames.flatMap((mcpServerName) => mcpServerName.split(',').map((m) => m.trim())),
    })
        .option('allowed-tools', {
        type: 'array',
        string: true,
        nargs: 1,
        description: '[DEPRECATED: Use Policy Engine instead See https://geminicli.com/docs/core/policy-engine] Tools that are allowed to run without confirmation',
        coerce: (tools) => 
        // Handle comma-separated values
        tools.flatMap((tool) => tool.split(',').map((t) => t.trim())),
    })
        .option('extensions', {
        alias: 'e',
        type: 'array',
        string: true,
        nargs: 1,
        description: 'A list of extensions to use. If not provided, all extensions are used.',
        coerce: (extensions) => 
        // Handle comma-separated values
        extensions.flatMap((extension) => extension.split(',').map((e) => e.trim())),
    })
        .option('list-extensions', {
        alias: 'l',
        type: 'boolean',
        description: 'List all available extensions and exit.',
    })
        .option('resume', {
        alias: 'r',
        type: 'string',
        // `skipValidation` so that we can distinguish between it being passed with a value, without
        // one, and not being passed at all.
        skipValidation: true,
        description: 'Resume a previous session. Use "latest" for most recent or index number (e.g. --resume 5)',
        coerce: (value) => {
            // When --resume passed with a value (`gemini --resume 123`): value = "123" (string)
            // When --resume passed without a value (`gemini --resume`): value = "" (string)
            // When --resume not passed at all: this `coerce` function is not called at all, and
            //   `yargsInstance.argv.resume` is undefined.
            if (value === '') {
                return RESUME_LATEST;
            }
            return value;
        },
    })
        .option('list-sessions', {
        type: 'boolean',
        description: 'List available sessions for the current project and exit.',
    })
        .option('delete-session', {
        type: 'string',
        description: 'Delete a session by index number (use --list-sessions to see available sessions).',
    })
        .option('include-directories', {
        type: 'array',
        string: true,
        nargs: 1,
        description: 'Additional directories to include in the workspace (comma-separated or multiple --include-directories)',
        coerce: (dirs) => 
        // Handle comma-separated values
        dirs.flatMap((dir) => dir.split(',').map((d) => d.trim())),
    })
        .option('screen-reader', {
        type: 'boolean',
        description: 'Enable screen reader mode for accessibility.',
    })
        .option('output-format', {
        alias: 'o',
        type: 'string',
        nargs: 1,
        description: 'The format of the CLI output.',
        choices: ['text', 'json', 'stream-json'],
    })
        .option('fake-responses', {
        type: 'string',
        description: 'Path to a file with fake model responses for testing.',
        hidden: true,
    })
        .option('record-responses', {
        type: 'string',
        description: 'Path to a file to record model responses for testing.',
        hidden: true,
    })
        .option('raw-output', {
        type: 'boolean',
        description: 'Disable sanitization of model output (e.g. allow ANSI escape sequences). WARNING: This can be a security risk if the model output is untrusted.',
    })
        .option('accept-raw-output-risk', {
        type: 'boolean',
        description: 'Suppress the security warning when using --raw-output.',
    }))
        // Register MCP subcommands
        .command(mcpCommand)
        // Ensure validation flows through .fail() for clean UX
        .fail((msg, err) => {
        if (err)
            throw err;
        throw new Error(msg);
    })
        .check((argv) => {
        // The 'query' positional can be a string (for one arg) or string[] (for multiple).
        // This guard safely checks if any positional argument was provided.
        // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
        const query = argv['query'];
        const hasPositionalQuery = Array.isArray(query)
            ? query.length > 0
            : !!query;
        if (argv['prompt'] && hasPositionalQuery) {
            return 'Cannot use both a positional prompt and the --prompt (-p) flag together';
        }
        if (argv['prompt'] && argv['promptInteractive']) {
            return 'Cannot use both --prompt (-p) and --prompt-interactive (-i) together';
        }
        if (argv['yolo'] && argv['approvalMode']) {
            return 'Cannot use both --yolo (-y) and --approval-mode together. Use --approval-mode=yolo instead.';
        }
        if (argv['outputFormat'] &&
            !['text', 'json', 'stream-json'].includes(
            // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
            argv['outputFormat'])) {
            return `Invalid values:\n  Argument: output-format, Given: "${argv['outputFormat']}", Choices: "text", "json", "stream-json"`;
        }
        return true;
    });
    if (settings.experimental?.extensionManagement) {
        yargsInstance.command(extensionsCommand);
    }
    if (settings.skills?.enabled ?? true) {
        yargsInstance.command(skillsCommand);
    }
    // Register hooks command if hooks are enabled
    if (settings.hooksConfig.enabled) {
        yargsInstance.command(hooksCommand);
    }
    yargsInstance
        .version(await getVersion()) // This will enable the --version flag based on package.json
        .alias('v', 'version')
        .help()
        .alias('h', 'help')
        .strict()
        .demandCommand(0, 0) // Allow base command to run with no subcommands
        .exitProcess(false);
    yargsInstance.wrap(yargsInstance.terminalWidth());
    let result;
    try {
        result = await yargsInstance.parse();
    }
    catch (e) {
        const msg = e instanceof Error ? e.message : String(e);
        debugLogger.error(msg);
        yargsInstance.showHelp();
        await runExitCleanup();
        process.exit(1);
    }
    // Handle help and version flags manually since we disabled exitProcess
    if (result['help'] || result['version']) {
        await runExitCleanup();
        process.exit(0);
    }
    // Normalize query args: handle both quoted "@path file" and unquoted @path file
    // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
    const queryArg = result.query;
    const q = Array.isArray(queryArg)
        ? queryArg.join(' ')
        : queryArg;
    // -p/--prompt forces non-interactive mode; positional args default to interactive in TTY
    if (q && !result['prompt']) {
        if (!isHeadlessMode()) {
            startupMessages.push('Positional arguments now default to interactive mode. To run in non-interactive mode, use the --prompt (-p) flag.');
            result['promptInteractive'] = q;
        }
        else {
            result['prompt'] = q;
        }
    }
    // Keep CliArgs.query as a string for downstream typing
    result['query'] = q || undefined;
    result['startupMessages'] = startupMessages;
    // The import format is now only controlled by settings.memoryImportFormat
    // We no longer accept it as a CLI argument
    // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
    return result;
}
/**
 * Creates a filter function to determine if a tool should be excluded.
 *
 * In non-interactive mode, we want to disable tools that require user
 * interaction to prevent the CLI from hanging. This function creates a predicate
 * that returns `true` if a tool should be excluded.
 *
 * A tool is excluded if it's not in the `allowedToolsSet`. The shell tool
 * has a special case: it's not excluded if any of its subcommands
 * are in the `allowedTools` list.
 *
 * @param allowedTools A list of explicitly allowed tool names.
 * @param allowedToolsSet A set of explicitly allowed tool names for quick lookups.
 * @returns A function that takes a tool name and returns `true` if it should be excluded.
 */
function createToolExclusionFilter(allowedTools, allowedToolsSet) {
    return (tool) => {
        if (tool === SHELL_TOOL_NAME) {
            // If any of the allowed tools is ShellTool (even with subcommands), don't exclude it.
            return !allowedTools.some((allowed) => SHELL_TOOL_NAMES.some((shellName) => allowed.startsWith(shellName)));
        }
        return !allowedToolsSet.has(tool);
    };
}
export function isDebugMode(argv) {
    return (argv.debug ||
        [process.env['DEBUG'], process.env['DEBUG_MODE']].some((v) => v === 'true' || v === '1'));
}
export async function loadCliConfig(settings, sessionId, argv, options = {}) {
    const { cwd = process.cwd(), projectHooks } = options;
    const debugMode = isDebugMode(argv);
    const loadedSettings = loadSettings(cwd);
    if (argv.sandbox) {
        process.env['GEMINI_SANDBOX'] = 'true';
    }
    const memoryImportFormat = settings.context?.importFormat || 'tree';
    const includeDirectoryTree = settings.context?.includeDirectoryTree ?? true;
    const ideMode = settings.ide?.enabled ?? false;
    const folderTrust = process.env['GEMINI_CLI_INTEGRATION_TEST'] === 'true' ||
        process.env['VITEST'] === 'true'
        ? false
        : (settings.security?.folderTrust?.enabled ?? false);
    const trustedFolder = isWorkspaceTrusted(settings, cwd, undefined, {
        prompt: argv.prompt,
        query: argv.query,
    })?.isTrusted ?? false;
    // Set the context filename in the server's memoryTool module BEFORE loading memory
    // TODO(b/343434939): This is a bit of a hack. The contextFileName should ideally be passed
    // directly to the Config constructor in core, and have core handle setGeminiMdFilename.
    // However, loadHierarchicalGeminiMemory is called *before* createServerConfig.
    if (settings.context?.fileName) {
        setServerGeminiMdFilename(settings.context.fileName);
    }
    else {
        // Reset to default if not provided in settings.
        setServerGeminiMdFilename(getCurrentGeminiMdFilename());
    }
    const fileService = new FileDiscoveryService(cwd);
    const memoryFileFiltering = {
        ...DEFAULT_MEMORY_FILE_FILTERING_OPTIONS,
        ...settings.context?.fileFiltering,
    };
    const fileFiltering = {
        ...DEFAULT_FILE_FILTERING_OPTIONS,
        ...settings.context?.fileFiltering,
    };
    const includeDirectories = (settings.context?.includeDirectories || [])
        .map(resolvePath)
        .concat((argv.includeDirectories || []).map(resolvePath));
    const extensionManager = new ExtensionManager({
        settings,
        requestConsent: requestConsentNonInteractive,
        requestSetting: promptForSetting,
        workspaceDir: cwd,
        enabledExtensionOverrides: argv.extensions,
        // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
        eventEmitter: coreEvents,
        clientVersion: await getVersion(),
    });
    await extensionManager.loadExtensions();
    const extensionPlanSettings = extensionManager
        .getExtensions()
        .find((ext) => ext.isActive && ext.plan?.directory)?.plan;
    const experimentalJitContext = settings.experimental?.jitContext ?? false;
    let memoryContent = '';
    let fileCount = 0;
    let filePaths = [];
    if (!experimentalJitContext) {
        // Call the (now wrapper) loadHierarchicalGeminiMemory which calls the server's version
        const result = await loadServerHierarchicalMemory(cwd, settings.context?.loadMemoryFromIncludeDirectories || false
            ? includeDirectories
            : [], debugMode, fileService, extensionManager, trustedFolder, memoryImportFormat, memoryFileFiltering, settings.context?.discoveryMaxDirs);
        memoryContent = result.memoryContent;
        fileCount = result.fileCount;
        filePaths = result.filePaths;
    }
    const question = argv.promptInteractive || argv.prompt || '';
    // Determine approval mode with backward compatibility
    let approvalMode;
    const rawApprovalMode = argv.approvalMode ||
        (argv.yolo ? 'yolo' : undefined) ||
        (settings.general?.defaultApprovalMode !== 'yolo'
            ? settings.general?.defaultApprovalMode
            : undefined);
    if (rawApprovalMode) {
        switch (rawApprovalMode) {
            case 'yolo':
                approvalMode = ApprovalMode.YOLO;
                break;
            case 'auto_edit':
                approvalMode = ApprovalMode.AUTO_EDIT;
                break;
            case 'plan':
                if (!(settings.experimental?.plan ?? false)) {
                    debugLogger.warn('Approval mode "plan" is only available when experimental.plan is enabled. Falling back to "default".');
                    approvalMode = ApprovalMode.DEFAULT;
                }
                else {
                    approvalMode = ApprovalMode.PLAN;
                }
                break;
            case 'default':
                approvalMode = ApprovalMode.DEFAULT;
                break;
            default:
                throw new Error(`Invalid approval mode: ${rawApprovalMode}. Valid values are: yolo, auto_edit, plan, default`);
        }
    }
    else {
        approvalMode = ApprovalMode.DEFAULT;
    }
    // Override approval mode if disableYoloMode is set.
    if (settings.security?.disableYoloMode || settings.admin?.secureModeEnabled) {
        if (approvalMode === ApprovalMode.YOLO) {
            if (settings.admin?.secureModeEnabled) {
                debugLogger.error('YOLO mode is disabled by "secureModeEnabled" setting.');
            }
            else {
                debugLogger.error('YOLO mode is disabled by the "disableYolo" setting.');
            }
            throw new FatalConfigError(getAdminErrorMessage('YOLO mode', undefined /* config */));
        }
    }
    else if (approvalMode === ApprovalMode.YOLO) {
        debugLogger.warn('YOLO mode is enabled. All tool calls will be automatically approved.');
    }
    // Force approval mode to default if the folder is not trusted.
    if (!trustedFolder && approvalMode !== ApprovalMode.DEFAULT) {
        debugLogger.warn(`Approval mode overridden to "default" because the current folder is not trusted.`);
        approvalMode = ApprovalMode.DEFAULT;
    }
    let telemetrySettings;
    try {
        telemetrySettings = await resolveTelemetrySettings({
            // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
            env: process.env,
            settings: settings.telemetry,
        });
    }
    catch (err) {
        if (err instanceof FatalConfigError) {
            throw new FatalConfigError(`Invalid telemetry configuration: ${err.message}.`);
        }
        throw err;
    }
    // -p/--prompt forces non-interactive (headless) mode
    // -i/--prompt-interactive forces interactive mode with an initial prompt
    const interactive = !!argv.promptInteractive ||
        !!argv.acp ||
        !!argv.experimentalAcp ||
        (!isHeadlessMode({ prompt: argv.prompt, query: argv.query }) &&
            !argv.isCommand);
    const allowedTools = argv.allowedTools || settings.tools?.allowed || [];
    const allowedToolsSet = new Set(allowedTools);
    // In non-interactive mode, exclude tools that require a prompt.
    const extraExcludes = [];
    if (!interactive) {
        // ask_user requires user interaction and must be excluded in all
        // non-interactive modes, regardless of the approval mode.
        extraExcludes.push(ASK_USER_TOOL_NAME);
        const defaultExcludes = [
            SHELL_TOOL_NAME,
            EDIT_TOOL_NAME,
            WRITE_FILE_TOOL_NAME,
            WEB_FETCH_TOOL_NAME,
        ];
        const autoEditExcludes = [SHELL_TOOL_NAME];
        const toolExclusionFilter = createToolExclusionFilter(allowedTools, allowedToolsSet);
        switch (approvalMode) {
            case ApprovalMode.PLAN:
                // In plan non-interactive mode, all tools that require approval are excluded.
                // TODO(#16625): Replace this default exclusion logic with specific rules for plan mode.
                extraExcludes.push(...defaultExcludes.filter(toolExclusionFilter));
                break;
            case ApprovalMode.DEFAULT:
                // In default non-interactive mode, all tools that require approval are excluded.
                extraExcludes.push(...defaultExcludes.filter(toolExclusionFilter));
                break;
            case ApprovalMode.AUTO_EDIT:
                // In auto-edit non-interactive mode, only tools that still require a prompt are excluded.
                extraExcludes.push(...autoEditExcludes.filter(toolExclusionFilter));
                break;
            case ApprovalMode.YOLO:
                // No extra excludes for YOLO mode.
                break;
            default:
                // This should never happen due to validation earlier, but satisfies the linter
                break;
        }
    }
    const excludeTools = mergeExcludeTools(settings, extraExcludes);
    // Create a settings object that includes CLI overrides for policy generation
    const effectiveSettings = {
        ...settings,
        tools: {
            ...settings.tools,
            allowed: allowedTools,
            exclude: excludeTools,
        },
        mcp: {
            ...settings.mcp,
            allowed: argv.allowedMcpServerNames ?? settings.mcp?.allowed,
        },
        policyPaths: argv.policy,
    };
    const { workspacePoliciesDir, policyUpdateConfirmationRequest } = await resolveWorkspacePolicyState({
        cwd,
        trustedFolder,
        interactive,
    });
    const policyEngineConfig = await createPolicyEngineConfig(effectiveSettings, approvalMode, workspacePoliciesDir);
    policyEngineConfig.nonInteractive = !interactive;
    const defaultModel = PREVIEW_GEMINI_MODEL_AUTO;
    const specifiedModel = argv.model || process.env['GEMINI_MODEL'] || settings.model?.name;
    const resolvedModel = specifiedModel === GEMINI_MODEL_ALIAS_AUTO
        ? defaultModel
        : specifiedModel || defaultModel;
    const sandboxConfig = await loadSandboxConfig(settings, argv);
    const screenReader = argv.screenReader !== undefined
        ? argv.screenReader
        : (settings.ui?.accessibility?.screenReader ?? false);
    const ptyInfo = await getPty();
    const mcpEnabled = settings.admin?.mcp?.enabled ?? true;
    const extensionsEnabled = settings.admin?.extensions?.enabled ?? true;
    const adminSkillsEnabled = settings.admin?.skills?.enabled ?? true;
    // Create MCP enablement manager and callbacks
    const mcpEnablementManager = McpServerEnablementManager.getInstance();
    const mcpEnablementCallbacks = mcpEnabled
        ? mcpEnablementManager.getEnablementCallbacks()
        : undefined;
    const adminAllowlist = settings.admin?.mcp?.config;
    let mcpServerCommand = mcpEnabled ? settings.mcp?.serverCommand : undefined;
    let mcpServers = mcpEnabled ? settings.mcpServers : {};
    if (mcpEnabled && adminAllowlist && Object.keys(adminAllowlist).length > 0) {
        const result = applyAdminAllowlist(mcpServers, adminAllowlist);
        mcpServers = result.mcpServers;
        mcpServerCommand = undefined;
        if (result.blockedServerNames && result.blockedServerNames.length > 0) {
            const message = getAdminBlockedMcpServersMessage(result.blockedServerNames, undefined);
            coreEvents.emitConsoleLog('warn', message);
        }
    }
    return new Config({
        acpMode: !!argv.acp || !!argv.experimentalAcp,
        sessionId,
        clientVersion: await getVersion(),
        embeddingModel: DEFAULT_GEMINI_EMBEDDING_MODEL,
        sandbox: sandboxConfig,
        targetDir: cwd,
        includeDirectoryTree,
        includeDirectories,
        loadMemoryFromIncludeDirectories: settings.context?.loadMemoryFromIncludeDirectories || false,
        debugMode,
        question,
        coreTools: settings.tools?.core || undefined,
        allowedTools: allowedTools.length > 0 ? allowedTools : undefined,
        policyEngineConfig,
        policyUpdateConfirmationRequest,
        excludeTools,
        toolDiscoveryCommand: settings.tools?.discoveryCommand,
        toolCallCommand: settings.tools?.callCommand,
        mcpServerCommand,
        mcpServers,
        mcpEnablementCallbacks,
        mcpEnabled,
        extensionsEnabled,
        agents: settings.agents,
        adminSkillsEnabled,
        allowedMcpServers: mcpEnabled
            ? (argv.allowedMcpServerNames ?? settings.mcp?.allowed)
            : undefined,
        blockedMcpServers: mcpEnabled
            ? argv.allowedMcpServerNames
                ? undefined
                : settings.mcp?.excluded
            : undefined,
        blockedEnvironmentVariables: settings.security?.environmentVariableRedaction?.blocked,
        enableEnvironmentVariableRedaction: settings.security?.environmentVariableRedaction?.enabled,
        userMemory: memoryContent,
        geminiMdFileCount: fileCount,
        geminiMdFilePaths: filePaths,
        approvalMode,
        disableYoloMode: settings.security?.disableYoloMode || settings.admin?.secureModeEnabled,
        showMemoryUsage: settings.ui?.showMemoryUsage || false,
        accessibility: {
            ...settings.ui?.accessibility,
            screenReader,
        },
        telemetry: telemetrySettings,
        usageStatisticsEnabled: settings.privacy?.usageStatisticsEnabled,
        fileFiltering,
        checkpointing: settings.general?.checkpointing?.enabled,
        proxy: process.env['HTTPS_PROXY'] ||
            process.env['https_proxy'] ||
            process.env['HTTP_PROXY'] ||
            process.env['http_proxy'],
        cwd,
        fileDiscoveryService: fileService,
        bugCommand: settings.advanced?.bugCommand,
        model: resolvedModel,
        maxSessionTurns: settings.model?.maxSessionTurns,
        listExtensions: argv.listExtensions || false,
        listSessions: argv.listSessions || false,
        deleteSession: argv.deleteSession,
        enabledExtensions: argv.extensions,
        extensionLoader: extensionManager,
        enableExtensionReloading: settings.experimental?.extensionReloading,
        enableAgents: settings.experimental?.enableAgents,
        plan: settings.experimental?.plan,
        directWebFetch: settings.experimental?.directWebFetch,
        planSettings: settings.general?.plan?.directory
            ? settings.general.plan
            : (extensionPlanSettings ?? settings.general?.plan),
        enableEventDrivenScheduler: true,
        skillsSupport: settings.skills?.enabled ?? true,
        disabledSkills: settings.skills?.disabled,
        experimentalJitContext: settings.experimental?.jitContext,
        modelSteering: settings.experimental?.modelSteering,
        toolOutputMasking: settings.experimental?.toolOutputMasking,
        noBrowser: !!process.env['NO_BROWSER'],
        summarizeToolOutput: settings.model?.summarizeToolOutput,
        ideMode,
        disableLoopDetection: settings.model?.disableLoopDetection,
        compressionThreshold: settings.model?.compressionThreshold,
        folderTrust,
        interactive,
        trustedFolder,
        useBackgroundColor: settings.ui?.useBackgroundColor,
        useAlternateBuffer: settings.ui?.useAlternateBuffer,
        useRipgrep: settings.tools?.useRipgrep,
        enableInteractiveShell: settings.tools?.shell?.enableInteractiveShell,
        shellToolInactivityTimeout: settings.tools?.shell?.inactivityTimeout,
        enableShellOutputEfficiency: settings.tools?.shell?.enableShellOutputEfficiency ?? true,
        skipNextSpeakerCheck: settings.model?.skipNextSpeakerCheck,
        truncateToolOutputThreshold: settings.tools?.truncateToolOutputThreshold,
        eventEmitter: coreEvents,
        useWriteTodos: argv.useWriteTodos ?? settings.useWriteTodos,
        output: {
            // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
            format: (argv.outputFormat ?? settings.output?.format),
        },
        gemmaModelRouter: settings.experimental?.gemmaModelRouter,
        fakeResponses: argv.fakeResponses,
        recordResponses: argv.recordResponses,
        retryFetchErrors: settings.general?.retryFetchErrors,
        billing: settings.billing,
        maxAttempts: settings.general?.maxAttempts,
        ptyInfo: ptyInfo?.name,
        disableLLMCorrection: settings.tools?.disableLLMCorrection,
        rawOutput: argv.rawOutput,
        acceptRawOutputRisk: argv.acceptRawOutputRisk,
        modelConfigServiceConfig: settings.modelConfigs,
        // TODO: loading of hooks based on workspace trust
        enableHooks: settings.hooksConfig.enabled,
        enableHooksUI: settings.hooksConfig.enabled,
        hooks: settings.hooks || {},
        disabledHooks: settings.hooksConfig?.disabled || [],
        projectHooks: projectHooks || {},
        onModelChange: (model) => saveModelChange(loadedSettings, model),
        onReload: async () => {
            const refreshedSettings = loadSettings(cwd);
            return {
                disabledSkills: refreshedSettings.merged.skills.disabled,
                agents: refreshedSettings.merged.agents,
            };
        },
        enableConseca: settings.security?.enableConseca,
    });
}
function mergeExcludeTools(settings, extraExcludes = []) {
    const allExcludeTools = new Set([
        ...(settings.tools.exclude || []),
        ...extraExcludes,
    ]);
    return Array.from(allExcludeTools);
}
//# sourceMappingURL=config.js.map