/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import * as path from 'node:path';
import { inspect } from 'node:util';
import process from 'node:process';
import { AuthType, createContentGenerator, createContentGeneratorConfig, } from '../core/contentGenerator.js';
import { PromptRegistry } from '../prompts/prompt-registry.js';
import { ToolRegistry } from '../tools/tool-registry.js';
import { LSTool } from '../tools/ls.js';
import { ReadFileTool } from '../tools/read-file.js';
import { GrepTool } from '../tools/grep.js';
import { canUseRipgrep, RipGrepTool } from '../tools/ripGrep.js';
import { GlobTool } from '../tools/glob.js';
import { EditTool } from '../tools/edit.js';
import { SmartEditTool } from '../tools/smart-edit.js';
import { ShellTool } from '../tools/shell.js';
import { WriteFileTool } from '../tools/write-file.js';
import { WebFetchTool } from '../tools/web-fetch.js';
import { MemoryTool, setGeminiMdFilename } from '../tools/memoryTool.js';
import { WebSearchTool } from '../tools/web-search.js';
import { GeminiClient } from '../core/client.js';
import { BaseLlmClient } from '../core/baseLlmClient.js';
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
import { GitService } from '../services/gitService.js';
import { initializeTelemetry, DEFAULT_TELEMETRY_TARGET, DEFAULT_OTLP_ENDPOINT, uiTelemetryService, } from '../telemetry/index.js';
import { coreEvents } from '../utils/events.js';
import { tokenLimit } from '../core/tokenLimits.js';
import { DEFAULT_GEMINI_EMBEDDING_MODEL, DEFAULT_GEMINI_FLASH_MODEL, DEFAULT_GEMINI_MODEL, DEFAULT_GEMINI_MODEL_AUTO, DEFAULT_THINKING_MODE, } from './models.js';
import { shouldAttemptBrowserLaunch } from '../utils/browser.js';
import { ideContextStore } from '../ide/ideContext.js';
import { WriteTodosTool } from '../tools/write-todos.js';
import { StandardFileSystemService } from '../services/fileSystemService.js';
import { logRipgrepFallback } from '../telemetry/loggers.js';
import { RipgrepFallbackEvent } from '../telemetry/types.js';
import { ModelRouterService } from '../routing/modelRouterService.js';
import { OutputFormat } from '../output/types.js';
import { ModelConfigService } from '../services/modelConfigService.js';
import { DEFAULT_MODEL_CONFIGS } from './defaultModelConfigs.js';
import { WorkspaceContext } from '../utils/workspaceContext.js';
import { Storage } from './storage.js';
import { FileExclusions } from '../utils/ignorePatterns.js';
import { MessageBus } from '../confirmation-bus/message-bus.js';
import { PolicyEngine } from '../policy/policy-engine.js';
import { getCodeAssistServer } from '../code_assist/codeAssist.js';
import { AgentRegistry } from '../agents/registry.js';
import { setGlobalProxy } from '../utils/fetch.js';
import { SubagentToolWrapper } from '../agents/subagent-tool-wrapper.js';
import { getExperiments } from '../code_assist/experiments/experiments.js';
import { ExperimentFlags } from '../code_assist/experiments/flagNames.js';
import { debugLogger } from '../utils/debugLogger.js';
import { ApprovalMode } from '../policy/types.js';
import { DEFAULT_FILE_FILTERING_OPTIONS, DEFAULT_MEMORY_FILE_FILTERING_OPTIONS, } from './constants.js';
import { SimpleExtensionLoader, } from '../utils/extensionLoader.js';
import { McpClientManager } from '../tools/mcp-client-manager.js';
export { DEFAULT_FILE_FILTERING_OPTIONS, DEFAULT_MEMORY_FILE_FILTERING_OPTIONS, };
export const DEFAULT_TRUNCATE_TOOL_OUTPUT_THRESHOLD = 4_000_000;
export const DEFAULT_TRUNCATE_TOOL_OUTPUT_LINES = 1000;
export class MCPServerConfig {
    command;
    args;
    env;
    cwd;
    url;
    httpUrl;
    headers;
    tcp;
    timeout;
    trust;
    description;
    includeTools;
    excludeTools;
    extension;
    oauth;
    authProviderType;
    targetAudience;
    targetServiceAccount;
    constructor(
    // For stdio transport
    command, args, env, cwd, 
    // For sse transport
    url, 
    // For streamable http transport
    httpUrl, headers, 
    // For websocket transport
    tcp, 
    // Common
    timeout, trust, 
    // Metadata
    description, includeTools, excludeTools, extension, 
    // OAuth configuration
    oauth, authProviderType, 
    // Service Account Configuration
    /* targetAudience format: CLIENT_ID.apps.googleusercontent.com */
    targetAudience, 
    /* targetServiceAccount format: <service-account-name>@<project-num>.iam.gserviceaccount.com */
    targetServiceAccount) {
        this.command = command;
        this.args = args;
        this.env = env;
        this.cwd = cwd;
        this.url = url;
        this.httpUrl = httpUrl;
        this.headers = headers;
        this.tcp = tcp;
        this.timeout = timeout;
        this.trust = trust;
        this.description = description;
        this.includeTools = includeTools;
        this.excludeTools = excludeTools;
        this.extension = extension;
        this.oauth = oauth;
        this.authProviderType = authProviderType;
        this.targetAudience = targetAudience;
        this.targetServiceAccount = targetServiceAccount;
    }
}
export var AuthProviderType;
(function (AuthProviderType) {
    AuthProviderType["DYNAMIC_DISCOVERY"] = "dynamic_discovery";
    AuthProviderType["GOOGLE_CREDENTIALS"] = "google_credentials";
    AuthProviderType["SERVICE_ACCOUNT_IMPERSONATION"] = "service_account_impersonation";
})(AuthProviderType || (AuthProviderType = {}));
export class Config {
    toolRegistry;
    mcpClientManager;
    allowedMcpServers;
    blockedMcpServers;
    promptRegistry;
    agentRegistry;
    sessionId;
    fileSystemService;
    contentGeneratorConfig;
    contentGenerator;
    modelConfigService;
    embeddingModel;
    sandbox;
    targetDir;
    workspaceContext;
    debugMode;
    question;
    coreTools;
    allowedTools;
    excludeTools;
    toolDiscoveryCommand;
    toolCallCommand;
    mcpServerCommand;
    mcpServers;
    userMemory;
    geminiMdFileCount;
    geminiMdFilePaths;
    approvalMode;
    showMemoryUsage;
    accessibility;
    telemetrySettings;
    usageStatisticsEnabled;
    geminiClient;
    baseLlmClient;
    modelRouterService;
    fileFiltering;
    fileDiscoveryService = null;
    gitService = undefined;
    checkpointing;
    proxy;
    cwd;
    bugCommand;
    model;
    noBrowser;
    folderTrust;
    ideMode;
    inFallbackMode = false;
    maxSessionTurns;
    listSessions;
    deleteSession;
    listExtensions;
    _extensionLoader;
    _enabledExtensions;
    enableExtensionReloading;
    fallbackModelHandler;
    quotaErrorOccurred = false;
    summarizeToolOutput;
    experimentalZedIntegration = false;
    loadMemoryFromIncludeDirectories = false;
    importFormat;
    discoveryMaxDirs;
    compressionThreshold;
    interactive;
    ptyInfo;
    trustedFolder;
    useRipgrep;
    enableInteractiveShell;
    skipNextSpeakerCheck;
    shellExecutionConfig;
    extensionManagement = true;
    enablePromptCompletion = false;
    truncateToolOutputThreshold;
    truncateToolOutputLines;
    enableToolOutputTruncation;
    initialized = false;
    storage;
    fileExclusions;
    eventEmitter;
    useSmartEdit;
    useWriteTodos;
    messageBus;
    policyEngine;
    outputSettings;
    useModelRouter;
    initialUseModelRouter;
    disableModelRouterForAuth;
    enableMessageBusIntegration;
    codebaseInvestigatorSettings;
    continueOnFailedApiCall;
    retryFetchErrors;
    enableShellOutputEfficiency;
    fakeResponses;
    recordResponses;
    disableYoloMode;
    pendingIncludeDirectories;
    enableHooks;
    hooks;
    experiments;
    experimentsPromise;
    constructor(params) {
        this.sessionId = params.sessionId;
        this.embeddingModel =
            params.embeddingModel ?? DEFAULT_GEMINI_EMBEDDING_MODEL;
        this.fileSystemService = new StandardFileSystemService();
        this.sandbox = params.sandbox;
        this.targetDir = path.resolve(params.targetDir);
        this.folderTrust = params.folderTrust ?? false;
        this.workspaceContext = new WorkspaceContext(this.targetDir, []);
        this.pendingIncludeDirectories = params.includeDirectories ?? [];
        this.debugMode = params.debugMode;
        this.question = params.question;
        this.coreTools = params.coreTools;
        this.allowedTools = params.allowedTools;
        this.excludeTools = params.excludeTools;
        this.toolDiscoveryCommand = params.toolDiscoveryCommand;
        this.toolCallCommand = params.toolCallCommand;
        this.mcpServerCommand = params.mcpServerCommand;
        this.mcpServers = params.mcpServers;
        this.allowedMcpServers = params.allowedMcpServers ?? [];
        this.blockedMcpServers = params.blockedMcpServers ?? [];
        this.userMemory = params.userMemory ?? '';
        this.geminiMdFileCount = params.geminiMdFileCount ?? 0;
        this.geminiMdFilePaths = params.geminiMdFilePaths ?? [];
        this.approvalMode = params.approvalMode ?? ApprovalMode.DEFAULT;
        this.showMemoryUsage = params.showMemoryUsage ?? false;
        this.accessibility = params.accessibility ?? {};
        this.telemetrySettings = {
            enabled: params.telemetry?.enabled ?? false,
            target: params.telemetry?.target ?? DEFAULT_TELEMETRY_TARGET,
            otlpEndpoint: params.telemetry?.otlpEndpoint ?? DEFAULT_OTLP_ENDPOINT,
            otlpProtocol: params.telemetry?.otlpProtocol,
            logPrompts: params.telemetry?.logPrompts ?? true,
            outfile: params.telemetry?.outfile,
            useCollector: params.telemetry?.useCollector,
        };
        this.usageStatisticsEnabled = params.usageStatisticsEnabled ?? true;
        this.fileFiltering = {
            respectGitIgnore: params.fileFiltering?.respectGitIgnore ??
                DEFAULT_FILE_FILTERING_OPTIONS.respectGitIgnore,
            respectGeminiIgnore: params.fileFiltering?.respectGeminiIgnore ??
                DEFAULT_FILE_FILTERING_OPTIONS.respectGeminiIgnore,
            enableRecursiveFileSearch: params.fileFiltering?.enableRecursiveFileSearch ?? true,
            disableFuzzySearch: params.fileFiltering?.disableFuzzySearch ?? false,
        };
        this.checkpointing = params.checkpointing ?? false;
        this.proxy = params.proxy;
        this.cwd = params.cwd ?? process.cwd();
        this.fileDiscoveryService = params.fileDiscoveryService ?? null;
        this.bugCommand = params.bugCommand;
        this.model = params.model;
        this.maxSessionTurns = params.maxSessionTurns ?? -1;
        this.experimentalZedIntegration =
            params.experimentalZedIntegration ?? false;
        this.listSessions = params.listSessions ?? false;
        this.deleteSession = params.deleteSession;
        this.listExtensions = params.listExtensions ?? false;
        this._extensionLoader =
            params.extensionLoader ?? new SimpleExtensionLoader([]);
        this._enabledExtensions = params.enabledExtensions ?? [];
        this.noBrowser = params.noBrowser ?? false;
        this.summarizeToolOutput = params.summarizeToolOutput;
        this.folderTrust = params.folderTrust ?? false;
        this.ideMode = params.ideMode ?? false;
        this.loadMemoryFromIncludeDirectories =
            params.loadMemoryFromIncludeDirectories ?? false;
        this.importFormat = params.importFormat ?? 'tree';
        this.discoveryMaxDirs = params.discoveryMaxDirs ?? 200;
        this.compressionThreshold = params.compressionThreshold;
        this.interactive = params.interactive ?? false;
        this.ptyInfo = params.ptyInfo ?? 'child_process';
        this.trustedFolder = params.trustedFolder;
        this.useRipgrep = params.useRipgrep ?? true;
        this.enableInteractiveShell = params.enableInteractiveShell ?? false;
        this.skipNextSpeakerCheck = params.skipNextSpeakerCheck ?? true;
        this.shellExecutionConfig = {
            terminalWidth: params.shellExecutionConfig?.terminalWidth ?? 80,
            terminalHeight: params.shellExecutionConfig?.terminalHeight ?? 24,
            showColor: params.shellExecutionConfig?.showColor ?? false,
            pager: params.shellExecutionConfig?.pager ?? 'cat',
        };
        this.truncateToolOutputThreshold =
            params.truncateToolOutputThreshold ??
                DEFAULT_TRUNCATE_TOOL_OUTPUT_THRESHOLD;
        this.truncateToolOutputLines =
            params.truncateToolOutputLines ?? DEFAULT_TRUNCATE_TOOL_OUTPUT_LINES;
        this.enableToolOutputTruncation = params.enableToolOutputTruncation ?? true;
        this.useSmartEdit = params.useSmartEdit ?? true;
        this.useWriteTodos = params.useWriteTodos ?? true;
        this.initialUseModelRouter = params.useModelRouter ?? false;
        this.useModelRouter = this.initialUseModelRouter;
        this.disableModelRouterForAuth = params.disableModelRouterForAuth ?? [];
        this.enableHooks = params.enableHooks ?? false;
        // Enable MessageBus integration if:
        // 1. Explicitly enabled via setting, OR
        // 2. Hooks are enabled and hooks are configured
        const hasHooks = params.hooks && Object.keys(params.hooks).length > 0;
        const hooksNeedMessageBus = this.enableHooks && hasHooks;
        this.enableMessageBusIntegration =
            params.enableMessageBusIntegration ??
                (hooksNeedMessageBus ? true : false);
        this.codebaseInvestigatorSettings = {
            enabled: params.codebaseInvestigatorSettings?.enabled ?? true,
            maxNumTurns: params.codebaseInvestigatorSettings?.maxNumTurns ?? 10,
            maxTimeMinutes: params.codebaseInvestigatorSettings?.maxTimeMinutes ?? 3,
            thinkingBudget: params.codebaseInvestigatorSettings?.thinkingBudget ??
                DEFAULT_THINKING_MODE,
            model: params.codebaseInvestigatorSettings?.model ?? DEFAULT_GEMINI_MODEL,
        };
        this.continueOnFailedApiCall = params.continueOnFailedApiCall ?? true;
        this.enableShellOutputEfficiency =
            params.enableShellOutputEfficiency ?? true;
        this.extensionManagement = params.extensionManagement ?? true;
        this.enableExtensionReloading = params.enableExtensionReloading ?? false;
        this.storage = new Storage(this.targetDir);
        this.fakeResponses = params.fakeResponses;
        this.recordResponses = params.recordResponses;
        this.enablePromptCompletion = params.enablePromptCompletion ?? false;
        this.fileExclusions = new FileExclusions(this);
        this.eventEmitter = params.eventEmitter;
        this.policyEngine = new PolicyEngine(params.policyEngineConfig);
        this.messageBus = new MessageBus(this.policyEngine, this.debugMode);
        this.outputSettings = {
            format: params.output?.format ?? OutputFormat.TEXT,
        };
        this.retryFetchErrors = params.retryFetchErrors ?? false;
        this.disableYoloMode = params.disableYoloMode ?? false;
        this.hooks = params.hooks;
        this.experiments = params.experiments;
        if (params.contextFileName) {
            setGeminiMdFilename(params.contextFileName);
        }
        if (this.telemetrySettings.enabled) {
            initializeTelemetry(this);
        }
        const proxy = this.getProxy();
        if (proxy) {
            try {
                setGlobalProxy(proxy);
            }
            catch (error) {
                coreEvents.emitFeedback('error', 'Invalid proxy configuration detected. Check debug drawer for more details (F12)', error);
            }
        }
        this.geminiClient = new GeminiClient(this);
        this.modelRouterService = new ModelRouterService(this);
        // HACK: The settings loading logic doesn't currently merge the default
        // generation config with the user's settings. This means if a user provides
        // any `generation` settings (e.g., just `overrides`), the default `aliases`
        // are lost. This hack manually merges the default aliases back in if they
        // are missing from the user's config.
        // TODO(12593): Fix the settings loading logic to properly merge defaults and
        // remove this hack.
        let modelConfigServiceConfig = params.modelConfigServiceConfig;
        if (modelConfigServiceConfig && !modelConfigServiceConfig.aliases) {
            modelConfigServiceConfig = {
                ...modelConfigServiceConfig,
                aliases: DEFAULT_MODEL_CONFIGS.aliases,
            };
        }
        this.modelConfigService = new ModelConfigService(modelConfigServiceConfig ?? DEFAULT_MODEL_CONFIGS);
    }
    /**
     * Must only be called once, throws if called again.
     */
    async initialize() {
        if (this.initialized) {
            throw Error('Config was already initialized');
        }
        this.initialized = true;
        // Initialize centralized FileDiscoveryService
        this.getFileService();
        if (this.getCheckpointingEnabled()) {
            await this.getGitService();
        }
        this.promptRegistry = new PromptRegistry();
        this.agentRegistry = new AgentRegistry(this);
        await this.agentRegistry.initialize();
        this.toolRegistry = await this.createToolRegistry();
        this.mcpClientManager = new McpClientManager(this.toolRegistry, this, this.eventEmitter);
        await Promise.all([
            await this.mcpClientManager.startConfiguredMcpServers(),
            await this.getExtensionLoader().start(this),
        ]);
        await this.geminiClient.initialize();
    }
    getContentGenerator() {
        return this.contentGenerator;
    }
    async refreshAuth(authMethod) {
        this.useModelRouter = this.initialUseModelRouter;
        if (this.disableModelRouterForAuth?.includes(authMethod)) {
            this.useModelRouter = false;
            if (this.model === DEFAULT_GEMINI_MODEL_AUTO) {
                this.model = DEFAULT_GEMINI_MODEL;
            }
        }
        // Vertex and Genai have incompatible encryption and sending history with
        // thoughtSignature from Genai to Vertex will fail, we need to strip them
        if (this.contentGeneratorConfig?.authType === AuthType.USE_GEMINI &&
            authMethod === AuthType.LOGIN_WITH_GOOGLE) {
            // Restore the conversation history to the new client
            this.geminiClient.stripThoughtsFromHistory();
        }
        const newContentGeneratorConfig = await createContentGeneratorConfig(this, authMethod);
        this.contentGenerator = await createContentGenerator(newContentGeneratorConfig, this, this.getSessionId());
        // Only assign to instance properties after successful initialization
        this.contentGeneratorConfig = newContentGeneratorConfig;
        // Initialize BaseLlmClient now that the ContentGenerator is available
        this.baseLlmClient = new BaseLlmClient(this.contentGenerator, this);
        const codeAssistServer = getCodeAssistServer(this);
        if (codeAssistServer) {
            this.experimentsPromise = getExperiments(codeAssistServer)
                .then((experiments) => {
                this.setExperiments(experiments);
            })
                .catch((e) => {
                debugLogger.error('Failed to fetch experiments', e);
            });
        }
        else {
            this.experiments = undefined;
            this.experimentsPromise = undefined;
        }
        // Reset the session flag since we're explicitly changing auth and using default model
        this.inFallbackMode = false;
    }
    getUserTier() {
        return this.contentGenerator?.userTier;
    }
    /**
     * Provides access to the BaseLlmClient for stateless LLM operations.
     */
    getBaseLlmClient() {
        if (!this.baseLlmClient) {
            // Handle cases where initialization might be deferred or authentication failed
            if (this.contentGenerator) {
                this.baseLlmClient = new BaseLlmClient(this.getContentGenerator(), this);
            }
            else {
                throw new Error('BaseLlmClient not initialized. Ensure authentication has occurred and ContentGenerator is ready.');
            }
        }
        return this.baseLlmClient;
    }
    getSessionId() {
        return this.sessionId;
    }
    setSessionId(sessionId) {
        this.sessionId = sessionId;
    }
    shouldLoadMemoryFromIncludeDirectories() {
        return this.loadMemoryFromIncludeDirectories;
    }
    getImportFormat() {
        return this.importFormat;
    }
    getDiscoveryMaxDirs() {
        return this.discoveryMaxDirs;
    }
    getContentGeneratorConfig() {
        return this.contentGeneratorConfig;
    }
    getModel() {
        return this.model;
    }
    setModel(newModel) {
        if (this.model !== newModel || this.inFallbackMode) {
            this.model = newModel;
            coreEvents.emitModelChanged(newModel);
        }
        this.setFallbackMode(false);
    }
    isInFallbackMode() {
        return this.inFallbackMode;
    }
    setFallbackMode(active) {
        this.inFallbackMode = active;
    }
    setFallbackModelHandler(handler) {
        this.fallbackModelHandler = handler;
    }
    getMaxSessionTurns() {
        return this.maxSessionTurns;
    }
    setQuotaErrorOccurred(value) {
        this.quotaErrorOccurred = value;
    }
    getQuotaErrorOccurred() {
        return this.quotaErrorOccurred;
    }
    getEmbeddingModel() {
        return this.embeddingModel;
    }
    getSandbox() {
        return this.sandbox;
    }
    isRestrictiveSandbox() {
        const sandboxConfig = this.getSandbox();
        const seatbeltProfile = process.env['SEATBELT_PROFILE'];
        return (!!sandboxConfig &&
            sandboxConfig.command === 'sandbox-exec' &&
            !!seatbeltProfile &&
            seatbeltProfile.startsWith('restrictive-'));
    }
    getTargetDir() {
        return this.targetDir;
    }
    getProjectRoot() {
        return this.targetDir;
    }
    getWorkspaceContext() {
        return this.workspaceContext;
    }
    getAgentRegistry() {
        return this.agentRegistry;
    }
    getToolRegistry() {
        return this.toolRegistry;
    }
    getPromptRegistry() {
        return this.promptRegistry;
    }
    getDebugMode() {
        return this.debugMode;
    }
    getQuestion() {
        return this.question;
    }
    getCoreTools() {
        return this.coreTools;
    }
    getAllowedTools() {
        return this.allowedTools;
    }
    /**
     * All the excluded tools from static configuration, loaded extensions, or
     * other sources.
     *
     * May change over time.
     */
    getExcludeTools() {
        const excludeToolsSet = new Set([...(this.excludeTools ?? [])]);
        for (const extension of this.getExtensionLoader().getExtensions()) {
            if (!extension.isActive) {
                continue;
            }
            for (const tool of extension.excludeTools || []) {
                excludeToolsSet.add(tool);
            }
        }
        return excludeToolsSet;
    }
    getToolDiscoveryCommand() {
        return this.toolDiscoveryCommand;
    }
    getToolCallCommand() {
        return this.toolCallCommand;
    }
    getMcpServerCommand() {
        return this.mcpServerCommand;
    }
    /**
     * The user configured MCP servers (via gemini settings files).
     *
     * Does NOT include mcp servers configured by extensions.
     */
    getMcpServers() {
        return this.mcpServers;
    }
    getMcpClientManager() {
        return this.mcpClientManager;
    }
    getAllowedMcpServers() {
        return this.allowedMcpServers;
    }
    getBlockedMcpServers() {
        return this.blockedMcpServers;
    }
    setMcpServers(mcpServers) {
        this.mcpServers = mcpServers;
    }
    getUserMemory() {
        return this.userMemory;
    }
    setUserMemory(newUserMemory) {
        this.userMemory = newUserMemory;
    }
    getGeminiMdFileCount() {
        return this.geminiMdFileCount;
    }
    setGeminiMdFileCount(count) {
        this.geminiMdFileCount = count;
    }
    getGeminiMdFilePaths() {
        return this.geminiMdFilePaths;
    }
    setGeminiMdFilePaths(paths) {
        this.geminiMdFilePaths = paths;
    }
    getApprovalMode() {
        return this.approvalMode;
    }
    setApprovalMode(mode) {
        if (!this.isTrustedFolder() && mode !== ApprovalMode.DEFAULT) {
            throw new Error('Cannot enable privileged approval modes in an untrusted folder.');
        }
        this.approvalMode = mode;
    }
    isYoloModeDisabled() {
        return this.disableYoloMode || !this.isTrustedFolder();
    }
    getPendingIncludeDirectories() {
        return this.pendingIncludeDirectories;
    }
    clearPendingIncludeDirectories() {
        this.pendingIncludeDirectories = [];
    }
    getShowMemoryUsage() {
        return this.showMemoryUsage;
    }
    getAccessibility() {
        return this.accessibility;
    }
    getTelemetryEnabled() {
        return this.telemetrySettings.enabled ?? false;
    }
    getTelemetryLogPromptsEnabled() {
        return this.telemetrySettings.logPrompts ?? true;
    }
    getTelemetryOtlpEndpoint() {
        return this.telemetrySettings.otlpEndpoint ?? DEFAULT_OTLP_ENDPOINT;
    }
    getTelemetryOtlpProtocol() {
        return this.telemetrySettings.otlpProtocol ?? 'grpc';
    }
    getTelemetryTarget() {
        return this.telemetrySettings.target ?? DEFAULT_TELEMETRY_TARGET;
    }
    getTelemetryOutfile() {
        return this.telemetrySettings.outfile;
    }
    getTelemetryUseCollector() {
        return this.telemetrySettings.useCollector ?? false;
    }
    getGeminiClient() {
        return this.geminiClient;
    }
    getModelRouterService() {
        return this.modelRouterService;
    }
    getEnableRecursiveFileSearch() {
        return this.fileFiltering.enableRecursiveFileSearch;
    }
    getFileFilteringDisableFuzzySearch() {
        return this.fileFiltering.disableFuzzySearch;
    }
    getFileFilteringRespectGitIgnore() {
        return this.fileFiltering.respectGitIgnore;
    }
    getFileFilteringRespectGeminiIgnore() {
        return this.fileFiltering.respectGeminiIgnore;
    }
    getFileFilteringOptions() {
        return {
            respectGitIgnore: this.fileFiltering.respectGitIgnore,
            respectGeminiIgnore: this.fileFiltering.respectGeminiIgnore,
        };
    }
    /**
     * Gets custom file exclusion patterns from configuration.
     * TODO: This is a placeholder implementation. In the future, this could
     * read from settings files, CLI arguments, or environment variables.
     */
    getCustomExcludes() {
        // Placeholder implementation - returns empty array for now
        // Future implementation could read from:
        // - User settings file
        // - Project-specific configuration
        // - Environment variables
        // - CLI arguments
        return [];
    }
    getCheckpointingEnabled() {
        return this.checkpointing;
    }
    getProxy() {
        return this.proxy;
    }
    getWorkingDir() {
        return this.cwd;
    }
    getBugCommand() {
        return this.bugCommand;
    }
    getFileService() {
        if (!this.fileDiscoveryService) {
            this.fileDiscoveryService = new FileDiscoveryService(this.targetDir);
        }
        return this.fileDiscoveryService;
    }
    getUsageStatisticsEnabled() {
        return this.usageStatisticsEnabled;
    }
    getExperimentalZedIntegration() {
        return this.experimentalZedIntegration;
    }
    getListExtensions() {
        return this.listExtensions;
    }
    getListSessions() {
        return this.listSessions;
    }
    getDeleteSession() {
        return this.deleteSession;
    }
    getExtensionManagement() {
        return this.extensionManagement;
    }
    getExtensions() {
        return this._extensionLoader.getExtensions();
    }
    getExtensionLoader() {
        return this._extensionLoader;
    }
    // The list of explicitly enabled extensions, if any were given, may contain
    // the string "none".
    getEnabledExtensions() {
        return this._enabledExtensions;
    }
    getEnableExtensionReloading() {
        return this.enableExtensionReloading;
    }
    getNoBrowser() {
        return this.noBrowser;
    }
    isBrowserLaunchSuppressed() {
        return this.getNoBrowser() || !shouldAttemptBrowserLaunch();
    }
    getSummarizeToolOutputConfig() {
        return this.summarizeToolOutput;
    }
    getIdeMode() {
        return this.ideMode;
    }
    /**
     * Returns 'true' if the folder trust feature is enabled.
     */
    getFolderTrust() {
        return this.folderTrust;
    }
    /**
     * Returns 'true' if the workspace is considered "trusted".
     * 'false' for untrusted.
     */
    isTrustedFolder() {
        // isWorkspaceTrusted in cli/src/config/trustedFolder.js returns undefined
        // when the file based trust value is unavailable, since it is mainly used
        // in the initialization for trust dialogs, etc. Here we return true since
        // config.isTrustedFolder() is used for the main business logic of blocking
        // tool calls etc in the rest of the application.
        //
        // Default value is true since we load with trusted settings to avoid
        // restarts in the more common path. If the user chooses to mark the folder
        // as untrusted, the CLI will restart and we will have the trust value
        // reloaded.
        const context = ideContextStore.get();
        if (context?.workspaceState?.isTrusted !== undefined) {
            return context.workspaceState.isTrusted;
        }
        return this.trustedFolder ?? true;
    }
    setIdeMode(value) {
        this.ideMode = value;
    }
    /**
     * Get the current FileSystemService
     */
    getFileSystemService() {
        return this.fileSystemService;
    }
    /**
     * Set a custom FileSystemService
     */
    setFileSystemService(fileSystemService) {
        this.fileSystemService = fileSystemService;
    }
    async getCompressionThreshold() {
        if (this.compressionThreshold) {
            return this.compressionThreshold;
        }
        await this.ensureExperimentsLoaded();
        const remoteThreshold = this.experiments?.flags[ExperimentFlags.CONTEXT_COMPRESSION_THRESHOLD]
            ?.floatValue;
        if (remoteThreshold === 0) {
            return undefined;
        }
        return remoteThreshold;
    }
    async getUserCaching() {
        await this.ensureExperimentsLoaded();
        return this.experiments?.flags[ExperimentFlags.USER_CACHING]?.boolValue;
    }
    async ensureExperimentsLoaded() {
        if (!this.experimentsPromise) {
            return;
        }
        try {
            await this.experimentsPromise;
        }
        catch (e) {
            debugLogger.debug('Failed to fetch experiments', e);
        }
    }
    isInteractiveShellEnabled() {
        return (this.interactive &&
            this.ptyInfo !== 'child_process' &&
            this.enableInteractiveShell);
    }
    isInteractive() {
        return this.interactive;
    }
    getUseRipgrep() {
        return this.useRipgrep;
    }
    getEnableInteractiveShell() {
        return this.enableInteractiveShell;
    }
    getSkipNextSpeakerCheck() {
        return this.skipNextSpeakerCheck;
    }
    getContinueOnFailedApiCall() {
        return this.continueOnFailedApiCall;
    }
    getRetryFetchErrors() {
        return this.retryFetchErrors;
    }
    getEnableShellOutputEfficiency() {
        return this.enableShellOutputEfficiency;
    }
    getShellExecutionConfig() {
        return this.shellExecutionConfig;
    }
    setShellExecutionConfig(config) {
        this.shellExecutionConfig = {
            terminalWidth: config.terminalWidth ?? this.shellExecutionConfig.terminalWidth,
            terminalHeight: config.terminalHeight ?? this.shellExecutionConfig.terminalHeight,
            showColor: config.showColor ?? this.shellExecutionConfig.showColor,
            pager: config.pager ?? this.shellExecutionConfig.pager,
        };
    }
    getScreenReader() {
        return this.accessibility.screenReader ?? false;
    }
    getEnablePromptCompletion() {
        return this.enablePromptCompletion;
    }
    getEnableToolOutputTruncation() {
        return this.enableToolOutputTruncation;
    }
    getTruncateToolOutputThreshold() {
        return Math.min(
        // Estimate remaining context window in characters (1 token ~= 4 chars).
        4 *
            (tokenLimit(this.model) - uiTelemetryService.getLastPromptTokenCount()), this.truncateToolOutputThreshold);
    }
    getTruncateToolOutputLines() {
        return this.truncateToolOutputLines;
    }
    getUseSmartEdit() {
        return this.useSmartEdit;
    }
    getUseWriteTodos() {
        return this.useWriteTodos;
    }
    getOutputFormat() {
        return this.outputSettings?.format
            ? this.outputSettings.format
            : OutputFormat.TEXT;
    }
    getUseModelRouter() {
        return this.useModelRouter;
    }
    async getGitService() {
        if (!this.gitService) {
            this.gitService = new GitService(this.targetDir, this.storage);
            await this.gitService.initialize();
        }
        return this.gitService;
    }
    getFileExclusions() {
        return this.fileExclusions;
    }
    getMessageBus() {
        return this.messageBus;
    }
    getPolicyEngine() {
        return this.policyEngine;
    }
    getEnableMessageBusIntegration() {
        return this.enableMessageBusIntegration;
    }
    getEnableHooks() {
        return this.enableHooks;
    }
    getCodebaseInvestigatorSettings() {
        return this.codebaseInvestigatorSettings;
    }
    async createToolRegistry() {
        const registry = new ToolRegistry(this);
        // Set message bus on tool registry before discovery so MCP tools can access it
        if (this.getEnableMessageBusIntegration()) {
            registry.setMessageBus(this.messageBus);
        }
        // helper to create & register core tools that are enabled
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const registerCoreTool = (ToolClass, ...args) => {
            const className = ToolClass.name;
            const toolName = ToolClass.Name || className;
            const coreTools = this.getCoreTools();
            // On some platforms, the className can be minified to _ClassName.
            const normalizedClassName = className.replace(/^_+/, '');
            let isEnabled = true; // Enabled by default if coreTools is not set.
            if (coreTools) {
                isEnabled = coreTools.some((tool) => tool === toolName ||
                    tool === normalizedClassName ||
                    tool.startsWith(`${toolName}(`) ||
                    tool.startsWith(`${normalizedClassName}(`));
            }
            if (isEnabled) {
                // Pass message bus to tools when feature flag is enabled
                // This first implementation is only focused on the general case of
                // the tool registry.
                const messageBusEnabled = this.getEnableMessageBusIntegration();
                const toolArgs = messageBusEnabled
                    ? [...args, this.getMessageBus()]
                    : args;
                registry.registerTool(new ToolClass(...toolArgs));
            }
        };
        registerCoreTool(LSTool, this);
        registerCoreTool(ReadFileTool, this);
        if (this.getUseRipgrep()) {
            let useRipgrep = false;
            let errorString = undefined;
            try {
                useRipgrep = await canUseRipgrep();
            }
            catch (error) {
                errorString = String(error);
            }
            if (useRipgrep) {
                registerCoreTool(RipGrepTool, this);
            }
            else {
                logRipgrepFallback(this, new RipgrepFallbackEvent(errorString));
                registerCoreTool(GrepTool, this);
            }
        }
        else {
            registerCoreTool(GrepTool, this);
        }
        registerCoreTool(GlobTool, this);
        if (this.getUseSmartEdit()) {
            registerCoreTool(SmartEditTool, this);
        }
        else {
            registerCoreTool(EditTool, this);
        }
        registerCoreTool(WriteFileTool, this);
        registerCoreTool(WebFetchTool, this);
        registerCoreTool(ShellTool, this);
        registerCoreTool(MemoryTool);
        registerCoreTool(WebSearchTool, this);
        if (this.getUseWriteTodos()) {
            registerCoreTool(WriteTodosTool, this);
        }
        // Register Subagents as Tools
        if (this.getCodebaseInvestigatorSettings().enabled) {
            const definition = this.agentRegistry.getDefinition('codebase_investigator');
            if (definition) {
                // We must respect the main allowed/exclude lists for agents too.
                const allowedTools = this.getAllowedTools();
                const isAllowed = !allowedTools || allowedTools.includes(definition.name);
                if (isAllowed) {
                    const messageBusEnabled = this.getEnableMessageBusIntegration();
                    const wrapper = new SubagentToolWrapper(definition, this, messageBusEnabled ? this.getMessageBus() : undefined);
                    registry.registerTool(wrapper);
                }
            }
        }
        await registry.discoverAllTools();
        registry.sortTools();
        return registry;
    }
    /**
     * Get hooks configuration
     */
    getHooks() {
        return this.hooks;
    }
    /**
     * Get experiments configuration
     */
    getExperiments() {
        return this.experiments;
    }
    /**
     * Set experiments configuration
     */
    setExperiments(experiments) {
        this.experiments = experiments;
        const flagSummaries = Object.entries(experiments.flags ?? {})
            .sort(([a], [b]) => a.localeCompare(b))
            .map(([flagId, flag]) => {
            const summary = { flagId };
            if (flag.boolValue !== undefined) {
                summary['boolValue'] = flag.boolValue;
            }
            if (flag.floatValue !== undefined) {
                summary['floatValue'] = flag.floatValue;
            }
            if (flag.intValue !== undefined) {
                summary['intValue'] = flag.intValue;
            }
            if (flag.stringValue !== undefined) {
                summary['stringValue'] = flag.stringValue;
            }
            const int32Length = flag.int32ListValue?.values?.length ?? 0;
            if (int32Length > 0) {
                summary['int32ListLength'] = int32Length;
            }
            const stringListLength = flag.stringListValue?.values?.length ?? 0;
            if (stringListLength > 0) {
                summary['stringListLength'] = stringListLength;
            }
            return summary;
        });
        const summary = {
            experimentIds: experiments.experimentIds ?? [],
            flags: flagSummaries,
        };
        const summaryString = inspect(summary, {
            depth: null,
            maxArrayLength: null,
            maxStringLength: null,
            breakLength: 80,
            compact: false,
        });
        debugLogger.debug('Experiments loaded', summaryString);
    }
}
// Export model constants for use in CLI
export { DEFAULT_GEMINI_FLASH_MODEL };
//# sourceMappingURL=config.js.map