"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.CodexAdapter = void 0;
const child_process_1 = require("child_process");
const fs = __importStar(require("fs"));
const errors_1 = require("../errors");
const helpers_1 = require("../utils/helpers");
const signal_forwarder_1 = require("../utils/signal-forwarder");
const shell_executor_1 = require("../utils/shell-executor");
const codex_detector_1 = require("./codex-detector");
const logging_1 = require("../services/logging");
const auth_token_manager_1 = require("../cliproxy/auth/auth-token-manager");
const port_manager_1 = require("../cliproxy/config/port-manager");
const model_catalog_1 = require("../cliproxy/model-catalog");
const model_id_normalizer_1 = require("../cliproxy/ai-providers/model-id-normalizer");
const codex_cliproxy_provider_config_1 = require("./codex-cliproxy-provider-config");
const adapterLogger = (0, logging_1.createLogger)('targets:codex');
const CODEX_RUNTIME_PROVIDER_ID = 'ccs_runtime';
const CODEX_RUNTIME_ENV_KEY = 'CCS_CODEX_API_KEY';
const CODEX_REASONING_LEVELS = new Set(['minimal', 'low', 'medium', 'high', 'xhigh']);
const CODEX_INFO_FLAGS = new Set(['--help', '-h', '--version', '-v']);
const CODEX_FAST_SERVICE_TIER = 'priority';
function formatTomlString(value) {
    return JSON.stringify(value);
}
function buildConfigOverrideArgs(overrides) {
    return overrides.flatMap((override) => ['-c', override]);
}
function buildConfigOverrideSupportError(binaryInfo) {
    const versionSummary = binaryInfo?.version ? ` (${binaryInfo.version})` : '';
    return new Error(`Codex CLI${versionSummary} does not advertise --config overrides. Upgrade Codex before using CCS-backed Codex profiles or runtime reasoning overrides.`);
}
function hydrateCodexBinaryVersion(binaryInfo) {
    if (!binaryInfo || binaryInfo.version || !binaryInfo.path) {
        return binaryInfo;
    }
    return {
        ...binaryInfo,
        version: (0, codex_detector_1.readCodexVersion)(binaryInfo.path),
    };
}
function findDisallowedCodexManagedFlags(args) {
    const disallowed = new Set();
    for (const arg of args) {
        if (arg === '-c' || arg === '--config' || arg.startsWith('--config=')) {
            disallowed.add('--config/-c');
            continue;
        }
        if (arg === '-p' || arg === '--profile' || arg.startsWith('--profile=')) {
            disallowed.add('--profile/-p');
            continue;
        }
        if (arg === '--oss') {
            disallowed.add('--oss');
            continue;
        }
        if (arg === '--local-provider' || arg.startsWith('--local-provider=')) {
            disallowed.add('--local-provider');
        }
    }
    return [...disallowed];
}
function normalizeCodexReasoningOverride(value) {
    if (value === undefined) {
        return undefined;
    }
    if (typeof value === 'string' && CODEX_REASONING_LEVELS.has(value)) {
        return value;
    }
    throw new Error('Codex target supports reasoning levels only: minimal, low, medium, high, xhigh.');
}
function normalizeCodexModelFlagValue(value) {
    const parsed = (0, model_id_normalizer_1.parseCodexModelTuningAlias)(value);
    if (!parsed || !parsed.baseModel)
        return null;
    if ((0, model_catalog_1.getModelMaxLevel)('codex', parsed.baseModel) === undefined)
        return null;
    return {
        model: parsed.baseModel,
        effort: parsed.effort ?? undefined,
        serviceTier: parsed.serviceTier ? CODEX_FAST_SERVICE_TIER : undefined,
    };
}
function normalizeCcsxpCodexModelFlagAliases(args) {
    const normalizedArgs = [...args];
    let reasoningEffort;
    let serviceTier;
    const applyModelValue = (value) => {
        const normalized = normalizeCodexModelFlagValue(value);
        if (!normalized) {
            reasoningEffort = undefined;
            serviceTier = undefined;
            return value;
        }
        reasoningEffort = normalized.effort;
        serviceTier = normalized.serviceTier;
        return normalized.model;
    };
    for (let index = 0; index < normalizedArgs.length; index += 1) {
        const arg = normalizedArgs[index];
        if (arg === '-m' || arg === '--model') {
            const nextValue = normalizedArgs[index + 1];
            if (typeof nextValue === 'string') {
                normalizedArgs[index + 1] = applyModelValue(nextValue);
                index += 1;
            }
            continue;
        }
        for (const prefix of ['--model=', '-m=']) {
            if (arg.startsWith(prefix)) {
                normalizedArgs[index] = `${prefix}${applyModelValue(arg.slice(prefix.length))}`;
                break;
            }
        }
    }
    const overrides = [];
    if (reasoningEffort) {
        overrides.push(`model_reasoning_effort=${formatTomlString(reasoningEffort)}`);
    }
    if (serviceTier) {
        overrides.push(`service_tier=${formatTomlString(serviceTier)}`);
    }
    return { args: normalizedArgs, overrides };
}
function isInformationalCodexInvocation(args) {
    if (args.length === 1) {
        return CODEX_INFO_FLAGS.has(args[0] || '');
    }
    if (args.length === 2) {
        return CODEX_INFO_FLAGS.has(args[1] || '');
    }
    return false;
}
function normalizeExplicitCodexHomeEnv(env) {
    const rawCodexHome = env.CODEX_HOME;
    if (rawCodexHome === undefined) {
        return env;
    }
    const trimmedCodexHome = rawCodexHome.trim();
    if (!trimmedCodexHome) {
        const nextEnv = { ...env };
        delete nextEnv.CODEX_HOME;
        return nextEnv;
    }
    const normalizedCodexHome = (0, helpers_1.expandPath)(trimmedCodexHome);
    if (normalizedCodexHome === rawCodexHome) {
        return env;
    }
    return {
        ...env,
        CODEX_HOME: normalizedCodexHome,
    };
}
function prepareExplicitCodexHome(env, args) {
    const normalizedEnv = normalizeExplicitCodexHomeEnv(env);
    const codexHome = normalizedEnv.CODEX_HOME;
    if (!codexHome) {
        return { env: normalizedEnv };
    }
    if (isInformationalCodexInvocation(args)) {
        return { env: normalizedEnv };
    }
    try {
        fs.mkdirSync(codexHome, { recursive: true });
    }
    catch (err) {
        const error = err;
        if (error.code !== 'EEXIST') {
            return {
                env: normalizedEnv,
                error: `[X] Unable to initialize CODEX_HOME (${error.code || 'unknown'}): ${codexHome}`,
            };
        }
    }
    try {
        if (!fs.statSync(codexHome).isDirectory()) {
            return {
                env: normalizedEnv,
                error: `[X] CODEX_HOME path is not a directory: ${codexHome}`,
            };
        }
        return { env: normalizedEnv };
    }
    catch (err) {
        const error = err;
        return {
            env: normalizedEnv,
            error: `[X] Unable to access CODEX_HOME (${error.code || 'unknown'}): ${codexHome}`,
        };
    }
}
class CodexAdapter {
    constructor() {
        this.type = 'codex';
        this.displayName = 'Codex CLI';
        this.ccsxpCliproxyEnvKey = codex_cliproxy_provider_config_1.CODEX_CLIPROXY_PROVIDER_ENV_KEY;
    }
    detectBinary() {
        return (0, codex_detector_1.getCodexBinaryInfo)({ includeVersion: false, includeFeatures: false });
    }
    async prepareCredentials(_creds) {
        if (!(0, codex_cliproxy_provider_config_1.isCcsxpCliproxyShortcut)()) {
            return;
        }
        try {
            const providerRepair = await (0, codex_cliproxy_provider_config_1.ensureCodexCliproxyProviderConfig)((0, port_manager_1.resolveLifecyclePort)());
            this.ccsxpCliproxyEnvKey = providerRepair.envKey;
        }
        catch (error) {
            throw new Error(`ccsxp could not repair the native Codex cliproxy provider: ${error.message}`);
        }
    }
    buildArgs(_profile, userArgs, options) {
        const profileType = options?.profileType || 'default';
        const creds = options?.creds;
        const reasoningOverride = normalizeCodexReasoningOverride(creds?.reasoningOverride);
        const runtimeConfigOverrides = creds?.runtimeConfigOverrides ?? [];
        if (profileType === 'default') {
            const modelFlagNormalization = (0, codex_cliproxy_provider_config_1.isCcsxpCliproxyShortcut)()
                ? normalizeCcsxpCodexModelFlagAliases(userArgs)
                : { args: userArgs, overrides: [] };
            const overrides = [...runtimeConfigOverrides, ...modelFlagNormalization.overrides];
            if (reasoningOverride) {
                overrides.push(`model_reasoning_effort=${formatTomlString(reasoningOverride)}`);
            }
            if (overrides.length === 0) {
                return modelFlagNormalization.args;
            }
            if (!(0, codex_detector_1.codexBinarySupportsConfigOverrides)(options?.binaryInfo)) {
                if (reasoningOverride || modelFlagNormalization.overrides.length > 0) {
                    throw buildConfigOverrideSupportError(hydrateCodexBinaryVersion(options?.binaryInfo));
                }
                return modelFlagNormalization.args;
            }
            return [...buildConfigOverrideArgs(overrides), ...modelFlagNormalization.args];
        }
        if (!(0, codex_detector_1.codexBinarySupportsConfigOverrides)(options?.binaryInfo)) {
            throw buildConfigOverrideSupportError(hydrateCodexBinaryVersion(options?.binaryInfo));
        }
        if (!creds?.baseUrl?.trim() || !creds.apiKey?.trim()) {
            throw new Error('Codex target requires base URL and API key for CCS-backed profile launches.');
        }
        const disallowedFlags = findDisallowedCodexManagedFlags(userArgs);
        if (disallowedFlags.length > 0) {
            throw new Error(`Codex target does not allow ${disallowedFlags.join(', ')} when CCS manages the runtime provider. Remove native Codex provider selection flags and retry.`);
        }
        const overrides = [
            `model_provider=${formatTomlString(CODEX_RUNTIME_PROVIDER_ID)}`,
            `model_providers.${CODEX_RUNTIME_PROVIDER_ID}.name=${formatTomlString('CCS Runtime')}`,
            `model_providers.${CODEX_RUNTIME_PROVIDER_ID}.base_url=${formatTomlString(creds.baseUrl)}`,
            `model_providers.${CODEX_RUNTIME_PROVIDER_ID}.env_key=${formatTomlString(CODEX_RUNTIME_ENV_KEY)}`,
            `model_providers.${CODEX_RUNTIME_PROVIDER_ID}.wire_api=${formatTomlString('responses')}`,
        ];
        if (creds.model?.trim()) {
            overrides.push(`model=${formatTomlString(creds.model)}`);
        }
        overrides.push(...runtimeConfigOverrides);
        if (reasoningOverride) {
            overrides.push(`model_reasoning_effort=${formatTomlString(reasoningOverride)}`);
        }
        return [...buildConfigOverrideArgs(overrides), ...userArgs];
    }
    buildEnv(creds, profileType) {
        const env = {
            ...(0, shell_executor_1.stripBrowserEnv)((0, shell_executor_1.stripCodexSessionEnv)((0, shell_executor_1.stripAnthropicEnv)(process.env))),
        };
        delete env[codex_cliproxy_provider_config_1.CCSXP_CLIPROXY_SHORTCUT_ENV];
        delete env[CODEX_RUNTIME_ENV_KEY];
        if (profileType === 'default' && (0, codex_cliproxy_provider_config_1.isCcsxpCliproxyShortcut)()) {
            env[this.ccsxpCliproxyEnvKey || codex_cliproxy_provider_config_1.CODEX_CLIPROXY_PROVIDER_ENV_KEY] = (0, auth_token_manager_1.getEffectiveApiKey)();
        }
        if (profileType !== 'default') {
            if (!creds.apiKey?.trim()) {
                throw new Error('Codex target requires an API key for CCS-backed profile launches.');
            }
            env[CODEX_RUNTIME_ENV_KEY] = creds.apiKey;
        }
        return env;
    }
    exec(args, env, options) {
        const exitWithCleanup = (code) => {
            try {
                (0, errors_1.runCleanup)();
            }
            catch {
                // Cleanup is best-effort on launch errors.
            }
            process.exit(code);
        };
        const codexPath = options?.binaryInfo?.path || (0, codex_detector_1.detectCodexCli)();
        if (!codexPath) {
            console.error('[X] Codex CLI not found. Install a recent @openai/codex build first.');
            return exitWithCleanup(1);
        }
        try {
            const stat = fs.statSync(codexPath);
            if (!stat.isFile()) {
                console.error(`[X] Codex CLI path is not a file: ${codexPath}`);
                return exitWithCleanup(1);
            }
        }
        catch (err) {
            const error = err;
            console.error(`[X] Codex CLI path is not accessible (${error.code || 'unknown'}): ${codexPath}`);
            return exitWithCleanup(1);
        }
        const codexHomePreparation = prepareExplicitCodexHome(env, args);
        if (codexHomePreparation.error) {
            console.error(codexHomePreparation.error);
            return exitWithCleanup(1);
        }
        const launchEnv = codexHomePreparation.env;
        const isWindows = process.platform === 'win32';
        const isPowerShellScript = isWindows && /\.ps1$/i.test(codexPath);
        const needsShell = isWindows && /\.(cmd|bat)$/i.test(codexPath);
        const spawnStartedAt = Date.now();
        adapterLogger.stage('dispatch', 'target.spawn', 'Spawning Codex CLI child process', {
            target: 'codex',
            codexPath,
            argCount: args.length,
        });
        let child;
        if (isPowerShellScript) {
            child = (0, child_process_1.spawn)('powershell.exe', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', codexPath, ...args], { stdio: 'inherit', windowsHide: true, env: launchEnv });
        }
        else if (needsShell) {
            const cmdString = [codexPath, ...args].map(shell_executor_1.escapeShellArg).join(' ');
            child = (0, child_process_1.spawn)(cmdString, {
                stdio: 'inherit',
                windowsHide: true,
                shell: (0, shell_executor_1.getWindowsEscapedCommandShell)(),
                env: launchEnv,
            });
        }
        else {
            child = (0, child_process_1.spawn)(codexPath, args, { stdio: 'inherit', windowsHide: true, env: launchEnv });
        }
        child.on('exit', (code, signal) => {
            adapterLogger.stage('respond', 'target.exit', 'Codex CLI child process exited', { target: 'codex', exitCode: code, signal }, { latencyMs: Date.now() - spawnStartedAt });
        });
        (0, signal_forwarder_1.wireChildProcessSignals)(child, (err) => {
            if (err.code === 'EACCES') {
                console.error(`[X] Codex CLI is not executable: ${codexPath}`);
                console.error('    Check file permissions and executable bit.');
            }
            else if (err.code === 'ENOENT') {
                if (isPowerShellScript) {
                    console.error('[X] PowerShell executable not found (required for .ps1 wrapper launch).');
                }
                else if (needsShell) {
                    console.error('[X] Windows command shell not found for Codex wrapper launch.');
                }
                else {
                    console.error(`[X] Codex CLI not found: ${codexPath}`);
                }
            }
            else {
                console.error(`[X] Failed to start Codex CLI (${codexPath}): ${err.message}`);
            }
            return exitWithCleanup(1);
        });
    }
    supportsProfileType(profileType) {
        // Bridge-backed settings profiles need additional compatibility context that the
        // adapter contract does not receive, so keep the adapter-level claim conservative.
        return profileType === 'default' || profileType === 'cliproxy';
    }
}
exports.CodexAdapter = CodexAdapter;
//# sourceMappingURL=codex-adapter.js.map