"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.patchCodexConfig = exports.saveCodexRawConfig = exports.getCodexRawConfig = exports.getCodexDashboardDiagnostics = exports.summarizeCodexMcpServers = exports.summarizeCodexProjectTrust = exports.summarizeCodexFeatureFlags = exports.summarizeCodexModelProviders = exports.resolveCodexConfigPaths = exports.CodexRawConfigValidationError = exports.CodexRawConfigConflictError = void 0;
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const helpers_1 = require("../../utils/helpers");
const codex_detector_1 = require("../../targets/codex-detector");
const compatible_cli_toml_file_service_1 = require("./compatible-cli-toml-file-service");
Object.defineProperty(exports, "CodexRawConfigConflictError", { enumerable: true, get: function () { return compatible_cli_toml_file_service_1.TomlFileConflictError; } });
Object.defineProperty(exports, "CodexRawConfigValidationError", { enumerable: true, get: function () { return compatible_cli_toml_file_service_1.TomlFileValidationError; } });
const compatible_cli_docs_registry_1 = require("./compatible-cli-docs-registry");
const KNOWN_CODEX_FEATURES = new Set([
    'apps',
    'apply_patch_freeform',
    'codex_hooks',
    'fast_mode',
    'js_repl',
    'multi_agent',
    'personality',
    'prevent_idle_sleep',
    'runtime_metrics',
    'shell_snapshot',
    'shell_tool',
    'smart_approvals',
    'unified_exec',
    'undo',
    'web_search',
    'web_search_cached',
    'web_search_request',
]);
const MODEL_REASONING_EFFORT_VALUES = new Set(['minimal', 'low', 'medium', 'high', 'xhigh']);
const APPROVAL_POLICY_VALUES = new Set(['on-request', 'never', 'untrusted']);
const SANDBOX_MODE_VALUES = new Set(['read-only', 'workspace-write', 'danger-full-access']);
const WEB_SEARCH_VALUES = new Set(['cached', 'live', 'disabled']);
const PERSONALITY_VALUES = new Set(['none', 'friendly', 'pragmatic']);
const PROJECT_TRUST_LEVEL_VALUES = new Set(['trusted', 'untrusted']);
const BUILT_IN_CODEX_MODEL_PROVIDERS = new Set(['openai', 'oss']);
function isObject(value) {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function asObject(value) {
    return isObject(value) ? value : null;
}
function asString(value) {
    return typeof value === 'string' && value.trim().length > 0 ? value.trim() : null;
}
function asNumber(value) {
    return typeof value === 'number' && Number.isFinite(value) ? value : null;
}
function redactCodexProviderBaseUrl(baseUrl) {
    if (!baseUrl)
        return null;
    try {
        const parsed = new URL(baseUrl);
        const scheme = parsed.protocol.replace(/:$/, '') || 'url';
        return `[redacted:${scheme}]`;
    }
    catch {
        return '[redacted:url]';
    }
}
function redactCodexProviderEnvKey(name, envKey) {
    if (!envKey)
        return null;
    return isBuiltInCodexModelProvider(name) ? envKey : '[set]';
}
function redactCodexProjectPath(projectPath) {
    const normalized = projectPath.trim().replace(/[\\/]+$/, '');
    if (!normalized)
        return '[unknown]';
    const basename = normalized.split(/[\\/]/).filter(Boolean).pop();
    return basename || '[root]';
}
function hasOwn(obj, key) {
    return Object.prototype.hasOwnProperty.call(obj, key);
}
function isNonEmptyString(value) {
    return typeof value === 'string' && value.trim().length > 0;
}
function ensureObject(target, key) {
    const existing = asObject(target[key]);
    if (existing)
        return existing;
    const next = {};
    target[key] = next;
    return next;
}
function deleteIfEmpty(target, key) {
    const value = asObject(target[key]);
    if (value && Object.keys(value).length === 0) {
        delete target[key];
    }
}
function shouldPreserveUnsupportedValue(value) {
    return Array.isArray(value) || isObject(value);
}
function deleteFieldUnlessUnsupported(target, key) {
    if (shouldPreserveUnsupportedValue(target[key])) {
        return;
    }
    delete target[key];
}
function setStringField(target, key, value) {
    if (!isNonEmptyString(value)) {
        deleteFieldUnlessUnsupported(target, key);
        return;
    }
    target[key] = value.trim();
}
function setEnumStringField(target, key, value, allowedValues, label) {
    if (!isNonEmptyString(value)) {
        deleteFieldUnlessUnsupported(target, key);
        return;
    }
    const normalized = value.trim();
    if (!allowedValues.has(normalized)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError(`${label} must be one of: ${Array.from(allowedValues).join(', ')}.`);
    }
    target[key] = normalized;
}
function setBooleanField(target, key, value) {
    if (typeof value !== 'boolean') {
        deleteFieldUnlessUnsupported(target, key);
        return;
    }
    target[key] = value;
}
function setNumberField(target, key, value, options = {}) {
    if (typeof value !== 'number' || !Number.isFinite(value)) {
        deleteFieldUnlessUnsupported(target, key);
        return;
    }
    if (options.integer && !Number.isInteger(value)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError(`${key} must be an integer.`);
    }
    if (typeof options.min === 'number' && value < options.min) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError(`${key} must be >= ${options.min}.`);
    }
    target[key] = value;
}
function normalizeStringArray(value, label) {
    if (value === null || value === undefined)
        return null;
    if (!Array.isArray(value)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError(`${label} must be an array of strings.`);
    }
    const normalized = value
        .map((entry) => (typeof entry === 'string' ? entry.trim() : ''))
        .filter((entry) => entry.length > 0);
    return normalized.length > 0 ? normalized : [];
}
function assertPatchableToml(fileProbe) {
    if (fileProbe.diagnostics.readError) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError(fileProbe.diagnostics.readError);
    }
    if (fileProbe.diagnostics.parseError) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('config.toml contains invalid TOML. Fix the raw file before using guided controls.');
    }
    return asObject(fileProbe.config) ?? {};
}
function summarizeApprovalPolicy(value) {
    const stringValue = asString(value);
    if (stringValue) {
        return stringValue;
    }
    const objectValue = asObject(value);
    if (!objectValue) {
        return null;
    }
    if (hasOwn(objectValue, 'granular')) {
        return 'granular (custom)';
    }
    return 'custom object';
}
function applyTopLevelSettingsPatch(target, values) {
    if (hasOwn(values, 'model'))
        setStringField(target, 'model', values.model);
    if (hasOwn(values, 'modelReasoningEffort')) {
        setEnumStringField(target, 'model_reasoning_effort', values.modelReasoningEffort, MODEL_REASONING_EFFORT_VALUES, 'model_reasoning_effort');
    }
    if (hasOwn(values, 'modelContextWindow')) {
        setNumberField(target, 'model_context_window', values.modelContextWindow, {
            integer: true,
            min: 1,
        });
    }
    if (hasOwn(values, 'modelAutoCompactTokenLimit')) {
        setNumberField(target, 'model_auto_compact_token_limit', values.modelAutoCompactTokenLimit, {
            integer: true,
            min: 1,
        });
    }
    if (hasOwn(values, 'modelProvider')) {
        setStringField(target, 'model_provider', values.modelProvider);
    }
    if (hasOwn(values, 'approvalPolicy')) {
        setEnumStringField(target, 'approval_policy', values.approvalPolicy, APPROVAL_POLICY_VALUES, 'approval_policy');
    }
    if (hasOwn(values, 'sandboxMode')) {
        setEnumStringField(target, 'sandbox_mode', values.sandboxMode, SANDBOX_MODE_VALUES, 'sandbox_mode');
    }
    if (hasOwn(values, 'webSearch')) {
        setEnumStringField(target, 'web_search', values.webSearch, WEB_SEARCH_VALUES, 'web_search');
    }
    if (hasOwn(values, 'toolOutputTokenLimit')) {
        setNumberField(target, 'tool_output_token_limit', values.toolOutputTokenLimit, {
            integer: true,
            min: 1,
        });
    }
    if (hasOwn(values, 'personality')) {
        setEnumStringField(target, 'personality', values.personality, PERSONALITY_VALUES, 'personality');
    }
}
function applyProjectTrustPatch(target, input) {
    if (!isNonEmptyString(input.path)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Project path is required.');
    }
    const expandedPath = (0, helpers_1.expandPath)(input.path.trim());
    if (!path.isAbsolute(expandedPath)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Project path must be absolute or use ~/... expansion.');
    }
    const canonicalPath = path.resolve(expandedPath);
    const projects = ensureObject(target, 'projects');
    if (!isNonEmptyString(input.trustLevel)) {
        delete projects[canonicalPath];
        deleteIfEmpty(target, 'projects');
        return;
    }
    const trustLevel = input.trustLevel.trim();
    if (!PROJECT_TRUST_LEVEL_VALUES.has(trustLevel)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError(`trust_level must be one of: ${Array.from(PROJECT_TRUST_LEVEL_VALUES).join(', ')}.`);
    }
    projects[canonicalPath] = {
        ...(asObject(projects[canonicalPath]) ?? {}),
        trust_level: trustLevel,
    };
}
function applyFeaturePatch(target, input) {
    const feature = input.feature.trim();
    const currentFeatures = asObject(target.features);
    if (!feature ||
        (!KNOWN_CODEX_FEATURES.has(feature) && !(currentFeatures && hasOwn(currentFeatures, feature)))) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError(`Unsupported feature key "${input.feature}".`);
    }
    if (input.enabled !== null && typeof input.enabled !== 'boolean') {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Feature enabled must be boolean or null.');
    }
    const features = ensureObject(target, 'features');
    if (input.enabled === null) {
        delete features[feature];
    }
    else {
        features[feature] = input.enabled;
    }
    deleteIfEmpty(target, 'features');
}
function applyProfilePatch(target, input) {
    if (!isNonEmptyString(input.name)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Profile name is required.');
    }
    const profileName = input.name.trim();
    if (!['set-active', 'upsert', 'delete'].includes(input.action)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Unsupported profile action.');
    }
    if (input.action === 'set-active') {
        setStringField(target, 'profile', profileName);
        return;
    }
    const profiles = ensureObject(target, 'profiles');
    if (input.action === 'delete') {
        delete profiles[profileName];
        if (asString(target.profile) === profileName) {
            delete target.profile;
        }
        deleteIfEmpty(target, 'profiles');
        return;
    }
    const nextProfile = { ...(asObject(profiles[profileName]) ?? {}) };
    applyTopLevelSettingsPatch(nextProfile, input.values ?? {});
    if (Object.keys(nextProfile).length === 0) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Profile patch must include at least one saved field.');
    }
    profiles[profileName] = nextProfile;
    if (input.setAsActive === true) {
        target.profile = profileName;
    }
}
function applyModelProviderPatch(target, input) {
    if (!isNonEmptyString(input.name)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Model provider name is required.');
    }
    const providerName = input.name.trim();
    const providers = ensureObject(target, 'model_providers');
    if (!['upsert', 'delete'].includes(input.action)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Unsupported model provider action.');
    }
    if (input.action === 'delete') {
        delete providers[providerName];
        if (asString(target.model_provider) === providerName) {
            delete target.model_provider;
        }
        deleteIfEmpty(target, 'model_providers');
        return;
    }
    const values = input.values;
    if (!values) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Model provider values are required.');
    }
    const nextProvider = { ...(asObject(providers[providerName]) ?? {}) };
    if (hasOwn(values, 'displayName'))
        setStringField(nextProvider, 'name', values.displayName);
    if (hasOwn(values, 'baseUrl'))
        setStringField(nextProvider, 'base_url', values.baseUrl);
    if (hasOwn(values, 'envKey'))
        setStringField(nextProvider, 'env_key', values.envKey);
    if (hasOwn(values, 'wireApi')) {
        if (values.wireApi !== null && values.wireApi !== undefined && values.wireApi !== 'responses') {
            throw new compatible_cli_toml_file_service_1.TomlFileValidationError('wire_api must be "responses" for Codex model providers.');
        }
        setStringField(nextProvider, 'wire_api', values.wireApi);
    }
    if (hasOwn(values, 'requiresOpenaiAuth')) {
        setBooleanField(nextProvider, 'requires_openai_auth', values.requiresOpenaiAuth);
    }
    if (hasOwn(values, 'supportsWebsockets')) {
        setBooleanField(nextProvider, 'supports_websockets', values.supportsWebsockets);
    }
    if (Object.keys(nextProvider).length === 0) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Model provider patch must include at least one saved field.');
    }
    providers[providerName] = nextProvider;
}
function applyMcpServerPatch(target, input) {
    if (!isNonEmptyString(input.name)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('MCP server name is required.');
    }
    const serverName = input.name.trim();
    const servers = ensureObject(target, 'mcp_servers');
    if (!['upsert', 'delete'].includes(input.action)) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Unsupported MCP server action.');
    }
    if (input.action === 'delete') {
        delete servers[serverName];
        deleteIfEmpty(target, 'mcp_servers');
        return;
    }
    const values = input.values;
    if (!values) {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('MCP server values are required.');
    }
    if (values.transport !== 'stdio' && values.transport !== 'streamable-http') {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('MCP transport must be "stdio" or "streamable-http".');
    }
    const nextServer = { ...(asObject(servers[serverName]) ?? {}) };
    if (values.transport === 'stdio') {
        if (!isNonEmptyString(values.command)) {
            throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Stdio MCP servers require a command.');
        }
        nextServer.command = values.command.trim();
        const nextArgs = normalizeStringArray(values.args, 'args');
        if (nextArgs === null) {
            delete nextServer.args;
        }
        else {
            nextServer.args = nextArgs;
        }
        delete nextServer.url;
    }
    else {
        if (!isNonEmptyString(values.url)) {
            throw new compatible_cli_toml_file_service_1.TomlFileValidationError('HTTP MCP servers require a URL.');
        }
        nextServer.url = values.url.trim();
        delete nextServer.command;
        delete nextServer.args;
    }
    if (hasOwn(values, 'enabled'))
        setBooleanField(nextServer, 'enabled', values.enabled);
    if (hasOwn(values, 'required'))
        setBooleanField(nextServer, 'required', values.required);
    if (hasOwn(values, 'startupTimeoutSec')) {
        delete nextServer.startup_timeout_ms;
        setNumberField(nextServer, 'startup_timeout_sec', values.startupTimeoutSec, { min: 1 });
    }
    if (hasOwn(values, 'toolTimeoutSec')) {
        setNumberField(nextServer, 'tool_timeout_sec', values.toolTimeoutSec, { min: 1 });
    }
    if (hasOwn(values, 'enabledTools')) {
        const nextEnabledTools = normalizeStringArray(values.enabledTools, 'enabledTools');
        if (nextEnabledTools === null) {
            delete nextServer.enabled_tools;
        }
        else {
            nextServer.enabled_tools = nextEnabledTools;
        }
    }
    if (hasOwn(values, 'disabledTools')) {
        const nextDisabledTools = normalizeStringArray(values.disabledTools, 'disabledTools');
        if (nextDisabledTools === null) {
            delete nextServer.disabled_tools;
        }
        else {
            nextServer.disabled_tools = nextDisabledTools;
        }
    }
    servers[serverName] = nextServer;
}
function parseTransport(server) {
    if (asString(server.command))
        return 'stdio';
    if (asString(server.url))
        return 'streamable-http';
    return 'unknown';
}
function resolveCodexConfigPaths(options = {}) {
    const env = options.env ?? process.env;
    const homeDir = options.homeDir ?? os.homedir();
    const baseDir = path.resolve(env.CODEX_HOME ? (0, helpers_1.expandPath)(env.CODEX_HOME) : path.join(homeDir, '.codex'));
    const baseDirDisplay = env.CODEX_HOME ? '$CODEX_HOME' : '~/.codex';
    return {
        baseDir,
        baseDirDisplay,
        configPath: path.join(baseDir, 'config.toml'),
        configDisplayPath: `${baseDirDisplay}/config.toml`,
    };
}
exports.resolveCodexConfigPaths = resolveCodexConfigPaths;
function summarizeCodexModelProviders(value) {
    const providers = asObject(value);
    if (!providers)
        return [];
    return Object.entries(providers)
        .map(([name, providerValue]) => {
        const provider = asObject(providerValue);
        if (!provider)
            return null;
        return {
            name,
            baseUrl: redactCodexProviderBaseUrl(asString(provider.base_url)),
            envKey: redactCodexProviderEnvKey(name, asString(provider.env_key)),
            wireApi: asString(provider.wire_api),
            requiresOpenaiAuth: provider.requires_openai_auth === true,
            supportsWebsockets: provider.supports_websockets === true,
            hasQueryParams: isObject(provider.query_params) && Object.keys(provider.query_params).length > 0,
            hasHttpHeaders: (isObject(provider.http_headers) && Object.keys(provider.http_headers).length > 0) ||
                (isObject(provider.env_http_headers) &&
                    Object.keys(provider.env_http_headers).length > 0),
            usesExperimentalBearerToken: asString(provider.experimental_bearer_token) !== null,
        };
    })
        .filter((provider) => provider !== null)
        .sort((left, right) => left.name.localeCompare(right.name));
}
exports.summarizeCodexModelProviders = summarizeCodexModelProviders;
function isBuiltInCodexModelProvider(name) {
    return name !== null && BUILT_IN_CODEX_MODEL_PROVIDERS.has(name);
}
function summarizeCodexFeatureFlags(value) {
    const features = asObject(value);
    if (!features) {
        return { all: [], enabled: [], disabled: [] };
    }
    const all = Object.entries(features)
        .map(([name, rawValue]) => {
        const state = rawValue === true ? 'enabled' : rawValue === false ? 'disabled' : 'custom';
        return { name, state };
    })
        .sort((left, right) => left.name.localeCompare(right.name));
    return {
        all,
        enabled: all.filter((feature) => feature.state === 'enabled'),
        disabled: all.filter((feature) => feature.state === 'disabled'),
    };
}
exports.summarizeCodexFeatureFlags = summarizeCodexFeatureFlags;
function summarizeCodexProjectTrust(value) {
    const projects = asObject(value);
    if (!projects)
        return [];
    return Object.entries(projects)
        .map(([projectPath, projectValue]) => {
        const project = asObject(projectValue);
        const trustLevel = project ? asString(project.trust_level) : null;
        if (!trustLevel)
            return null;
        return {
            path: redactCodexProjectPath(projectPath),
            trustLevel,
        };
    })
        .filter((project) => project !== null)
        .sort((left, right) => left.path.localeCompare(right.path));
}
exports.summarizeCodexProjectTrust = summarizeCodexProjectTrust;
function summarizeCodexMcpServers(value) {
    const servers = asObject(value);
    if (!servers)
        return [];
    return Object.entries(servers)
        .map(([name, serverValue]) => {
        const server = asObject(serverValue);
        if (!server)
            return null;
        const startupTimeoutMs = asNumber(server.startup_timeout_ms);
        const startupTimeoutSec = asNumber(server.startup_timeout_sec) ??
            (startupTimeoutMs !== null ? startupTimeoutMs / 1000 : null);
        return {
            name,
            transport: parseTransport(server),
            enabled: server.enabled !== false,
            required: server.required === true,
            startupTimeoutSec,
            toolTimeoutSec: asNumber(server.tool_timeout_sec),
            enabledToolsCount: Array.isArray(server.enabled_tools) ? server.enabled_tools.length : 0,
            disabledToolsCount: Array.isArray(server.disabled_tools) ? server.disabled_tools.length : 0,
            usesInlineBearerToken: hasOwn(server, 'bearer_token'),
        };
    })
        .filter((server) => server !== null)
        .sort((left, right) => left.name.localeCompare(right.name));
}
exports.summarizeCodexMcpServers = summarizeCodexMcpServers;
function getCodexSupportMatrix(supportsManagedRouting) {
    return [
        {
            id: 'default',
            label: 'default',
            supported: true,
            notes: 'Uses the local Codex CLI with existing native auth and config.',
        },
        {
            id: 'cliproxy-provider-codex',
            label: 'cliproxy provider=codex',
            supported: supportsManagedRouting,
            notes: supportsManagedRouting
                ? 'Routed through the CLIProxy Codex Responses bridge.'
                : 'Requires a Codex build that exposes --config overrides.',
        },
        {
            id: 'settings-with-bridge',
            label: 'settings with bridge metadata',
            supported: supportsManagedRouting,
            notes: supportsManagedRouting
                ? 'Supported when the resolved API profile points at a Codex CLIProxy bridge.'
                : 'Requires a Codex build that exposes --config overrides.',
        },
        {
            id: 'cliproxy-composite',
            label: 'cliproxy composite',
            supported: false,
            notes: 'Not yet proven safe for native Codex routing in CCS v1.',
        },
        {
            id: 'settings-generic-api',
            label: 'settings generic API profile',
            supported: false,
            notes: 'Generic API profiles stay on Claude or Droid targets.',
        },
        {
            id: 'account',
            label: 'account',
            supported: false,
            notes: 'Account isolation remains a Claude-oriented concept.',
        },
        {
            id: 'copilot',
            label: 'copilot',
            supported: false,
            notes: 'GitHub Copilot flow is not a native Codex target path.',
        },
    ];
}
async function getCodexDashboardDiagnostics() {
    const paths = resolveCodexConfigPaths();
    const binaryInfo = (0, codex_detector_1.getCodexBinaryInfo)();
    const supportsConfigOverrides = !!binaryInfo && (0, codex_detector_1.codexBinarySupportsConfigOverrides)(binaryInfo);
    const docsReference = (0, compatible_cli_docs_registry_1.getCompatibleCliDocsReference)('codex');
    const fileProbe = await (0, compatible_cli_toml_file_service_1.probeTomlObjectFile)(paths.configPath, 'Codex user config', paths.configDisplayPath);
    const config = asObject(fileProbe.config);
    const topLevelKeys = config
        ? Object.keys(config).sort((left, right) => left.localeCompare(right))
        : [];
    const activeProfile = asString(config?.profile);
    const activeModelProvider = asString(config?.model_provider);
    const profileNames = Object.keys(asObject(config?.profiles) ?? {}).sort((left, right) => left.localeCompare(right));
    const modelProviders = summarizeCodexModelProviders(config?.model_providers);
    const features = summarizeCodexFeatureFlags(config?.features);
    const projectTrust = summarizeCodexProjectTrust(config?.projects);
    const mcpServers = summarizeCodexMcpServers(config?.mcp_servers);
    const supportMatrix = getCodexSupportMatrix(supportsConfigOverrides);
    const warnings = [];
    if (!binaryInfo) {
        warnings.push('Codex binary is not detected in PATH or CCS_CODEX_PATH.');
    }
    else if (!supportsConfigOverrides) {
        warnings.push('This Codex build does not expose --config overrides required for CCS-backed Codex routing.');
    }
    if (fileProbe.diagnostics.parseError) {
        warnings.push(`${paths.configDisplayPath} contains invalid TOML.`);
    }
    if (activeProfile && !profileNames.includes(activeProfile)) {
        warnings.push(`Active profile "${activeProfile}" is selected but missing from [profiles].`);
    }
    if (activeModelProvider) {
        const activeProvider = modelProviders.find((provider) => provider.name === activeModelProvider);
        if (!activeProvider && !isBuiltInCodexModelProvider(activeModelProvider)) {
            warnings.push(`Active model provider "${activeModelProvider}" is selected but missing from [model_providers].`);
        }
        else if (activeProvider) {
            if (!activeProvider.baseUrl) {
                warnings.push(`Active model provider "${activeProvider.name}" is missing base_url.`);
            }
            if (!activeProvider.envKey && !activeProvider.requiresOpenaiAuth) {
                warnings.push(`Active model provider "${activeProvider.name}" is missing env_key.`);
            }
        }
    }
    if (modelProviders.some((provider) => provider.usesExperimentalBearerToken)) {
        warnings.push('One or more model_providers entries use experimental_bearer_token; prefer env_key-backed auth.');
    }
    if (mcpServers.some((server) => server.usesInlineBearerToken)) {
        warnings.push('One or more mcp_servers entries include inline bearer_token; prefer bearer_token_env_var.');
    }
    return {
        binary: {
            installed: !!binaryInfo,
            path: binaryInfo?.path ?? null,
            installDir: binaryInfo?.path ? path.dirname(binaryInfo.path) : null,
            source: process.env.CCS_CODEX_PATH ? 'CCS_CODEX_PATH' : binaryInfo ? 'PATH' : 'missing',
            version: binaryInfo?.version ?? null,
            overridePath: process.env.CCS_CODEX_PATH || null,
            supportsConfigOverrides,
        },
        file: fileProbe.diagnostics,
        workspacePath: process.cwd(),
        config: {
            model: asString(config?.model),
            modelReasoningEffort: asString(config?.model_reasoning_effort),
            modelContextWindow: asNumber(config?.model_context_window),
            modelAutoCompactTokenLimit: asNumber(config?.model_auto_compact_token_limit),
            modelProvider: asString(config?.model_provider),
            activeProfile,
            approvalPolicy: summarizeApprovalPolicy(config?.approval_policy),
            sandboxMode: asString(config?.sandbox_mode),
            webSearch: asString(config?.web_search),
            toolOutputTokenLimit: asNumber(config?.tool_output_token_limit),
            personality: asString(config?.personality),
            topLevelKeys,
            profileCount: profileNames.length,
            profileNames,
            modelProviderCount: modelProviders.length,
            modelProviders,
            featureCount: features.all.length,
            enabledFeatures: features.enabled,
            disabledFeatures: features.disabled,
            trustedProjectCount: projectTrust.filter((entry) => entry.trustLevel === 'trusted').length,
            untrustedProjectCount: projectTrust.filter((entry) => entry.trustLevel !== 'trusted').length,
            projectTrust,
            mcpServerCount: mcpServers.length,
            mcpServers,
        },
        supportMatrix,
        warnings,
        docsReference,
    };
}
exports.getCodexDashboardDiagnostics = getCodexDashboardDiagnostics;
async function getCodexRawConfig() {
    const paths = resolveCodexConfigPaths();
    const fileProbe = await (0, compatible_cli_toml_file_service_1.probeTomlObjectFile)(paths.configPath, 'Codex user config', paths.configDisplayPath);
    return {
        path: paths.configDisplayPath,
        resolvedPath: paths.configPath,
        exists: fileProbe.diagnostics.exists,
        mtime: fileProbe.diagnostics.mtimeMs ?? Date.now(),
        rawText: fileProbe.rawText,
        config: fileProbe.config,
        parseError: fileProbe.diagnostics.parseError,
        readError: fileProbe.diagnostics.readError,
    };
}
exports.getCodexRawConfig = getCodexRawConfig;
async function saveCodexRawConfig(input) {
    const paths = resolveCodexConfigPaths();
    if (typeof input.rawText !== 'string') {
        throw new compatible_cli_toml_file_service_1.TomlFileValidationError('rawText must be a string.');
    }
    const saved = await (0, compatible_cli_toml_file_service_1.writeTomlFileAtomic)({
        filePath: paths.configPath,
        rawText: input.rawText,
        expectedMtime: input.expectedMtime,
        fileLabel: 'config.toml',
    });
    return { success: true, mtime: saved.mtime };
}
exports.saveCodexRawConfig = saveCodexRawConfig;
async function patchCodexConfig(input) {
    const paths = resolveCodexConfigPaths();
    const fileProbe = await (0, compatible_cli_toml_file_service_1.probeTomlObjectFile)(paths.configPath, 'Codex user config', paths.configDisplayPath);
    const nextConfig = { ...assertPatchableToml(fileProbe) };
    switch (input.kind) {
        case 'top-level':
            applyTopLevelSettingsPatch(nextConfig, input.values);
            break;
        case 'project-trust':
            applyProjectTrustPatch(nextConfig, input);
            break;
        case 'feature':
            applyFeaturePatch(nextConfig, input);
            break;
        case 'profile':
            applyProfilePatch(nextConfig, input);
            break;
        case 'model-provider':
            applyModelProviderPatch(nextConfig, input);
            break;
        case 'mcp-server':
            applyMcpServerPatch(nextConfig, input);
            break;
        default:
            throw new compatible_cli_toml_file_service_1.TomlFileValidationError('Unsupported Codex config patch.');
    }
    const rawText = (0, compatible_cli_toml_file_service_1.stringifyTomlObject)(nextConfig);
    const saved = await (0, compatible_cli_toml_file_service_1.writeTomlFileAtomic)({
        filePath: paths.configPath,
        rawText,
        expectedMtime: input.expectedMtime ?? fileProbe.diagnostics.mtimeMs ?? undefined,
        fileLabel: 'config.toml',
    });
    return {
        success: true,
        path: paths.configDisplayPath,
        resolvedPath: paths.configPath,
        exists: true,
        mtime: saved.mtime,
        rawText,
        config: nextConfig,
        parseError: null,
        readError: null,
    };
}
exports.patchCodexConfig = patchCodexConfig;
//# sourceMappingURL=codex-dashboard-service.js.map