/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import * as path from 'node:path';
import os from 'node:os';
import process from 'node:process';
import { AuthType, 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 { RipGrepTool } from '../tools/ripGrep.js';
import { GlobTool } from '../tools/glob.js';
import { DebugLogger } from '../debug/DebugLogger.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 { GoogleWebFetchTool } from '../tools/google-web-fetch.js';
import { ReadManyFilesTool } from '../tools/read-many-files.js';
import { ReadLineRangeTool } from '../tools/read_line_range.js';
import { DeleteLineRangeTool } from '../tools/delete_line_range.js';
import { InsertAtLineTool } from '../tools/insert_at_line.js';
import { MemoryTool, setLlxprtMdFilename, LLXPRT_CONFIG_DIR as LLXPRT_DIR, } from '../tools/memoryTool.js';
import { GoogleWebSearchTool } from '../tools/google-web-search.js';
import { ExaWebSearchTool } from '../tools/exa-web-search.js';
import { TodoWrite } from '../tools/todo-write.js';
import { TodoRead } from '../tools/todo-read.js';
import { TodoPause } from '../tools/todo-pause.js';
import { CodeSearchTool } from '../tools/codesearch.js';
import { DirectWebFetchTool } from '../tools/direct-web-fetch.js';
import { TaskTool } from '../tools/task.js';
import { ListSubagentsTool } from '../tools/list-subagents.js';
import { GeminiClient } from '../core/client.js';
import { createAgentRuntimeStateFromConfig } from '../runtime/runtimeStateFactory.js';
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
import { GitService } from '../services/gitService.js';
import { loadServerHierarchicalMemory } from '../utils/memoryDiscovery.js';
import { 
// TELEMETRY: Re-enabled for local file logging only
initializeTelemetry, DEFAULT_TELEMETRY_TARGET, DEFAULT_OTLP_ENDPOINT, logCliConfiguration, StartSessionEvent, } from '../telemetry/index.js';
import { DEFAULT_GEMINI_FLASH_MODEL } from './models.js';
import { shouldAttemptBrowserLaunch } from '../utils/browser.js';
import { IdeClient } from '../ide/ide-client.js';
import { ideContext } from '../ide/ideContext.js';
import { registerSettingsService } from '../settings/settingsServiceInstance.js';
import { createProviderRuntimeContext, getActiveProviderRuntimeContext, peekActiveProviderRuntimeContext, setActiveProviderRuntimeContext, } from '../runtime/providerRuntimeContext.js';
import { StandardFileSystemService, } from '../services/fileSystemService.js';
import { ProfileManager } from './profileManager.js';
import { SubagentManager } from './subagentManager.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';
export var ApprovalMode;
(function (ApprovalMode) {
    ApprovalMode["DEFAULT"] = "default";
    ApprovalMode["AUTO_EDIT"] = "autoEdit";
    ApprovalMode["YOLO"] = "yolo";
})(ApprovalMode || (ApprovalMode = {}));
import { DEFAULT_MEMORY_FILE_FILTERING_OPTIONS, DEFAULT_FILE_FILTERING_OPTIONS, } from './constants.js';
export { DEFAULT_MEMORY_FILE_FILTERING_OPTIONS, DEFAULT_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;
    extensionName;
    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, extensionName, 
    // 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.extensionName = extensionName;
        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;
    promptRegistry;
    sessionId;
    settingsService;
    fileSystemService;
    contentGeneratorConfig;
    embeddingModel;
    sandbox;
    targetDir;
    workspaceContext;
    debugMode;
    question;
    fullContext;
    coreTools;
    allowedTools;
    excludeTools;
    toolDiscoveryCommand;
    toolCallCommand;
    mcpServerCommand;
    mcpServers;
    userMemory;
    llxprtMdFileCount;
    llxprtMdFilePaths;
    approvalMode;
    showMemoryUsage;
    accessibility;
    telemetrySettings;
    usageStatisticsEnabled;
    geminiClient;
    runtimeState;
    fileFiltering;
    alwaysAllowedCommands = new Set();
    fileDiscoveryService = null;
    gitService = undefined;
    checkpointing;
    dumpOnError;
    proxy;
    cwd;
    bugCommand;
    model;
    originalModel;
    extensionContextFilePaths;
    noBrowser;
    folderTrustFeature;
    folderTrust;
    ideMode;
    ideClient;
    inFallbackMode = false;
    _modelSwitchedDuringSession = false;
    maxSessionTurns;
    _activeExtensions;
    listExtensions;
    _extensions;
    _blockedMcpServers;
    providerManager;
    profileManager;
    subagentManager;
    subagentSchedulerFactory;
    bucketFailoverHandler;
    // Track all potential tools for settings UI
    allPotentialTools = [];
    setProviderManager(providerManager) {
        this.providerManager = providerManager;
    }
    getProviderManager() {
        return this.providerManager;
    }
    setProfileManager(manager) {
        this.profileManager = manager;
    }
    getProfileManager() {
        return this.profileManager;
    }
    setSubagentManager(manager) {
        this.subagentManager = manager;
    }
    getSubagentManager() {
        return this.subagentManager;
    }
    /**
     * Set the bucket failover handler for rate limit/quota error handling
     * @plan PLAN-20251213issue490
     */
    setBucketFailoverHandler(handler) {
        this.bucketFailoverHandler = handler;
    }
    /**
     * Get the bucket failover handler
     * @plan PLAN-20251213issue490
     */
    getBucketFailoverHandler() {
        return this.bucketFailoverHandler;
    }
    setInteractiveSubagentSchedulerFactory(factory) {
        this.subagentSchedulerFactory = factory;
    }
    getInteractiveSubagentSchedulerFactory() {
        return this.subagentSchedulerFactory;
    }
    provider;
    summarizeToolOutput;
    experimentalZedIntegration = false;
    complexityAnalyzerSettings;
    loadMemoryFromIncludeDirectories = false;
    chatCompression;
    interactive;
    trustedFolder;
    useRipgrep;
    shouldUseNodePtyShell;
    skipNextSpeakerCheck;
    extensionManagement;
    enablePromptCompletion = false;
    initialized = false;
    shellReplacement = false;
    storage;
    fileExclusions;
    eventEmitter;
    useSmartEdit;
    messageBus;
    policyEngine;
    truncateToolOutputThreshold;
    truncateToolOutputLines;
    enableToolOutputTruncation;
    constructor(params) {
        const providedSettingsService = params.settingsService;
        if (providedSettingsService) {
            registerSettingsService(providedSettingsService);
        }
        const existingContext = peekActiveProviderRuntimeContext();
        if (providedSettingsService) {
            this.settingsService = providedSettingsService;
        }
        else if (existingContext?.settingsService) {
            this.settingsService = existingContext.settingsService;
        }
        else {
            this.settingsService = getActiveProviderRuntimeContext().settingsService;
        }
        const currentContext = peekActiveProviderRuntimeContext();
        if (!currentContext) {
            setActiveProviderRuntimeContext(createProviderRuntimeContext({
                settingsService: this.settingsService,
                config: this,
                runtimeId: providedSettingsService
                    ? 'injected-config'
                    : 'legacy-config',
                metadata: { source: 'ConfigConstructor' },
            }));
        }
        else if (currentContext.settingsService === this.settingsService &&
            currentContext.config !== this) {
            setActiveProviderRuntimeContext({
                ...currentContext,
                config: this,
            });
        }
        this.sessionId = params.sessionId;
        // Embedding models not currently configured for llxprt-code
        this.embeddingModel = params.embeddingModel;
        this.fileSystemService = new StandardFileSystemService();
        this.sandbox = params.sandbox;
        this.targetDir = path.resolve(params.targetDir);
        this.workspaceContext = new WorkspaceContext(this.targetDir, params.includeDirectories ?? []);
        this.debugMode = params.debugMode;
        this.question = params.question;
        this.fullContext = params.fullContext ?? false;
        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.userMemory = params.userMemory ?? '';
        this.llxprtMdFileCount = params.llxprtMdFileCount ?? 0;
        this.llxprtMdFilePaths = params.llxprtMdFilePaths ?? [];
        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,
            logPrompts: params.telemetry?.logPrompts ?? true,
            outfile: params.telemetry?.outfile,
            logConversations: params.telemetry?.logConversations ?? false,
            logResponses: params.telemetry?.logResponses ?? false,
            redactSensitiveData: params.telemetry?.redactSensitiveData ?? true,
            redactFilePaths: params.telemetry?.redactFilePaths ?? false,
            redactUrls: params.telemetry?.redactUrls ?? false,
            redactEmails: params.telemetry?.redactEmails ?? false,
            redactPersonalInfo: params.telemetry?.redactPersonalInfo ?? false,
        };
        this.usageStatisticsEnabled = params.usageStatisticsEnabled ?? true;
        this.fileFiltering = {
            respectGitIgnore: params.fileFiltering?.respectGitIgnore ?? true,
            respectLlxprtIgnore: params.fileFiltering?.respectLlxprtIgnore ?? true,
            enableRecursiveFileSearch: params.fileFiltering?.enableRecursiveFileSearch ?? true,
            disableFuzzySearch: params.fileFiltering?.disableFuzzySearch ?? false,
        };
        this.checkpointing = params.checkpointing ?? false;
        this.dumpOnError = params.dumpOnError ?? 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.originalModel = params.model;
        this.extensionContextFilePaths = params.extensionContextFilePaths ?? [];
        this.maxSessionTurns = params.maxSessionTurns ?? -1;
        this.experimentalZedIntegration =
            params.experimentalZedIntegration ?? false;
        this.listExtensions = params.listExtensions ?? false;
        this._activeExtensions = params.activeExtensions ?? [];
        this.providerManager = params.providerManager;
        this.provider = params.provider;
        this._extensions = params.extensions ?? [];
        this._blockedMcpServers = params.blockedMcpServers ?? [];
        this.noBrowser = params.noBrowser ?? false;
        this.summarizeToolOutput = params.summarizeToolOutput;
        this.folderTrustFeature = params.folderTrustFeature ?? false;
        this.folderTrust = params.folderTrust ?? false;
        this.ideMode = params.ideMode ?? false;
        this.complexityAnalyzerSettings = params.complexityAnalyzer ?? {
            complexityThreshold: 0.5,
            minTasksForSuggestion: 3,
            suggestionCooldownMs: 300000, // 5 minutes
        };
        this.loadMemoryFromIncludeDirectories =
            params.loadMemoryFromIncludeDirectories ?? false;
        this.chatCompression = params.chatCompression;
        this.interactive = params.interactive ?? false;
        this.shellReplacement = params.shellReplacement ?? false;
        this.trustedFolder = params.trustedFolder;
        this.useRipgrep = params.useRipgrep ?? false;
        this.shouldUseNodePtyShell = params.shouldUseNodePtyShell ?? false;
        this.skipNextSpeakerCheck = params.skipNextSpeakerCheck ?? false;
        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 ?? false;
        this.extensionManagement = params.extensionManagement ?? false;
        this.storage = new Storage(this.targetDir);
        this.enablePromptCompletion = params.enablePromptCompletion ?? false;
        this.fileExclusions = new FileExclusions(this);
        this.eventEmitter = params.eventEmitter;
        // Initialize policy engine and message bus
        this.policyEngine = new PolicyEngine(params.policyEngineConfig);
        this.messageBus = new MessageBus(this.policyEngine, this.debugMode);
        this.runtimeState = createAgentRuntimeStateFromConfig(this);
        if (params.contextFileName) {
            setLlxprtMdFilename(params.contextFileName);
        }
        // TELEMETRY: Re-enabled for local file logging only - no network endpoints allowed
        const isTestEnvironment = process.env.NODE_ENV === 'test' || process.env.VITEST;
        if (process.env.VERBOSE === 'true' && !isTestEnvironment) {
            console.log(`[CONFIG] Telemetry settings:`, JSON.stringify(this.telemetrySettings));
        }
        if (this.telemetrySettings.enabled) {
            if (process.env.VERBOSE === 'true' && !isTestEnvironment) {
                console.log(`[CONFIG] Initializing telemetry`);
            }
            initializeTelemetry(this);
        }
        else if (process.env.VERBOSE === 'true' && !isTestEnvironment) {
            console.log(`[CONFIG] Telemetry disabled`);
        }
        logCliConfiguration(this, new StartSessionEvent(this));
    }
    /**
     * Must only be called once, throws if called again.
     */
    async initialize() {
        if (this.initialized) {
            throw Error('Config was already initialized');
        }
        this.initialized = true;
        this.ideClient = await IdeClient.getInstance();
        // Initialize centralized FileDiscoveryService
        this.getFileService();
        if (this.getCheckpointingEnabled()) {
            await this.getGitService();
        }
        this.promptRegistry = new PromptRegistry();
        this.toolRegistry = await this.createToolRegistry();
        // Create GeminiClient instance immediately without authentication
        // This ensures geminiClient is available for providers on startup
        this.geminiClient = new GeminiClient(this, this.runtimeState);
        // Reserved for future model switching tracking
        void this._modelSwitchedDuringSession;
    }
    async refreshAuth(authMethod) {
        const logger = new DebugLogger('llxprt:config:refreshAuth');
        // Save the current conversation history AND HistoryService before creating a new client
        const previousGeminiClient = this.geminiClient;
        let existingHistory = [];
        let existingHistoryService = null;
        if (previousGeminiClient && previousGeminiClient.isInitialized()) {
            existingHistory = await previousGeminiClient.getHistory();
            existingHistoryService = previousGeminiClient.getHistoryService();
            logger.debug('Retrieved existing state', {
                historyLength: existingHistory.length,
                hasHistoryService: !!existingHistoryService,
                authMethod,
            });
        }
        // Create new content generator config
        const newContentGeneratorConfig = createContentGeneratorConfig(this, authMethod);
        // Add provider manager to the config if available (llxprt multi-provider support)
        if (this.providerManager) {
            newContentGeneratorConfig.providerManager = this.providerManager;
        }
        const updatedRuntimeState = createAgentRuntimeStateFromConfig(this, {
            runtimeId: this.runtimeState.runtimeId,
            overrides: {
                model: newContentGeneratorConfig.model,
                authType: newContentGeneratorConfig.authType ?? this.runtimeState.authType,
                authPayload: newContentGeneratorConfig.apiKey
                    ? { apiKey: newContentGeneratorConfig.apiKey }
                    : undefined,
                proxyUrl: newContentGeneratorConfig.proxy ?? this.runtimeState.proxyUrl,
            },
        });
        this.runtimeState = updatedRuntimeState;
        // Create new client in local variable first
        const newGeminiClient = new GeminiClient(this, this.runtimeState);
        // CRITICAL: Store both the history AND the HistoryService instance
        // This preserves both the API conversation context and the UI's conversation display
        if (existingHistoryService) {
            logger.debug('Storing existing HistoryService for reuse', {
                historyLength: existingHistory.length,
            });
            newGeminiClient.storeHistoryServiceForReuse(existingHistoryService);
        }
        if (existingHistory.length > 0) {
            // Vertex and Genai have incompatible encryption and sending history with
            // throughtSignature from Genai to Vertex will fail, we need to strip them
            const fromGenaiToVertex = this.contentGeneratorConfig?.authType === AuthType.USE_GEMINI &&
                authMethod === AuthType.LOGIN_WITH_GOOGLE;
            logger.debug('Storing history for later use', {
                historyLength: existingHistory.length,
                fromGenaiToVertex,
                willStripThoughts: fromGenaiToVertex,
            });
            // Use storeHistoryForLaterUse to ensure history is preserved through initialization
            const historyToStore = fromGenaiToVertex
                ? existingHistory.map((content) => {
                    const newContent = { ...content };
                    if (newContent.parts) {
                        newContent.parts = newContent.parts.map((part) => {
                            if (part &&
                                typeof part === 'object' &&
                                'thoughtSignature' in part) {
                                const newPart = { ...part };
                                delete newPart
                                    .thoughtSignature;
                                return newPart;
                            }
                            return part;
                        });
                    }
                    return newContent;
                })
                : existingHistory;
            newGeminiClient.storeHistoryForLaterUse(historyToStore);
            logger.debug('History stored in new client', {
                storedHistoryLength: historyToStore.length,
            });
        }
        // Now initialize with the new config
        await newGeminiClient.initialize(newContentGeneratorConfig);
        logger.debug('New client initialized');
        // Only assign to instance properties after successful initialization
        this.contentGeneratorConfig = newContentGeneratorConfig;
        if (previousGeminiClient &&
            typeof previousGeminiClient.dispose === 'function') {
            try {
                previousGeminiClient.dispose();
            }
            catch (error) {
                logger.warn(() => `Failed to dispose previous GeminiClient: ${error instanceof Error ? error.message : String(error)}`);
            }
        }
        this.geminiClient = newGeminiClient;
        // Verify history was preserved
        const newHistory = await this.geminiClient.getHistory();
        const newHistoryService = this.geminiClient.getHistoryService();
        logger.debug('State verification after refreshAuth', {
            originalHistoryLength: existingHistory.length,
            newHistoryLength: newHistory.length,
            historyPreserved: newHistory.length > 0,
            historyServicePreserved: existingHistoryService === newHistoryService,
        });
        // Reset the session flag since we're explicitly changing auth and using default model
        this.inFallbackMode = false;
    }
    getSessionId() {
        return this.sessionId;
    }
    shouldLoadMemoryFromIncludeDirectories() {
        return this.loadMemoryFromIncludeDirectories;
    }
    getContentGeneratorConfig() {
        return this.contentGeneratorConfig;
    }
    getModel() {
        // Delegate to SettingsService as source of truth
        const settingsService = this.getSettingsService();
        if (settingsService) {
            const activeProvider = settingsService.get('activeProvider');
            if (activeProvider) {
                const providerSettings = settingsService.getProviderSettings(activeProvider);
                if (providerSettings.model) {
                    return providerSettings.model;
                }
            }
        }
        // Fallback to legacy
        return this.contentGeneratorConfig?.model || this.model;
    }
    setModel(newModel) {
        // Update SettingsService as source of truth
        const settingsService = this.getSettingsService();
        if (settingsService) {
            const activeProvider = settingsService.get('activeProvider');
            if (activeProvider) {
                settingsService.setProviderSetting(activeProvider, 'model', newModel);
            }
        }
        // Keep legacy updates for backward compatibility
        if (this.contentGeneratorConfig) {
            this.contentGeneratorConfig.model = newModel;
        }
        // Also update the base model so it persists across refreshAuth
        this.model = newModel;
    }
    isInFallbackMode() {
        return this.inFallbackMode;
    }
    resetModelToDefault() {
        if (this.contentGeneratorConfig) {
            this.contentGeneratorConfig.model = this.originalModel; // Reset to the original default model
            this.inFallbackMode = false;
        }
        this.model = this.originalModel;
    }
    setFallbackMode(active) {
        this.inFallbackMode = active;
    }
    getMaxSessionTurns() {
        return this.maxSessionTurns;
    }
    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;
    }
    getToolRegistry() {
        return this.toolRegistry;
    }
    getPromptRegistry() {
        return this.promptRegistry;
    }
    getDebugMode() {
        return this.debugMode;
    }
    getQuestion() {
        return this.question;
    }
    getFullContext() {
        return this.fullContext;
    }
    getCoreTools() {
        return this.coreTools;
    }
    getAllowedTools() {
        return this.allowedTools;
    }
    getExcludeTools() {
        return this.excludeTools;
    }
    getToolDiscoveryCommand() {
        return this.toolDiscoveryCommand;
    }
    getToolCallCommand() {
        return this.toolCallCommand;
    }
    getMcpServerCommand() {
        return this.mcpServerCommand;
    }
    getMcpServers() {
        return this.mcpServers;
    }
    getUserMemory() {
        return this.userMemory;
    }
    setUserMemory(newUserMemory) {
        this.userMemory = newUserMemory;
    }
    getLlxprtMdFileCount() {
        return this.llxprtMdFileCount;
    }
    setLlxprtMdFileCount(count) {
        this.llxprtMdFileCount = count;
    }
    getLlxprtMdFilePaths() {
        return this.llxprtMdFilePaths;
    }
    setLlxprtMdFilePaths(paths) {
        this.llxprtMdFilePaths = 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;
    }
    getMessageBus() {
        return this.messageBus;
    }
    getPolicyEngine() {
        return this.policyEngine;
    }
    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;
    }
    getTelemetryTarget() {
        return this.telemetrySettings.target ?? DEFAULT_TELEMETRY_TARGET;
    }
    getTelemetryOutfile() {
        return this.telemetrySettings.outfile;
    }
    // Conversation logging configuration methods
    getConversationLoggingEnabled() {
        // Check CLI flags first - placeholder for future CLI implementation
        // For now, check environment variables and settings file
        // Check environment variables
        const envVar = process.env.LLXPRT_LOG_CONVERSATIONS;
        if (envVar !== undefined) {
            return envVar.toLowerCase() === 'true';
        }
        // Check settings file
        return this.telemetrySettings.logConversations ?? false;
    }
    getResponseLoggingEnabled() {
        return this.telemetrySettings.logResponses ?? false;
    }
    getConversationLogPath() {
        // Check environment variable first
        const envPath = process.env.LLXPRT_CONVERSATION_LOG_PATH;
        if (envPath) {
            return this.expandPath(envPath);
        }
        // Check settings file
        if (this.telemetrySettings.conversationLogPath) {
            return this.expandPath(this.telemetrySettings.conversationLogPath);
        }
        // Default path
        return this.expandPath('~/.llxprt/conversations/');
    }
    getMaxConversationHistory() {
        return this.telemetrySettings.maxConversationHistory ?? 50;
    }
    getConversationRetentionDays() {
        return this.telemetrySettings.retentionDays ?? 30;
    }
    getMaxLogFiles() {
        return this.telemetrySettings.maxLogFiles ?? 10;
    }
    getMaxLogSizeMB() {
        return this.telemetrySettings.maxLogSizeMB ?? 100;
    }
    // Privacy configuration methods
    getRedactionConfig() {
        return {
            redactApiKeys: this.telemetrySettings.redactSensitiveData ?? true,
            redactCredentials: this.telemetrySettings.redactSensitiveData ?? true,
            redactFilePaths: this.telemetrySettings.redactFilePaths ?? false,
            redactUrls: this.telemetrySettings.redactUrls ?? false,
            redactEmails: this.telemetrySettings.redactEmails ?? false,
            redactPersonalInfo: this.telemetrySettings.redactPersonalInfo ?? false,
            customPatterns: this.telemetrySettings.customRedactionPatterns,
        };
    }
    getDataRetentionEnabled() {
        return this.telemetrySettings.enableDataRetention ?? true;
    }
    getConversationExpirationDays() {
        return this.telemetrySettings.conversationExpirationDays ?? 30;
    }
    getMaxConversationsStored() {
        return this.telemetrySettings.maxConversationsStored ?? 1000;
    }
    getTelemetrySettings() {
        return {
            ...this.telemetrySettings,
            remoteConsentGiven: this.telemetrySettings.remoteConsentGiven,
        };
    }
    updateTelemetrySettings(settings) {
        this.telemetrySettings = {
            ...this.telemetrySettings,
            ...settings,
        };
        // If we have a provider manager, update its config to trigger re-wrapping
        if (this.providerManager) {
            this.providerManager.setConfig(this);
        }
    }
    expandPath(path) {
        if (path.startsWith('~/')) {
            return path.replace('~', process.env.HOME || '');
        }
        return path;
    }
    getGeminiClient() {
        return this.geminiClient;
    }
    getGeminiDir() {
        return path.join(this.targetDir, LLXPRT_DIR);
    }
    getProjectTempDir() {
        return this.storage.getProjectTempDir();
    }
    getEnableRecursiveFileSearch() {
        return this.fileFiltering.enableRecursiveFileSearch;
    }
    getFileFilteringDisableFuzzySearch() {
        return this.fileFiltering.disableFuzzySearch;
    }
    getFileFilteringRespectGitIgnore() {
        return this.fileFiltering.respectGitIgnore;
    }
    getFileFilteringRespectLlxprtIgnore() {
        return this.fileFiltering.respectLlxprtIgnore;
    }
    getFileFilteringOptions() {
        return {
            respectGitIgnore: this.fileFiltering.respectGitIgnore,
            respectLlxprtIgnore: this.fileFiltering.respectLlxprtIgnore,
        };
    }
    /**
     * 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;
    }
    getDumpOnError() {
        return this.dumpOnError;
    }
    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;
    }
    getExtensionContextFilePaths() {
        return this.extensionContextFilePaths;
    }
    getExperimentalZedIntegration() {
        return this.experimentalZedIntegration;
    }
    getListExtensions() {
        return this.listExtensions;
    }
    getExtensionManagement() {
        return this.extensionManagement;
    }
    getExtensions() {
        return this._extensions;
    }
    getActiveExtensions() {
        return this._activeExtensions;
    }
    getBlockedMcpServers() {
        return this._blockedMcpServers;
    }
    getProvider() {
        return this.provider;
    }
    setProvider(provider) {
        this.provider = provider;
    }
    getNoBrowser() {
        return this.noBrowser;
    }
    isBrowserLaunchSuppressed() {
        return this.getNoBrowser() || !shouldAttemptBrowserLaunch();
    }
    getSummarizeToolOutputConfig() {
        return this.summarizeToolOutput;
    }
    getIdeClient() {
        return this.ideClient;
    }
    getIdeMode() {
        return this.ideMode;
    }
    getFolderTrustFeature() {
        return this.folderTrustFeature;
    }
    /**
     * Returns 'true' if the workspace is considered "trusted".
     * 'false' for untrusted.
     */
    getFolderTrust() {
        return this.folderTrust;
    }
    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 = ideContext.getIdeContext();
        if (context?.workspaceState?.isTrusted !== undefined) {
            return context.workspaceState.isTrusted;
        }
        return this.trustedFolder ?? true;
    }
    setIdeMode(value) {
        this.ideMode = value;
    }
    setIdeClientDisconnected() {
        this.ideClient?.disconnect();
    }
    setIdeClientConnected() {
        this.ideClient?.connect();
    }
    getComplexityAnalyzerSettings() {
        return this.complexityAnalyzerSettings;
    }
    normalizeStreamingValue(value) {
        if (value === undefined || value === null) {
            return value;
        }
        if (typeof value === 'boolean') {
            return value ? 'enabled' : 'disabled';
        }
        if (typeof value === 'string') {
            const normalized = value.trim().toLowerCase();
            if (normalized === 'true') {
                return 'enabled';
            }
            if (normalized === 'false') {
                return 'disabled';
            }
            if (normalized === 'enabled' || normalized === 'disabled') {
                return normalized;
            }
        }
        return value;
    }
    normalizeAndPersistStreaming(value) {
        const normalized = this.normalizeStreamingValue(value);
        if (normalized !== value && normalized !== undefined) {
            this.settingsService.set('streaming', normalized);
            return normalized;
        }
        return normalized;
    }
    getEphemeralSetting(key) {
        const rawValue = this.settingsService.get(key);
        if (key === 'streaming') {
            return this.normalizeAndPersistStreaming(rawValue);
        }
        if (key === 'context-limit') {
            const normalized = this.normalizeContextLimit(rawValue);
            if (normalized !== undefined) {
                if (normalized !== rawValue) {
                    this.settingsService.set(key, normalized);
                }
                return normalized;
            }
            return undefined;
        }
        return rawValue;
    }
    normalizeContextLimit(value) {
        if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
            return Math.floor(value);
        }
        if (typeof value === 'string') {
            const trimmed = value.trim();
            if (trimmed === '') {
                return undefined;
            }
            const parsed = Number(trimmed);
            if (Number.isFinite(parsed) && parsed > 0) {
                return Math.floor(parsed);
            }
        }
        return undefined;
    }
    setEphemeralSetting(key, value) {
        let settingValue = value;
        if (key === 'streaming') {
            settingValue = this.normalizeStreamingValue(value);
        }
        if (key === 'context-limit') {
            settingValue =
                value === undefined ? undefined : this.normalizeContextLimit(value);
        }
        if (key === 'streaming' &&
            settingValue !== undefined &&
            typeof settingValue !== 'string') {
            throw new Error('Streaming setting must resolve to "enabled" or "disabled"');
        }
        // Line 90: Direct delegation, no local storage
        this.settingsService.set(key, settingValue);
        // Clear provider caches when auth settings or base-url change
        // This fixes the issue where cached auth tokens persist after clearing auth settings
        if (key === 'auth-key' ||
            key === 'auth-keyfile' ||
            key === 'base-url' ||
            key === 'socket-timeout' ||
            key === 'socket-keepalive' ||
            key === 'socket-nodelay' ||
            key === 'streaming') {
            if (this.providerManager) {
                const activeProvider = this.providerManager.getActiveProvider();
                if (activeProvider) {
                    // Clear cached OpenAI client if provider has this method
                    if ('clearClientCache' in activeProvider &&
                        typeof activeProvider.clearClientCache === 'function') {
                        const providerWithClearCache = activeProvider;
                        providerWithClearCache.clearClientCache();
                    }
                    // Clear cached auth token if provider has this method
                    if ('clearAuthCache' in activeProvider &&
                        typeof activeProvider.clearAuthCache === 'function') {
                        const providerWithClearAuth = activeProvider;
                        providerWithClearAuth.clearAuthCache();
                    }
                }
            }
        }
        // NO async operations
        // NO queue processing
    }
    clearEphemeralSettings() {
        // Line 97: Direct delegation
        this.settingsService.clear();
    }
    getEphemeralSettings() {
        // Return a copy of all global settings from the SettingsService
        const allSettings = this.settingsService.getAllGlobalSettings();
        if ('streaming' in allSettings) {
            const normalized = this.normalizeAndPersistStreaming(allSettings.streaming);
            if (normalized !== undefined) {
                allSettings.streaming = normalized;
            }
        }
        return allSettings;
    }
    isInteractive() {
        return this.interactive;
    }
    /**
     * Get the current FileSystemService
     */
    getFileSystemService() {
        return this.fileSystemService;
    }
    /**
     * Set a custom FileSystemService
     */
    setFileSystemService(fileSystemService) {
        this.fileSystemService = fileSystemService;
    }
    getChatCompression() {
        return this.chatCompression;
    }
    addAlwaysAllowedCommand(rootCommand) {
        this.alwaysAllowedCommands.add(rootCommand);
    }
    isCommandAlwaysAllowed(rootCommand) {
        return this.alwaysAllowedCommands.has(rootCommand);
    }
    getAlwaysAllowedCommands() {
        return Array.from(this.alwaysAllowedCommands);
    }
    getShellReplacement() {
        // Check ephemeral setting first, fall back to constructor value
        const ephemeralValue = this.getEphemeralSetting('shell-replacement');
        if (ephemeralValue === true) {
            return true;
        }
        return this.shellReplacement;
    }
    getUseRipgrep() {
        return this.useRipgrep;
    }
    getShouldUseNodePtyShell() {
        return this.shouldUseNodePtyShell;
    }
    getSkipNextSpeakerCheck() {
        return this.skipNextSpeakerCheck;
    }
    getScreenReader() {
        return this.accessibility.screenReader ?? false;
    }
    getEnablePromptCompletion() {
        return this.enablePromptCompletion;
    }
    getUseSmartEdit() {
        return this.useSmartEdit;
    }
    getNonInteractive() {
        return !this.interactive;
    }
    async getGitService() {
        if (!this.gitService) {
            this.gitService = new GitService(this.targetDir, this.storage);
            await this.gitService.initialize();
        }
        return this.gitService;
    }
    /**
     * Get the SettingsService instance
     */
    getSettingsService() {
        return this.settingsService;
    }
    getFileExclusions() {
        return this.fileExclusions;
    }
    async refreshMemory() {
        const { memoryContent, fileCount, filePaths } = await loadServerHierarchicalMemory(this.getWorkingDir(), this.shouldLoadMemoryFromIncludeDirectories()
            ? this.getWorkspaceContext().getDirectories()
            : [], this.getDebugMode(), this.getFileService(), this.getExtensionContextFilePaths(), this.getFolderTrust());
        this.setUserMemory(memoryContent);
        this.setLlxprtMdFileCount(fileCount);
        this.setLlxprtMdFilePaths(filePaths);
        return { memoryContent, fileCount, filePaths };
    }
    async createToolRegistry() {
        const registry = new ToolRegistry(this, this.eventEmitter);
        const baseCoreTools = this.getCoreTools();
        const effectiveCoreTools = baseCoreTools && baseCoreTools.length > 0
            ? [...baseCoreTools]
            : undefined;
        const matchesToolIdentifier = (value, target) => value === target || value.startsWith(`${target}(`);
        const ensureCoreToolIncluded = (identifier) => {
            if (!effectiveCoreTools) {
                return;
            }
            if (!effectiveCoreTools.some((tool) => matchesToolIdentifier(tool, identifier))) {
                effectiveCoreTools.push(identifier);
            }
        };
        ensureCoreToolIncluded('TaskTool');
        ensureCoreToolIncluded(TaskTool.Name);
        ensureCoreToolIncluded('ListSubagentsTool');
        ensureCoreToolIncluded(ListSubagentsTool.Name);
        // 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 = effectiveCoreTools;
            const excludeTools = this.getExcludeTools() || [];
            let isEnabled = true; // Enabled by default if coreTools is not set.
            let reason;
            if (coreTools) {
                isEnabled = coreTools.some((tool) => tool === className ||
                    tool === toolName ||
                    tool.startsWith(`${className}(`) ||
                    tool.startsWith(`${toolName}(`));
            }
            const isExcluded = excludeTools.some((tool) => tool === className || tool === toolName);
            if (isExcluded) {
                isEnabled = false;
                reason = 'excluded by excludeTools setting';
            }
            // Record tool attempt for settings UI
            const toolRecord = {
                toolClass: ToolClass,
                toolName: className,
                displayName: toolName,
                isRegistered: false,
                reason,
                args,
            };
            if (isEnabled) {
                registry.registerTool(new ToolClass(...args));
                toolRecord.isRegistered = true;
                toolRecord.reason = undefined;
            }
            else if (!reason) {
                reason = 'not included in coreTools configuration';
                toolRecord.reason = reason;
            }
            this.allPotentialTools.push(toolRecord);
        };
        registerCoreTool(LSTool, this);
        registerCoreTool(ReadFileTool, this);
        if (this.getUseRipgrep()) {
            registerCoreTool(RipGrepTool, this);
        }
        else {
            registerCoreTool(GrepTool, this);
        }
        registerCoreTool(GlobTool, this);
        if (this.getUseSmartEdit()) {
            registerCoreTool(SmartEditTool, this);
        }
        else {
            registerCoreTool(EditTool, this);
        }
        registerCoreTool(WriteFileTool, this);
        registerCoreTool(GoogleWebFetchTool, this);
        registerCoreTool(ReadManyFilesTool, this);
        registerCoreTool(ReadLineRangeTool, this);
        registerCoreTool(DeleteLineRangeTool, this);
        registerCoreTool(InsertAtLineTool, this);
        registerCoreTool(ShellTool, this);
        registerCoreTool(MemoryTool, this);
        registerCoreTool(GoogleWebSearchTool, this);
        registerCoreTool(ExaWebSearchTool, this);
        registerCoreTool(TodoWrite);
        registerCoreTool(TodoRead);
        registerCoreTool(TodoPause);
        registerCoreTool(CodeSearchTool, this);
        registerCoreTool(DirectWebFetchTool, this);
        let profileManager = this.getProfileManager();
        if (!profileManager) {
            const profilesDir = path.join(os.homedir(), '.llxprt', 'profiles');
            profileManager = new ProfileManager(profilesDir);
            this.setProfileManager(profileManager);
        }
        let subagentManager = this.getSubagentManager();
        if (!subagentManager && profileManager) {
            const subagentsDir = path.join(os.homedir(), '.llxprt', 'subagents');
            subagentManager = new SubagentManager(subagentsDir, profileManager);
            this.setSubagentManager(subagentManager);
        }
        // Handle TaskTool with dependency checking
        const taskToolArgs = {
            profileManager,
            subagentManager,
            schedulerFactoryProvider: () => this.getInteractiveSubagentSchedulerFactory(),
        };
        if (profileManager && subagentManager) {
            registerCoreTool(TaskTool, this, taskToolArgs);
        }
        else {
            // Record TaskTool as unregistered due to missing dependencies
            const taskToolRecord = {
                toolClass: TaskTool,
                toolName: 'TaskTool',
                displayName: TaskTool.Name || 'TaskTool',
                isRegistered: false,
                reason: !profileManager && !subagentManager
                    ? 'requires profile manager and subagent manager'
                    : !profileManager
                        ? 'requires profile manager'
                        : 'requires subagent manager',
                args: [this, taskToolArgs],
            };
            this.allPotentialTools.push(taskToolRecord);
        }
        // Handle ListSubagentsTool with dependency checking
        const listSubagentsArgs = {
            getSubagentManager: () => this.getSubagentManager(),
        };
        if (subagentManager) {
            registerCoreTool(ListSubagentsTool, this, listSubagentsArgs);
        }
        else {
            // Record ListSubagentsTool as unregistered due to missing subagent manager
            const listSubagentsRecord = {
                toolClass: ListSubagentsTool,
                toolName: 'ListSubagentsTool',
                displayName: ListSubagentsTool.Name || 'ListSubagentsTool',
                isRegistered: false,
                reason: 'requires subagent manager',
                args: [this, listSubagentsArgs],
            };
            this.allPotentialTools.push(listSubagentsRecord);
        }
        await registry.discoverAllTools();
        return registry;
    }
    /**
     * Get all potential tools (both registered and unregistered) for settings UI
     */
    getAllPotentialTools() {
        return this.allPotentialTools;
    }
    /**
     * Get tool registry information with registered/unregistered separation
     */
    getToolRegistryInfo() {
        return {
            registered: this.allPotentialTools.filter((t) => t.isRegistered),
            unregistered: this.allPotentialTools.filter((t) => !t.isRegistered),
        };
    }
}
// Export model constants for use in CLI
export { DEFAULT_GEMINI_FLASH_MODEL };
//# sourceMappingURL=config.js.map