"use strict";
/**
 * CLIProxy Executor - Main Orchestrator
 *
 * Coordinates the full execution flow:
 * 1. Configuration resolution and validation
 * 2. Binary management and remote proxy checks
 * 3. Authentication and account management
 * 4. Proxy lifecycle (spawn/detect/join)
 * 5. Environment setup and proxy chains
 * 6. Claude CLI execution with cleanup handlers
 */
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.__testExports = exports._resolveRuntimeQuotaMonitorProviders = exports.filterCcsFlags = exports.CCS_FLAGS = exports.hasGitLabTokenLoginFlag = exports.readOptionValue = exports.findAvailablePort = exports.isPortAvailable = exports.execClaudeWithCLIProxy = void 0;
const fs = __importStar(require("fs"));
const ui_1 = require("../../utils/ui");
const config_generator_1 = require("../config/config-generator");
const model_config_1 = require("../config/model-config");
const model_catalog_1 = require("../model-catalog");
const websearch_manager_1 = require("../../utils/websearch-manager");
const image_analysis_1 = require("../../utils/image-analysis");
const config_loader_facade_1 = require("../../config/config-loader-facade");
const https_tunnel_proxy_1 = require("../proxy/https-tunnel-proxy");
const profile_continuity_inheritance_1 = require("../../auth/profile-continuity-inheritance");
// Import modular components
const browser_launch_setup_1 = require("./browser-launch-setup");
const account_resolution_1 = require("./account-resolution");
const lifecycle_manager_1 = require("./lifecycle-manager");
const env_resolver_1 = require("./env-resolver");
const session_bridge_1 = require("./session-bridge");
const websearch_manager_2 = require("../../utils/websearch-manager");
const auth_coordinator_1 = require("./auth-coordinator");
const thinking_override_resolver_1 = require("./thinking-override-resolver");
const https_tunnel_policy_1 = require("./https-tunnel-policy");
const arg_parser_1 = require("./arg-parser");
const proxy_resolver_1 = require("./proxy-resolver");
const proxy_chain_builder_1 = require("./proxy-chain-builder");
const model_warnings_1 = require("./model-warnings");
const claude_launcher_1 = require("./claude-launcher");
/** Local alias so internal call sites need no change */
const resolveRuntimeQuotaMonitorProviders = account_resolution_1.resolveRuntimeQuotaMonitorProviders;
/** Default executor configuration */
const DEFAULT_CONFIG = {
    port: config_generator_1.CLIPROXY_DEFAULT_PORT,
    timeout: 5000,
    verbose: false,
    pollInterval: 100,
};
// readOptionValue, hasGitLabTokenLoginFlag, CCS_FLAGS, filterCcsFlags are
// re-exported from ./arg-parser via the export block at the bottom of this file
// for backwards compatibility with external callers.
/**
 * Execute Claude CLI with CLIProxy (main entry point)
 *
 * @param claudeCli Path to Claude CLI executable
 * @param provider CLIProxy provider (gemini, codex, agy, qwen)
 * @param args Arguments to pass to Claude CLI
 * @param config Optional executor configuration
 */
async function execClaudeWithCLIProxy(claudeCli, provider, args, config = {}) {
    // Filter out undefined values to prevent overwriting defaults
    const filteredConfig = Object.fromEntries(Object.entries(config).filter(([, v]) => v !== undefined));
    const cfg = { ...DEFAULT_CONFIG, ...filteredConfig };
    const verbose = cfg.verbose || args.includes('--verbose') || args.includes('-v');
    // Validate Claude CLI exists before proceeding
    if (!fs.existsSync(claudeCli)) {
        console.error((0, ui_1.fail)(`Claude CLI not found at: ${claudeCli}`));
        console.error('    Run "ccs doctor --fix" to reinstall or check your PATH');
        process.exit(1);
    }
    const log = (msg) => {
        if (verbose) {
            console.error(`[cliproxy] ${msg}`);
        }
    };
    // Helper: Extract unique providers from composite tiers
    const compositeProviders = cfg.isComposite && cfg.compositeTiers
        ? [...new Set(Object.values(cfg.compositeTiers).map((t) => t.provider))]
        : [];
    // 0. Resolve proxy configuration (CLI > ENV > config.yaml > defaults)
    const unifiedConfig = (0, config_loader_facade_1.loadOrCreateUnifiedConfig)();
    // Collect all providers to validate (default + composite tiers)
    const allProviders = [provider, ...compositeProviders];
    const { proxyConfig, useRemoteProxy, localBackend, binaryPath, argsWithoutProxy } = await (0, proxy_resolver_1.resolveExecutorProxy)(args, {
        unifiedConfig,
        allProviders,
        verbose,
        cfg,
        log,
    });
    const { browserLaunchOverride, argsWithoutBrowserFlags } = (0, browser_launch_setup_1.resolveBrowserLaunchFlags)(argsWithoutProxy);
    // Setup first-class CCS WebSearch runtime
    (0, websearch_manager_1.ensureWebSearchMcpOrThrow)();
    const imageAnalysisMcpReady = (0, image_analysis_1.ensureImageAnalysisMcpOrThrow)();
    (0, websearch_manager_1.displayWebSearchStatus)();
    const providerConfig = (0, config_generator_1.getProviderConfig)(provider);
    log(`Provider: ${providerConfig.displayName}`);
    // Variables for local proxy mode
    let sessionId;
    // 2. Parse all CCS executor flags (extracted to arg-parser.ts)
    const parsedFlags = (0, arg_parser_1.parseExecutorFlags)(argsWithoutProxy, {
        provider,
        compositeProviders,
        unifiedConfig,
    });
    if (process.exitCode === 1)
        return;
    // Validate cross-flag combinations (exits with code 1 on violation)
    (0, arg_parser_1.validateFlagCombinations)(parsedFlags, { provider, compositeProviders }, argsWithoutProxy);
    if (process.exitCode === 1)
        return;
    const { forceConfig, addAccount, showAccounts, useAccount, setNickname, extendedContextOverride, thinkingParse, } = parsedFlags;
    const { thinkingOverride, thinkingSource } = (0, thinking_override_resolver_1.resolveRuntimeThinkingOverride)(thinkingParse.value, process.env.CCS_THINKING);
    const thinkingCfg = (0, config_loader_facade_1.getThinkingConfig)();
    if (thinkingParse.duplicateDisplays.length > 0) {
        console.warn(`[!] Multiple reasoning flags detected. Using first occurrence: ${thinkingParse.sourceDisplay}`);
    }
    if (thinkingParse.sourceFlag === '--effort' && provider !== 'codex') {
        console.warn((0, ui_1.warn)('`--effort` is primarily for codex. Continuing as alias of `--thinking` for compatibility.'));
    }
    // Handle --accounts / --use / --nickname (warnOAuthBanRisk emitted inside)
    await (0, account_resolution_1.resolveAccounts)({ provider, showAccounts, useAccount, setNickname, addAccount });
    // Handle --config
    if (forceConfig && (0, model_catalog_1.supportsModelConfig)(provider)) {
        // Block --config for composite variants (per-tier models in config.yaml)
        if (cfg.isComposite) {
            const variantName = cfg.profileName || provider;
            console.log((0, ui_1.warn)('Composite variants use per-tier config. Edit config.yaml to change tier models.'));
            console.error(`    Use "ccs cliproxy edit ${variantName}" to modify composite variants`);
            process.exit(1);
        }
        else {
            await (0, model_config_1.configureProviderModel)(provider, true, cfg.customSettingsPath);
            process.exit(0);
        }
    }
    // Build auth coordination context (used for logout/import/antigravity/oauth)
    const authCtx = {
        provider,
        compositeProviders,
        parsedFlags,
        cfg,
        unifiedConfig,
        verbose,
        log,
    };
    // Handle --logout (early exit)
    await (0, auth_coordinator_1.handleLogout)(authCtx);
    // Handle --import (early exit, Kiro only)
    await (0, auth_coordinator_1.handleImport)(authCtx);
    // 3. Ensure OAuth completed (if provider requires it)
    const remoteAuthToken = proxyConfig.authToken?.trim();
    const skipLocalAuth = (0, auth_coordinator_1.resolveSkipLocalAuth)(remoteAuthToken, useRemoteProxy);
    if (skipLocalAuth) {
        log(`Using remote proxy authentication (skipping local OAuth)`);
    }
    // Antigravity gate (runs before OAuth check)
    const { earlyReturn: agyEarlyReturn } = await (0, auth_coordinator_1.runAntigravityGate)(authCtx, skipLocalAuth);
    if (agyEarlyReturn)
        return;
    if (providerConfig.requiresOAuth && !skipLocalAuth) {
        await (0, auth_coordinator_1.ensureProviderAuthentication)(authCtx);
    }
    // 3b. Preflight quota check (providers with quota-based rotation)
    if (!skipLocalAuth) {
        await (0, auth_coordinator_1.runPreflightQuotaCheck)(provider, compositeProviders);
    }
    // 3c. Account safety: enforce cross-provider isolation
    if (!skipLocalAuth) {
        (0, auth_coordinator_1.runAccountSafetyGuards)(provider, compositeProviders);
    }
    // 4. First-run model configuration + codex plan reconcile
    if (!skipLocalAuth) {
        await (0, auth_coordinator_1.ensureModelConfiguration)(provider, cfg, verbose);
    }
    // 5. Check for broken models (multi-tier for composite)
    (0, model_warnings_1.warnBrokenModels)({ provider, cfg, compositeProviders, skipLocalAuth });
    // 6. Ensure user settings file exists
    (0, auth_coordinator_1.ensureProviderSettingsFile)(provider);
    // Local proxy mode: generate config, spawn/join proxy, track session
    let proxy = null;
    let configPath;
    if (!useRemoteProxy) {
        log(`Generating config for ${provider}`);
        configPath = (0, config_generator_1.generateConfig)(provider, cfg.port);
        log(`Config written: ${configPath}`);
        // 6a. Check or join existing proxy
        const { sessionId: existingSessionId, shouldSpawn } = await (0, session_bridge_1.checkOrJoinProxy)(cfg.port, cfg.timeout, verbose);
        sessionId = existingSessionId;
        // 6b. Spawn new proxy if needed
        if (shouldSpawn && binaryPath) {
            proxy = (0, lifecycle_manager_1.spawnProxy)(binaryPath, configPath, verbose);
            // 7. Wait for proxy readiness
            await (0, lifecycle_manager_1.waitForProxyReadyWithSpinner)(cfg.port, cfg.timeout, cfg.pollInterval, localBackend, configPath);
            // Register session
            if (proxy.pid) {
                sessionId = (0, session_bridge_1.registerProxySession)(cfg.port, proxy.pid, localBackend, verbose);
            }
        }
    }
    // 8. Setup HTTPS tunnel if needed (tunnelPort used by imageAnalysisProxyTarget below)
    let httpsTunnel = null;
    let tunnelPort = null;
    const useHttpsTunnel = (0, https_tunnel_policy_1.shouldStartHttpsTunnel)({
        provider,
        useRemoteProxy,
        protocol: proxyConfig.protocol,
        host: proxyConfig.host,
        isComposite: cfg.isComposite,
    });
    if (useHttpsTunnel && proxyConfig.host) {
        try {
            httpsTunnel = new https_tunnel_proxy_1.HttpsTunnelProxy({
                remoteHost: proxyConfig.host,
                remotePort: proxyConfig.port,
                authToken: proxyConfig.authToken,
                verbose,
                allowSelfSigned: proxyConfig.allowSelfSigned ?? false,
            });
            tunnelPort = await httpsTunnel.start();
            log(`HTTPS tunnel started on port ${tunnelPort} -> https://${proxyConfig.host}:${proxyConfig.port}`);
        }
        catch (error) {
            const err = error;
            console.error((0, ui_1.warn)(`Failed to start HTTPS tunnel: ${err.message}`));
            throw new Error(`HTTPS tunnel startup failed: ${err.message}`);
        }
    }
    else if (useRemoteProxy && proxyConfig.protocol === 'https' && provider === 'codex') {
        log('HTTPS tunnel skipped for Codex; local proxy chain will connect to remote HTTPS directly');
    }
    const imageAnalysisProxyTarget = useRemoteProxy && proxyConfig.host
        ? {
            host: proxyConfig.host,
            port: proxyConfig.port,
            protocol: proxyConfig.protocol,
            authToken: proxyConfig.authToken,
            managementKey: proxyConfig.managementKey,
            allowSelfSigned: proxyConfig.allowSelfSigned,
            isRemote: true,
        }
        : {
            host: '127.0.0.1',
            port: cfg.port,
            protocol: 'http',
            isRemote: false,
        };
    const imageAnalysisResolution = await (0, env_resolver_1.resolveCliproxyImageAnalysisEnv)({
        profileName: cfg.profileName || provider,
        provider,
        profileSettingsPath: cfg.customSettingsPath,
        isComposite: cfg.isComposite,
        proxyTarget: imageAnalysisProxyTarget,
        tunnelPort,
        proxyReachable: true,
    });
    const imageAnalysisProvisioningFailed = !imageAnalysisMcpReady && imageAnalysisResolution.env.CCS_IMAGE_ANALYSIS_ENABLED === '1';
    const imageAnalysisEnv = {
        ...imageAnalysisResolution.env,
        CCS_IMAGE_ANALYSIS_SKIP_HOOK: imageAnalysisMcpReady ? '1' : '0',
    };
    const imageAnalysisWarning = imageAnalysisProvisioningFailed
        ? 'ImageAnalysis MCP provisioning failed. This session will use compatibility fallback when available.'
        : imageAnalysisResolution.warning;
    // 9. Resolve config dir + browser runtime (needed before proxy chain)
    let toolSanitizationProxy = null;
    let toolSanitizationPort = null;
    let codexReasoningProxy = null;
    let codexReasoningPort = null;
    let inheritedClaudeConfigDir = cfg.claudeConfigDir;
    if (!inheritedClaudeConfigDir && cfg.profileName) {
        const continuityInheritance = await (0, profile_continuity_inheritance_1.resolveProfileContinuityInheritance)({
            profileName: cfg.profileName,
            profileType: 'cliproxy',
            target: 'claude',
        });
        inheritedClaudeConfigDir = continuityInheritance.claudeConfigDir;
        if (continuityInheritance.sourceAccount && process.env.CCS_DEBUG) {
            log(`Continuity inheritance active: profile "${cfg.profileName}" -> account "${continuityInheritance.sourceAccount}"`);
        }
    }
    (0, image_analysis_1.syncImageAnalysisMcpToConfigDir)(inheritedClaudeConfigDir);
    // Resolve browser attach runtime and sync browser MCP (needs inheritedClaudeConfigDir)
    const { browserRuntimeEnv } = await (0, browser_launch_setup_1.resolveBrowserRuntime)(browserLaunchOverride, inheritedClaudeConfigDir);
    // Build initial env vars to get ANTHROPIC_BASE_URL
    const initialEnvVars = (0, env_resolver_1.buildClaudeEnvironment)({
        provider,
        useRemoteProxy,
        remoteConfig: proxyConfig.host
            ? {
                host: proxyConfig.host,
                port: proxyConfig.port,
                protocol: proxyConfig.protocol,
                authToken: proxyConfig.authToken,
            }
            : undefined,
        httpsTunnel: httpsTunnel ?? undefined,
        tunnelPort: tunnelPort ?? undefined,
        localPort: cfg.port,
        customSettingsPath: cfg.customSettingsPath,
        thinkingOverride,
        extendedContextOverride,
        verbose,
        isComposite: cfg.isComposite,
        compositeTiers: cfg.compositeTiers,
        compositeDefaultTier: cfg.compositeDefaultTier,
        claudeConfigDir: inheritedClaudeConfigDir,
        imageAnalysisEnv,
    });
    // 9b. Build env-dependent proxy chain (tool-sanitization + codex-reasoning)
    ({ toolSanitizationProxy, toolSanitizationPort, codexReasoningProxy, codexReasoningPort } =
        await (0, proxy_chain_builder_1.buildProxyChain)({
            provider,
            useRemoteProxy,
            proxyConfig,
            cfg,
            initialEnvVars,
            thinkingOverride,
            thinkingCfg,
            verbose,
            log,
        }));
    // 11. Build final environment with all proxy chains
    const env = (0, env_resolver_1.buildClaudeEnvironment)({
        provider,
        useRemoteProxy,
        remoteConfig: proxyConfig.host
            ? {
                host: proxyConfig.host,
                port: proxyConfig.port,
                protocol: proxyConfig.protocol,
                authToken: proxyConfig.authToken,
            }
            : undefined,
        httpsTunnel: httpsTunnel ?? undefined,
        tunnelPort: tunnelPort ?? undefined,
        codexReasoningProxy: codexReasoningProxy ?? undefined,
        codexReasoningPort: codexReasoningPort ?? undefined,
        toolSanitizationProxy: toolSanitizationProxy ?? undefined,
        toolSanitizationPort: toolSanitizationPort ?? undefined,
        localPort: cfg.port,
        customSettingsPath: cfg.customSettingsPath,
        thinkingOverride,
        extendedContextOverride,
        verbose,
        isComposite: cfg.isComposite,
        compositeTiers: cfg.compositeTiers,
        compositeDefaultTier: cfg.compositeDefaultTier,
        claudeConfigDir: inheritedClaudeConfigDir,
        imageAnalysisEnv,
        browserRuntimeEnv,
    });
    if (cfg.isComposite && cfg.compositeTiers && cfg.compositeDefaultTier) {
        const mode = useRemoteProxy
            ? proxyConfig.protocol === 'https'
                ? 'remote-https'
                : 'remote-http'
            : 'local';
        const defaultTierProvider = cfg.compositeTiers[cfg.compositeDefaultTier]?.provider ?? provider;
        log(`Composite self-check: mode=${mode}, baseUrl=${env.ANTHROPIC_BASE_URL || 'unset'}, defaultTier=${cfg.compositeDefaultTier}, defaultProvider=${defaultTierProvider}`);
    }
    const webSearchEnv = (0, websearch_manager_2.getWebSearchHookEnv)();
    if (process.env.CCS_DEBUG) {
        console.error(`[cliproxy-browser-debug] keys=${Object.keys(env)
            .filter((key) => key.startsWith('CCS_BROWSER_'))
            .sort()
            .join(',')} ws=${env.CCS_BROWSER_DEVTOOLS_WS_URL || ''}`);
    }
    (0, env_resolver_1.logEnvironment)(env, webSearchEnv, verbose);
    if (imageAnalysisWarning) {
        console.error((0, ui_1.info)(imageAnalysisWarning));
    }
    // 11b. Print thinking status feedback (TTY only, non-piped sessions)
    if (process.stderr.isTTY) {
        const { thinkingLabel, sourceLabel } = (0, thinking_override_resolver_1.buildThinkingStartupStatus)(thinkingCfg, thinkingOverride, thinkingSource, thinkingParse.sourceDisplay);
        console.error(`[i] Thinking: ${thinkingLabel} (${sourceLabel})`);
    }
    // 12. Filter CCS flags, spawn Claude CLI, start quota monitor, wire cleanup
    const claudeArgs = (0, arg_parser_1.filterCcsFlags)(argsWithoutBrowserFlags);
    await (0, claude_launcher_1.launchClaude)({
        claudeCli,
        claudeArgs,
        env,
        cfg,
        provider,
        compositeProviders,
        skipLocalAuth,
        sessionId,
        imageAnalysisMcpReady,
        browserRuntimeEnv,
        inheritedClaudeConfigDir,
        codexReasoningProxy,
        toolSanitizationProxy,
        httpsTunnel,
        verbose,
    });
}
exports.execClaudeWithCLIProxy = execClaudeWithCLIProxy;
// Re-export utility functions for backwards compatibility
var lifecycle_manager_2 = require("./lifecycle-manager");
Object.defineProperty(exports, "isPortAvailable", { enumerable: true, get: function () { return lifecycle_manager_2.isPortAvailable; } });
Object.defineProperty(exports, "findAvailablePort", { enumerable: true, get: function () { return lifecycle_manager_2.findAvailablePort; } });
// Re-export arg-parser helpers (previously inlined here; external callers can
// import from index or directly from ./arg-parser)
var arg_parser_2 = require("./arg-parser");
Object.defineProperty(exports, "readOptionValue", { enumerable: true, get: function () { return arg_parser_2.readOptionValue; } });
Object.defineProperty(exports, "hasGitLabTokenLoginFlag", { enumerable: true, get: function () { return arg_parser_2.hasGitLabTokenLoginFlag; } });
Object.defineProperty(exports, "CCS_FLAGS", { enumerable: true, get: function () { return arg_parser_2.CCS_FLAGS; } });
Object.defineProperty(exports, "filterCcsFlags", { enumerable: true, get: function () { return arg_parser_2.filterCcsFlags; } });
// Re-export account-resolution helpers for backwards compat with __testExports consumers
var account_resolution_2 = require("./account-resolution");
Object.defineProperty(exports, "_resolveRuntimeQuotaMonitorProviders", { enumerable: true, get: function () { return account_resolution_2.resolveRuntimeQuotaMonitorProviders; } });
exports.__testExports = {
    resolveRuntimeQuotaMonitorProviders,
};
exports.default = execClaudeWithCLIProxy;
//# sourceMappingURL=index.js.map