"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
    return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var m = o[Symbol.asyncIterator], i;
    return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
    function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
    function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var __read = (this && this.__read) || function (o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
        try {
            if (r && !r.done && (m = i["return"])) m.call(i);
        }
        finally { if (e) throw e.error; }
    }
    return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CodexClient = void 0;
var fs_1 = require("fs");
var os = require("os");
var path = require("path");
var promises_1 = require("timers/promises");
var CodexClient = /** @class */ (function () {
    function CodexClient(config) {
        this.codex = null;
        this.codexInit = null;
        this.threadCache = new Map();
        this.debugEnabled = (process.env.AI_DASHBOARD_DEBUG || '').trim().toLowerCase() === 'true';
        this.streamEnabled = this.resolveStreamEnabled();
        this.cleanZdotdirEnabled = this.resolveCleanZdotdirEnabled();
        this.zDotDir = null;
        this.defaultTimeoutMs = this.resolveDefaultTimeoutMs();
        this.pingEnabled = this.resolvePingEnabled();
        this.pingTimeoutMs = this.resolvePingTimeoutMs();
        this.modelUnavailableTtlMs = this.resolveModelUnavailableTtlMs();
        this.config = config;
        if (!this.config.apiKey) {
            throw new Error('AI API key is required for AI client');
        }
        this.defaultThreadOptions = this.resolveDefaultThreadOptions();
    }
    CodexClient.prototype.run = function (prompt, options) {
        return __awaiter(this, void 0, void 0, function () {
            var maxRetries, retryDelayMs, lastError, modelSequence, _loop_1, this_1, modelIndex, state_1;
            var _this = this;
            var _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0: return [4 /*yield*/, this.ensureModelFallbackPreferencesLoaded()];
                    case 1:
                        _b.sent();
                        maxRetries = this.normalizeRetryCount((_a = options === null || options === void 0 ? void 0 : options.maxRetries) !== null && _a !== void 0 ? _a : this.config.maxRetries);
                        retryDelayMs = this.normalizeRetryDelay(this.config.retryDelayMs);
                        lastError = null;
                        modelSequence = this.resolveModelSequence(options);
                        _loop_1 = function (modelIndex) {
                            var model, nextModel, modelOptions, processCwdFallbackApplied, attempt, _loop_2, state_2;
                            return __generator(this, function (_c) {
                                switch (_c.label) {
                                    case 0:
                                        model = modelSequence[modelIndex];
                                        nextModel = modelSequence[modelIndex + 1];
                                        modelOptions = this_1.applyModelOverride(options, model);
                                        processCwdFallbackApplied = false;
                                        attempt = 0;
                                        _loop_2 = function () {
                                            var result_1, result, error_1, message, workingDirectory, fallbackOptions_1, _d, delay;
                                            return __generator(this, function (_e) {
                                                switch (_e.label) {
                                                    case 0:
                                                        _e.trys.push([0, 8, , 14]);
                                                        this_1.log("run model=".concat(model || this_1.config.model || 'default', " attempt ").concat(attempt + 1, "/").concat(maxRetries + 1));
                                                        if (!(this_1.pingEnabled && !this_1.isPingPrompt(prompt))) return [3 /*break*/, 2];
                                                        return [4 /*yield*/, this_1.runPing(modelOptions === null || modelOptions === void 0 ? void 0 : modelOptions.threadOptions)];
                                                    case 1:
                                                        _e.sent();
                                                        _e.label = 2;
                                                    case 2:
                                                        if (!(this_1.streamEnabled && !this_1.isPingPrompt(prompt))) return [3 /*break*/, 5];
                                                        return [4 /*yield*/, this_1.runStreamedOnce(prompt, modelOptions)];
                                                    case 3:
                                                        result_1 = _e.sent();
                                                        return [4 /*yield*/, this_1.clearModelFallbackPreference(model)];
                                                    case 4:
                                                        _e.sent();
                                                        return [2 /*return*/, { value: result_1 }];
                                                    case 5: return [4 /*yield*/, this_1.runOnce(prompt, modelOptions)];
                                                    case 6:
                                                        result = _e.sent();
                                                        return [4 /*yield*/, this_1.clearModelFallbackPreference(model)];
                                                    case 7:
                                                        _e.sent();
                                                        return [2 /*return*/, { value: result }];
                                                    case 8:
                                                        error_1 = _e.sent();
                                                        lastError = error_1;
                                                        message = error_1 instanceof Error ? error_1.message : String(error_1 || 'Unknown error');
                                                        this_1.log("run model=".concat(model || this_1.config.model || 'default', " attempt ").concat(attempt + 1, " failed: ").concat(message));
                                                        if (!(!processCwdFallbackApplied && this_1.shouldApplyProcessCwdFallback(error_1, modelOptions))) return [3 /*break*/, 10];
                                                        processCwdFallbackApplied = true;
                                                        workingDirectory = this_1.resolveProcessWorkingDirectory(modelOptions);
                                                        fallbackOptions_1 = this_1.applyProcessCwdFallback(modelOptions);
                                                        this_1.log('codex workingDirectory launch failed with os error 2; retrying from process cwd without CLI workingDirectory.');
                                                        _d = {};
                                                        return [4 /*yield*/, this_1.withProcessWorkingDirectoryFallback(workingDirectory, function () { return __awaiter(_this, void 0, void 0, function () {
                                                                var fallbackResult_1, fallbackResult;
                                                                return __generator(this, function (_a) {
                                                                    switch (_a.label) {
                                                                        case 0:
                                                                            if (!(this.streamEnabled && !this.isPingPrompt(prompt))) return [3 /*break*/, 3];
                                                                            return [4 /*yield*/, this.runStreamedOnce(prompt, fallbackOptions_1)];
                                                                        case 1:
                                                                            fallbackResult_1 = _a.sent();
                                                                            return [4 /*yield*/, this.clearModelFallbackPreference(model)];
                                                                        case 2:
                                                                            _a.sent();
                                                                            return [2 /*return*/, fallbackResult_1];
                                                                        case 3: return [4 /*yield*/, this.runOnce(prompt, fallbackOptions_1)];
                                                                        case 4:
                                                                            fallbackResult = _a.sent();
                                                                            return [4 /*yield*/, this.clearModelFallbackPreference(model)];
                                                                        case 5:
                                                                            _a.sent();
                                                                            return [2 /*return*/, fallbackResult];
                                                                    }
                                                                });
                                                            }); })];
                                                    case 9: return [2 /*return*/, (_d.value = _e.sent(), _d)];
                                                    case 10:
                                                        if (!(nextModel && this_1.isModelAvailabilityError(error_1))) return [3 /*break*/, 12];
                                                        return [4 /*yield*/, this_1.rememberModelFallbackPreference(model, nextModel)];
                                                    case 11:
                                                        _e.sent();
                                                        this_1.log("model unavailable; retrying with fallback model ".concat(nextModel));
                                                        return [2 /*return*/, "break"];
                                                    case 12:
                                                        if (this_1.isCodexEnvironmentError(error_1)) {
                                                            this_1.recoverCodexEnvironment(error_1);
                                                        }
                                                        if (attempt >= maxRetries || !this_1.isRetryableError(error_1)) {
                                                            throw lastError;
                                                        }
                                                        delay = retryDelayMs * Math.pow(2, attempt);
                                                        return [4 /*yield*/, this_1.sleep(delay)];
                                                    case 13:
                                                        _e.sent();
                                                        attempt += 1;
                                                        return [3 /*break*/, 14];
                                                    case 14: return [2 /*return*/];
                                                }
                                            });
                                        };
                                        _c.label = 1;
                                    case 1:
                                        if (!(attempt <= maxRetries)) return [3 /*break*/, 3];
                                        return [5 /*yield**/, _loop_2()];
                                    case 2:
                                        state_2 = _c.sent();
                                        if (typeof state_2 === "object")
                                            return [2 /*return*/, state_2];
                                        if (state_2 === "break")
                                            return [3 /*break*/, 3];
                                        return [3 /*break*/, 1];
                                    case 3: return [2 /*return*/];
                                }
                            });
                        };
                        this_1 = this;
                        modelIndex = 0;
                        _b.label = 2;
                    case 2:
                        if (!(modelIndex < modelSequence.length)) return [3 /*break*/, 5];
                        return [5 /*yield**/, _loop_1(modelIndex)];
                    case 3:
                        state_1 = _b.sent();
                        if (typeof state_1 === "object")
                            return [2 /*return*/, state_1.value];
                        _b.label = 4;
                    case 4:
                        modelIndex += 1;
                        return [3 /*break*/, 2];
                    case 5: throw lastError;
                }
            });
        });
    };
    CodexClient.prototype.runStreamedOnce = function (prompt, options) {
        return __awaiter(this, void 0, void 0, function () {
            var startedAt, thread, timeoutMs, streamIdleTimeoutMs, controller, timeoutId, lastStreamActivityAt, idleTimeoutId, finalResponse, lastText, usageSummary, events, _a, events_1, events_1_1, event_1, error_2, message, e_1_1, error_3, idleForMs, message;
            var _this = this;
            var _b, e_1, _c, _d;
            var _e, _f, _g;
            return __generator(this, function (_h) {
                switch (_h.label) {
                    case 0:
                        startedAt = Date.now();
                        this.log("runStreamed start (promptLength=".concat(prompt.length, ")"));
                        return [4 /*yield*/, this.startThread(options === null || options === void 0 ? void 0 : options.threadOptions, options === null || options === void 0 ? void 0 : options.threadKey, options === null || options === void 0 ? void 0 : options.reuseThread)];
                    case 1:
                        thread = _h.sent();
                        timeoutMs = (_e = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _e !== void 0 ? _e : this.defaultTimeoutMs;
                        streamIdleTimeoutMs = this.normalizeStreamIdleTimeoutMs(options === null || options === void 0 ? void 0 : options.streamIdleTimeoutMs);
                        controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
                        timeoutId = controller
                            ? setTimeout(function () { return controller.abort(); }, timeoutMs)
                            : null;
                        lastStreamActivityAt = Date.now();
                        idleTimeoutId = controller && streamIdleTimeoutMs > 0
                            ? setInterval(function () {
                                if (Date.now() - lastStreamActivityAt >= streamIdleTimeoutMs) {
                                    controller.abort();
                                }
                            }, Math.max(15000, Math.min(60000, Math.floor(streamIdleTimeoutMs / 4))))
                            : null;
                        finalResponse = '';
                        lastText = '';
                        usageSummary = null;
                        _h.label = 2;
                    case 2:
                        _h.trys.push([2, 21, 22, 23]);
                        return [4 /*yield*/, thread.runStreamed(prompt, controller ? { signal: controller.signal } : undefined)];
                    case 3:
                        events = (_h.sent()).events;
                        _h.label = 4;
                    case 4:
                        _h.trys.push([4, 14, 15, 20]);
                        _a = true, events_1 = __asyncValues(events);
                        _h.label = 5;
                    case 5: return [4 /*yield*/, events_1.next()];
                    case 6:
                        if (!(events_1_1 = _h.sent(), _b = events_1_1.done, !_b)) return [3 /*break*/, 13];
                        _d = events_1_1.value;
                        _a = false;
                        event_1 = _d;
                        lastStreamActivityAt = Date.now();
                        if ((event_1 === null || event_1 === void 0 ? void 0 : event_1.type) === 'turn.completed') {
                            usageSummary = this.normalizeUsageSummary(event_1 === null || event_1 === void 0 ? void 0 : event_1.usage);
                        }
                        if (!(options === null || options === void 0 ? void 0 : options.onStreamEvent)) return [3 /*break*/, 10];
                        _h.label = 7;
                    case 7:
                        _h.trys.push([7, 9, , 10]);
                        return [4 /*yield*/, options.onStreamEvent(event_1)];
                    case 8:
                        _h.sent();
                        return [3 /*break*/, 10];
                    case 9:
                        error_2 = _h.sent();
                        message = error_2 instanceof Error ? error_2.message : String(error_2 || 'Unknown error');
                        this.log("onStreamEvent failed: ".concat(message));
                        if (options === null || options === void 0 ? void 0 : options.failOnStreamHandlerError) {
                            throw error_2;
                        }
                        return [3 /*break*/, 10];
                    case 10: return [4 /*yield*/, this.handleStreamEvent(event_1, function (text) { return __awaiter(_this, void 0, void 0, function () {
                            var next, delta, error_4, message;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        next = text || '';
                                        if (!next) {
                                            return [2 /*return*/];
                                        }
                                        delta = next.startsWith(lastText) ? next.slice(lastText.length) : next;
                                        if (!delta) return [3 /*break*/, 4];
                                        this.logStreamText(delta);
                                        if (!(options === null || options === void 0 ? void 0 : options.onStreamText)) return [3 /*break*/, 4];
                                        _a.label = 1;
                                    case 1:
                                        _a.trys.push([1, 3, , 4]);
                                        return [4 /*yield*/, options.onStreamText(delta, next)];
                                    case 2:
                                        _a.sent();
                                        return [3 /*break*/, 4];
                                    case 3:
                                        error_4 = _a.sent();
                                        message = error_4 instanceof Error ? error_4.message : String(error_4 || 'Unknown error');
                                        this.log("onStreamText failed: ".concat(message));
                                        if (options === null || options === void 0 ? void 0 : options.failOnStreamHandlerError) {
                                            throw error_4;
                                        }
                                        return [3 /*break*/, 4];
                                    case 4:
                                        lastText = next;
                                        finalResponse = next;
                                        return [2 /*return*/];
                                }
                            });
                        }); })];
                    case 11:
                        _h.sent();
                        if ((event_1 === null || event_1 === void 0 ? void 0 : event_1.type) === 'turn.failed') {
                            throw new Error(((_f = event_1.error) === null || _f === void 0 ? void 0 : _f.message) || 'AI run failed.');
                        }
                        if ((event_1 === null || event_1 === void 0 ? void 0 : event_1.type) === 'error') {
                            throw new Error(event_1.message || 'AI stream error.');
                        }
                        _h.label = 12;
                    case 12:
                        _a = true;
                        return [3 /*break*/, 5];
                    case 13: return [3 /*break*/, 20];
                    case 14:
                        e_1_1 = _h.sent();
                        e_1 = { error: e_1_1 };
                        return [3 /*break*/, 20];
                    case 15:
                        _h.trys.push([15, , 18, 19]);
                        if (!(!_a && !_b && (_c = events_1.return))) return [3 /*break*/, 17];
                        return [4 /*yield*/, _c.call(events_1)];
                    case 16:
                        _h.sent();
                        _h.label = 17;
                    case 17: return [3 /*break*/, 19];
                    case 18:
                        if (e_1) throw e_1.error;
                        return [7 /*endfinally*/];
                    case 19: return [7 /*endfinally*/];
                    case 20: return [3 /*break*/, 23];
                    case 21:
                        error_3 = _h.sent();
                        if ((_g = controller === null || controller === void 0 ? void 0 : controller.signal) === null || _g === void 0 ? void 0 : _g.aborted) {
                            idleForMs = Date.now() - lastStreamActivityAt;
                            if (streamIdleTimeoutMs > 0 && idleForMs >= streamIdleTimeoutMs) {
                                this.log("runStreamed idle timed out (durationMs=".concat(Date.now() - startedAt, ", idleForMs=").concat(idleForMs, ")"));
                                throw new Error("AI stream stalled with no activity for ".concat(idleForMs, "ms."));
                            }
                            this.log("runStreamed timed out (durationMs=".concat(Date.now() - startedAt, ")"));
                            throw new Error('AI request timed out.');
                        }
                        message = error_3 instanceof Error ? error_3.message : String(error_3 || 'Unknown error');
                        this.log("runStreamed failed (durationMs=".concat(Date.now() - startedAt, "): ").concat(message));
                        throw error_3;
                    case 22:
                        if (timeoutId) {
                            clearTimeout(timeoutId);
                        }
                        if (idleTimeoutId) {
                            clearInterval(idleTimeoutId);
                        }
                        return [7 /*endfinally*/];
                    case 23:
                        if (!finalResponse) {
                            throw new Error('AI returned no completion content.');
                        }
                        return [4 /*yield*/, this.emitUsageSummary(options, usageSummary)];
                    case 24:
                        _h.sent();
                        this.log("runStreamed complete (contentLength=".concat(finalResponse.length, ", durationMs=").concat(Date.now() - startedAt, ")"));
                        return [2 /*return*/, finalResponse.trim()];
                }
            });
        });
    };
    CodexClient.prototype.normalizeStreamIdleTimeoutMs = function (value) {
        var parsed = Number(value || 0);
        if (!Number.isFinite(parsed) || parsed < 60000) {
            return 0;
        }
        return Math.floor(parsed);
    };
    CodexClient.prototype.runOnce = function (prompt, options) {
        return __awaiter(this, void 0, void 0, function () {
            var startedAt, thread, runPromise, timeoutMs, result, content, error_5, message;
            var _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        startedAt = Date.now();
                        this.log("runOnce start (promptLength=".concat(prompt.length, ")"));
                        _b.label = 1;
                    case 1:
                        _b.trys.push([1, 5, , 6]);
                        return [4 /*yield*/, this.startThread(options === null || options === void 0 ? void 0 : options.threadOptions, options === null || options === void 0 ? void 0 : options.threadKey, options === null || options === void 0 ? void 0 : options.reuseThread)];
                    case 2:
                        thread = _b.sent();
                        runPromise = thread.run(prompt);
                        timeoutMs = (_a = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _a !== void 0 ? _a : this.defaultTimeoutMs;
                        this.log("runOnce awaiting result (timeoutMs=".concat(timeoutMs, ")"));
                        return [4 /*yield*/, this.withTimeout(runPromise, timeoutMs)];
                    case 3:
                        result = _b.sent();
                        content = this.extractContent(result);
                        if (!content) {
                            throw new Error('AI returned no completion content.');
                        }
                        return [4 /*yield*/, this.emitUsageSummary(options, this.normalizeUsageSummary(result === null || result === void 0 ? void 0 : result.usage))];
                    case 4:
                        _b.sent();
                        this.log("runOnce complete (contentLength=".concat(content.length, ", durationMs=").concat(Date.now() - startedAt, ")"));
                        return [2 /*return*/, content];
                    case 5:
                        error_5 = _b.sent();
                        message = error_5 instanceof Error ? error_5.message : String(error_5 || 'Unknown error');
                        this.log("runOnce failed (durationMs=".concat(Date.now() - startedAt, "): ").concat(message));
                        throw error_5;
                    case 6: return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.startThread = function (threadOptions_1, threadKey_1) {
        return __awaiter(this, arguments, void 0, function (threadOptions, threadKey, reuseThread) {
            var mergedOptions, optionsKey, effectiveModel, modelKey, cacheKey, explicitThreadKey, hasExplicitThreadKey, existing, sameOptions, sameModel, thread_1, thread;
            if (reuseThread === void 0) { reuseThread = true; }
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, this.ensureCodex()];
                    case 1:
                        _a.sent();
                        mergedOptions = this.mergeThreadOptions(threadOptions);
                        optionsKey = this.buildThreadOptionsKey(mergedOptions);
                        effectiveModel = (mergedOptions === null || mergedOptions === void 0 ? void 0 : mergedOptions.model) || this.config.model || 'default';
                        modelKey = this.normalizeOptionalString(effectiveModel).toLowerCase() || 'default';
                        cacheKey = this.buildThreadCacheKey(threadKey, mergedOptions);
                        explicitThreadKey = (threadKey || '').trim();
                        hasExplicitThreadKey = explicitThreadKey.length > 0;
                        if (reuseThread && cacheKey) {
                            existing = this.threadCache.get(cacheKey);
                            if (existing) {
                                sameOptions = existing.optionsKey === optionsKey;
                                sameModel = existing.modelKey === modelKey;
                                if (sameOptions || (hasExplicitThreadKey && sameModel)) {
                                    if (hasExplicitThreadKey && existing.optionsKey !== optionsKey) {
                                        this.log("startThread reuse explicit key (".concat(cacheKey, ") despite option change"));
                                    }
                                    else {
                                        this.log("startThread reuse (".concat(cacheKey, ")"));
                                    }
                                    return [2 /*return*/, existing.thread];
                                }
                                if (hasExplicitThreadKey && !sameModel) {
                                    this.log("startThread explicit key (".concat(cacheKey, ") model changed (").concat(existing.modelKey, " -> ").concat(modelKey, "); creating new thread"));
                                }
                            }
                        }
                        this.log("startThread (model=".concat(effectiveModel, ")"));
                        if (mergedOptions === null || mergedOptions === void 0 ? void 0 : mergedOptions.model) {
                            this.log("startThread options: ".concat(this.formatThreadOptions(mergedOptions)));
                            thread_1 = this.codex.startThread(mergedOptions);
                            this.log('startThread created with model override');
                            if (cacheKey) {
                                this.threadCache.set(cacheKey, { thread: thread_1, optionsKey: optionsKey, modelKey: modelKey });
                            }
                            return [2 /*return*/, thread_1];
                        }
                        if (mergedOptions && Object.keys(mergedOptions).length) {
                            this.log("startThread options: ".concat(this.formatThreadOptions(mergedOptions)));
                        }
                        thread = this.codex.startThread(mergedOptions);
                        this.log('startThread created');
                        if (cacheKey) {
                            this.threadCache.set(cacheKey, { thread: thread, optionsKey: optionsKey, modelKey: modelKey });
                        }
                        return [2 /*return*/, thread];
                }
            });
        });
    };
    CodexClient.prototype.extractContent = function (result) {
        var _this = this;
        if (!result) {
            return '';
        }
        if (typeof result.finalResponse === 'string') {
            return result.finalResponse.trim();
        }
        if (typeof result === 'string') {
            return result.trim();
        }
        if (Array.isArray(result.items)) {
            var lastMessage = __spreadArray([], __read(result.items), false).reverse().find(function (item) { return (item === null || item === void 0 ? void 0 : item.type) === 'agent_message' && typeof item.text === 'string'; });
            if (lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.text) {
                return lastMessage.text.trim();
            }
        }
        if (typeof result.output_text === 'string') {
            return result.output_text.trim();
        }
        if (typeof result.outputText === 'string') {
            return result.outputText.trim();
        }
        if (typeof result.content === 'string') {
            return result.content.trim();
        }
        if (typeof result.text === 'string') {
            return result.text.trim();
        }
        if (Array.isArray(result.content)) {
            var text = result.content
                .map(function (part) { return _this.extractPartText(part); })
                .join('')
                .trim();
            if (text) {
                return text;
            }
        }
        if (Array.isArray(result.output)) {
            var text = result.output
                .map(function (item) {
                if (!item) {
                    return '';
                }
                if (typeof item === 'string') {
                    return item;
                }
                if (typeof item.text === 'string') {
                    return item.text;
                }
                if (typeof item.content === 'string') {
                    return item.content;
                }
                if (Array.isArray(item.content)) {
                    return item.content.map(function (part) { return _this.extractPartText(part); }).join('');
                }
                return '';
            })
                .join('')
                .trim();
            if (text) {
                return text;
            }
        }
        return '';
    };
    CodexClient.prototype.handleStreamEvent = function (event, onAgentMessage) {
        return __awaiter(this, void 0, void 0, function () {
            var _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        if (!event || !event.type) {
                            return [2 /*return*/];
                        }
                        _a = event.type;
                        switch (_a) {
                            case 'thread.started': return [3 /*break*/, 1];
                            case 'turn.started': return [3 /*break*/, 2];
                            case 'turn.completed': return [3 /*break*/, 3];
                            case 'item.started': return [3 /*break*/, 4];
                            case 'item.updated': return [3 /*break*/, 4];
                            case 'item.completed': return [3 /*break*/, 4];
                        }
                        return [3 /*break*/, 6];
                    case 1:
                        this.log("stream thread.started (id=".concat(event.thread_id || 'unknown', ")"));
                        return [3 /*break*/, 7];
                    case 2:
                        this.log('stream turn.started');
                        return [3 /*break*/, 7];
                    case 3:
                        this.log('stream turn.completed');
                        return [3 /*break*/, 7];
                    case 4: return [4 /*yield*/, this.handleStreamItem(event.item, onAgentMessage)];
                    case 5:
                        _b.sent();
                        return [3 /*break*/, 7];
                    case 6: return [3 /*break*/, 7];
                    case 7: return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.normalizeUsageSummary = function (raw) {
        var _a, _b, _c;
        if (!raw || typeof raw !== 'object') {
            return null;
        }
        var inputTokens = this.normalizeUsageToken((_a = raw.input_tokens) !== null && _a !== void 0 ? _a : raw.inputTokens);
        var cachedInputTokens = this.normalizeUsageToken((_b = raw.cached_input_tokens) !== null && _b !== void 0 ? _b : raw.cachedInputTokens);
        var outputTokens = this.normalizeUsageToken((_c = raw.output_tokens) !== null && _c !== void 0 ? _c : raw.outputTokens);
        if (inputTokens <= 0 && cachedInputTokens <= 0 && outputTokens <= 0) {
            return null;
        }
        return {
            inputTokens: inputTokens,
            cachedInputTokens: cachedInputTokens,
            outputTokens: outputTokens
        };
    };
    CodexClient.prototype.normalizeUsageToken = function (value) {
        var parsed = Number(value);
        if (!Number.isFinite(parsed) || parsed <= 0) {
            return 0;
        }
        return Math.floor(parsed);
    };
    CodexClient.prototype.emitUsageSummary = function (options, usage) {
        return __awaiter(this, void 0, void 0, function () {
            var error_6, message;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (!(options === null || options === void 0 ? void 0 : options.onUsage)) {
                            return [2 /*return*/];
                        }
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 3, , 4]);
                        return [4 /*yield*/, options.onUsage(usage)];
                    case 2:
                        _a.sent();
                        return [3 /*break*/, 4];
                    case 3:
                        error_6 = _a.sent();
                        message = error_6 instanceof Error ? error_6.message : String(error_6 || 'Unknown error');
                        this.log("onUsage failed: ".concat(message));
                        return [3 /*break*/, 4];
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.handleStreamItem = function (item, onAgentMessage) {
        return __awaiter(this, void 0, void 0, function () {
            var _a, output, summary, total, done, snippet;
            var _b;
            return __generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        if (!item || !item.type) {
                            return [2 /*return*/];
                        }
                        _a = item.type;
                        switch (_a) {
                            case 'agent_message': return [3 /*break*/, 1];
                            case 'command_execution': return [3 /*break*/, 3];
                            case 'file_change': return [3 /*break*/, 4];
                            case 'mcp_tool_call': return [3 /*break*/, 5];
                            case 'web_search': return [3 /*break*/, 6];
                            case 'todo_list': return [3 /*break*/, 7];
                            case 'reasoning': return [3 /*break*/, 8];
                            case 'error': return [3 /*break*/, 9];
                        }
                        return [3 /*break*/, 10];
                    case 1: return [4 /*yield*/, onAgentMessage(item.text || '')];
                    case 2:
                        _c.sent();
                        return [3 /*break*/, 11];
                    case 3:
                        if (item.command) {
                            this.log("stream command: ".concat(item.command, " (").concat(item.status || 'unknown', ")"));
                        }
                        if (item.aggregated_output) {
                            output = item.aggregated_output.length > 800
                                ? "".concat(item.aggregated_output.slice(0, 800), "...")
                                : item.aggregated_output;
                            this.log("stream command output: ".concat(output));
                        }
                        return [3 /*break*/, 11];
                    case 4:
                        if (Array.isArray(item.changes) && item.changes.length) {
                            summary = item.changes.map(function (change) { return "".concat(change.kind, ":").concat(change.path); }).join(', ');
                            this.log("stream file_change (".concat(item.status || 'unknown', "): ").concat(summary));
                        }
                        return [3 /*break*/, 11];
                    case 5:
                        if (item.tool) {
                            this.log("stream tool_call: ".concat(item.tool, " (").concat(item.status || 'unknown', ")"));
                        }
                        if ((_b = item.error) === null || _b === void 0 ? void 0 : _b.message) {
                            this.log("stream tool_call error: ".concat(item.error.message));
                        }
                        return [3 /*break*/, 11];
                    case 6:
                        if (item.query) {
                            this.log("stream web_search: ".concat(item.query));
                        }
                        return [3 /*break*/, 11];
                    case 7:
                        if (Array.isArray(item.items)) {
                            total = item.items.length;
                            done = item.items.filter(function (entry) { return entry === null || entry === void 0 ? void 0 : entry.completed; }).length;
                            this.log("stream todo_list: ".concat(done, "/").concat(total, " completed"));
                        }
                        return [3 /*break*/, 11];
                    case 8:
                        if (item.text) {
                            snippet = item.text.length > 200 ? "".concat(item.text.slice(0, 200), "...") : item.text;
                            this.log("stream reasoning: ".concat(snippet));
                        }
                        return [3 /*break*/, 11];
                    case 9:
                        if (item.message) {
                            this.log("stream error: ".concat(item.message));
                        }
                        return [3 /*break*/, 11];
                    case 10: return [3 /*break*/, 11];
                    case 11: return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.logStreamText = function (text) {
        var e_2, _a;
        if (!this.debugEnabled) {
            return;
        }
        var lines = text.split(/\r?\n/);
        try {
            for (var lines_1 = __values(lines), lines_1_1 = lines_1.next(); !lines_1_1.done; lines_1_1 = lines_1.next()) {
                var line = lines_1_1.value;
                this.log("stream: ".concat(line));
            }
        }
        catch (e_2_1) { e_2 = { error: e_2_1 }; }
        finally {
            try {
                if (lines_1_1 && !lines_1_1.done && (_a = lines_1.return)) _a.call(lines_1);
            }
            finally { if (e_2) throw e_2.error; }
        }
    };
    CodexClient.prototype.extractPartText = function (part) {
        if (!part) {
            return '';
        }
        if (typeof part === 'string') {
            return part;
        }
        if (typeof part.text === 'string') {
            return part.text;
        }
        if (typeof part.content === 'string') {
            return part.content;
        }
        return '';
    };
    CodexClient.prototype.withTimeout = function (promise, timeoutMs) {
        return __awaiter(this, void 0, void 0, function () {
            var done, startedAt, heartbeatMs, timeoutPromise;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        done = false;
                        startedAt = Date.now();
                        heartbeatMs = Math.max(10000, Math.min(30000, Math.floor(timeoutMs / 4)));
                        timeoutPromise = (function () { return __awaiter(_this, void 0, void 0, function () {
                            var elapsed, remaining, currentElapsed, currentRemaining;
                            return __generator(this, function (_a) {
                                switch (_a.label) {
                                    case 0:
                                        if (!!done) return [3 /*break*/, 4];
                                        elapsed = Date.now() - startedAt;
                                        if (elapsed >= timeoutMs) {
                                            throw new Error('AI request timed out.');
                                        }
                                        remaining = timeoutMs - elapsed;
                                        return [4 /*yield*/, (0, promises_1.setTimeout)(Math.min(heartbeatMs, remaining))];
                                    case 1:
                                        _a.sent();
                                        if (!done) return [3 /*break*/, 3];
                                        return [4 /*yield*/, promise];
                                    case 2: return [2 /*return*/, _a.sent()];
                                    case 3:
                                        currentElapsed = Date.now() - startedAt;
                                        if (currentElapsed >= timeoutMs) {
                                            throw new Error('AI request timed out.');
                                        }
                                        currentRemaining = Math.max(0, timeoutMs - currentElapsed);
                                        this.log("runOnce waiting (elapsedMs=".concat(currentElapsed, ", remainingMs=").concat(currentRemaining, ")"));
                                        return [3 /*break*/, 0];
                                    case 4: return [4 /*yield*/, promise];
                                    case 5: return [2 /*return*/, _a.sent()];
                                }
                            });
                        }); })();
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, , 3, 4]);
                        return [4 /*yield*/, Promise.race([promise, timeoutPromise])];
                    case 2: return [2 /*return*/, _a.sent()];
                    case 3:
                        done = true;
                        return [7 /*endfinally*/];
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.normalizeRetryCount = function (value) {
        if (typeof value !== 'number' || Number.isNaN(value)) {
            return 2;
        }
        return Math.max(0, Math.floor(value));
    };
    CodexClient.prototype.normalizeRetryDelay = function (value) {
        if (typeof value !== 'number' || Number.isNaN(value)) {
            return 500;
        }
        return Math.max(100, Math.floor(value));
    };
    CodexClient.prototype.resolveModelSequence = function (options) {
        var _this = this;
        var _a;
        var primary = this.normalizeOptionalString(((_a = options === null || options === void 0 ? void 0 : options.threadOptions) === null || _a === void 0 ? void 0 : _a.model) || this.config.model);
        var fallbackModels = this.collectFallbackModels(options === null || options === void 0 ? void 0 : options.fallbackModels);
        var sequence = [];
        var push = function (value) {
            var normalized = _this.normalizeOptionalString(value);
            if (!normalized || sequence.includes(normalized)) {
                return;
            }
            sequence.push(normalized);
        };
        var preferredFallback = this.getModelFallbackPreference(primary);
        if (preferredFallback) {
            push(preferredFallback);
            this.log("sticky model fallback active: ".concat(primary, " -> ").concat(preferredFallback));
        }
        push(primary);
        fallbackModels.forEach(push);
        if (!sequence.length) {
            sequence.push('');
        }
        return sequence;
    };
    CodexClient.prototype.collectFallbackModels = function (runFallbackModels) {
        var _this = this;
        var models = [];
        var push = function (value) {
            var normalized = _this.normalizeOptionalString(value);
            if (!normalized || models.includes(normalized)) {
                return;
            }
            models.push(normalized);
        };
        this.normalizeModelList(runFallbackModels).forEach(push);
        this.normalizeModelList(this.config.fallbackModels).forEach(push);
        push(this.config.fallbackModel);
        this.normalizeModelList(process.env.AI_ASSISTANT_CODEX_FALLBACK_MODELS).forEach(push);
        push(process.env.AI_ASSISTANT_CODEX_FALLBACK_MODEL);
        this.normalizeModelList(process.env.AI_TERMINAL_CODEX_FALLBACK_MODELS).forEach(push);
        push(process.env.AI_TERMINAL_CODEX_FALLBACK_MODEL);
        this.normalizeModelList(process.env.AI_DASHBOARD_CODEX_FALLBACK_MODELS).forEach(push);
        push(process.env.AI_DASHBOARD_CODEX_FALLBACK_MODEL);
        var primaryModel = this.normalizeOptionalString(this.config.model
            || (runFallbackModels === null || runFallbackModels === void 0 ? void 0 : runFallbackModels[0])
            || '');
        if (/^gpt-5(?:\.\d+)?-codex$/i.test(primaryModel)) {
            push('gpt-5-codex');
        }
        if (/^gpt-5(?:-codex|\.\d+-codex)$/i.test(primaryModel)) {
            push('gpt-5.5');
        }
        return models;
    };
    CodexClient.prototype.normalizeModelList = function (value) {
        var _this = this;
        if (Array.isArray(value)) {
            return value
                .map(function (entry) { return _this.normalizeOptionalString(entry); })
                .filter(Boolean);
        }
        var raw = this.normalizeOptionalString(value);
        if (!raw) {
            return [];
        }
        return raw
            .split(',')
            .map(function (entry) { return _this.normalizeOptionalString(entry); })
            .filter(Boolean);
    };
    CodexClient.prototype.applyModelOverride = function (options, model) {
        var nextThreadOptions = __assign({}, ((options === null || options === void 0 ? void 0 : options.threadOptions) || {}));
        if (model) {
            nextThreadOptions.model = model;
        }
        else {
            delete nextThreadOptions.model;
        }
        return __assign(__assign({}, (options || {})), { threadOptions: nextThreadOptions });
    };
    CodexClient.prototype.isModelAvailabilityError = function (error) {
        var message = error instanceof Error ? error.message : String(error || '');
        var normalized = message.toLowerCase();
        if (!normalized.includes('model')) {
            return false;
        }
        if (/does not exist|not found|unknown model|invalid model|unsupported model|model_not_found|no such model/.test(normalized)) {
            return true;
        }
        if (/not available|unavailable|not enabled|not allowed|do not have access|don't have access|insufficient permissions/.test(normalized)) {
            return true;
        }
        return /404/.test(normalized) && /model/.test(normalized);
    };
    CodexClient.prototype.isRetryableError = function (error) {
        var message = error instanceof Error ? error.message : String(error || '');
        if (/AI returned no completion content|Codex returned no completion content/i.test(message)) {
            return true;
        }
        if (this.isCodexEnvironmentError(error)) {
            return true;
        }
        var statusMatch = message.match(/\\b(429|5\\d{2})\\b/);
        if (statusMatch) {
            return true;
        }
        return /ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|fetch failed|timed out|timeout/i.test(message);
    };
    CodexClient.prototype.isCodexEnvironmentError = function (error) {
        var message = error instanceof Error ? error.message : String(error || '');
        return /error finding codex home|could not update path: no such file or directory/i.test(message);
    };
    CodexClient.prototype.recoverCodexEnvironment = function (error) {
        var message = error instanceof Error ? error.message : String(error || 'Unknown error');
        this.log("recovering codex environment after error: ".concat(message));
        this.threadCache.clear();
        this.codex = null;
        this.codexInit = null;
        this.zDotDir = null;
    };
    CodexClient.prototype.shouldApplyProcessCwdFallback = function (error, options) {
        var workingDirectory = this.resolveProcessWorkingDirectory(options);
        if (!workingDirectory) {
            return false;
        }
        var message = error instanceof Error ? error.message : String(error || '');
        return /no such file or directory \(os error 2\)/i.test(message);
    };
    CodexClient.prototype.resolveProcessWorkingDirectory = function (options) {
        var _a;
        return this.normalizeOptionalString((options === null || options === void 0 ? void 0 : options.processWorkingDirectory) || ((_a = options === null || options === void 0 ? void 0 : options.threadOptions) === null || _a === void 0 ? void 0 : _a.workingDirectory));
    };
    CodexClient.prototype.applyProcessCwdFallback = function (options) {
        var nextThreadOptions = __assign({}, ((options === null || options === void 0 ? void 0 : options.threadOptions) || {}));
        delete nextThreadOptions.workingDirectory;
        return __assign(__assign({}, (options || {})), { threadOptions: nextThreadOptions });
    };
    CodexClient.prototype.withProcessWorkingDirectoryFallback = function (workingDirectory, runner) {
        return __awaiter(this, void 0, void 0, function () {
            var normalizedWorkingDirectory, originalCwd, message;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        normalizedWorkingDirectory = this.normalizeOptionalString(workingDirectory);
                        if (!!normalizedWorkingDirectory) return [3 /*break*/, 2];
                        return [4 /*yield*/, runner()];
                    case 1: return [2 /*return*/, _a.sent()];
                    case 2:
                        if (!CodexClient.cwdFallbackRunning) return [3 /*break*/, 4];
                        return [4 /*yield*/, this.sleep(50)];
                    case 3:
                        _a.sent();
                        return [3 /*break*/, 2];
                    case 4:
                        CodexClient.cwdFallbackRunning = true;
                        originalCwd = process.cwd();
                        _a.label = 5;
                    case 5:
                        _a.trys.push([5, , 7, 8]);
                        process.chdir(normalizedWorkingDirectory);
                        this.log("running Codex fallback from process cwd ".concat(normalizedWorkingDirectory));
                        return [4 /*yield*/, runner()];
                    case 6: return [2 /*return*/, _a.sent()];
                    case 7:
                        try {
                            process.chdir(originalCwd);
                        }
                        catch (error) {
                            message = error instanceof Error ? error.message : String(error || 'Unknown error');
                            this.log("failed to restore process cwd to ".concat(originalCwd, ": ").concat(message));
                        }
                        CodexClient.cwdFallbackRunning = false;
                        return [7 /*endfinally*/];
                    case 8: return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.normalizeOptionalString = function (value) {
        return typeof value === 'string' ? value.trim() : '';
    };
    CodexClient.prototype.resolveModelUnavailableTtlMs = function () {
        var raw = Number(process.env.AI_DASHBOARD_CODEX_MODEL_UNAVAILABLE_TTL_MS
            || process.env.AI_ASSISTANT_CODEX_MODEL_UNAVAILABLE_TTL_MS);
        if (Number.isFinite(raw) && raw >= CodexClient.MIN_MODEL_UNAVAILABLE_TTL_MS) {
            return Math.floor(raw);
        }
        return CodexClient.DEFAULT_MODEL_UNAVAILABLE_TTL_MS;
    };
    CodexClient.prototype.ensureModelFallbackPreferencesLoaded = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (CodexClient.modelFallbackPreferencesLoaded) {
                            this.pruneModelFallbackPreferences();
                            return [2 /*return*/];
                        }
                        if (!(CodexClient.modelFallbackPreferencesLoadPromise !== null)) return [3 /*break*/, 2];
                        return [4 /*yield*/, CodexClient.modelFallbackPreferencesLoadPromise];
                    case 1:
                        _a.sent();
                        this.pruneModelFallbackPreferences();
                        return [2 /*return*/];
                    case 2:
                        CodexClient.modelFallbackPreferencesLoadPromise = (function () { return __awaiter(_this, void 0, void 0, function () {
                            var raw, parsed, _a;
                            var _this = this;
                            return __generator(this, function (_b) {
                                switch (_b.label) {
                                    case 0:
                                        _b.trys.push([0, 2, 3, 4]);
                                        return [4 /*yield*/, fs_1.promises.readFile(CodexClient.MODEL_UNAVAILABLE_FALLBACK_FILE, 'utf8')];
                                    case 1:
                                        raw = _b.sent();
                                        parsed = JSON.parse(raw);
                                        if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
                                            return [2 /*return*/];
                                        }
                                        Object.entries(parsed).forEach(function (_a) {
                                            var _b = __read(_a, 2), model = _b[0], entry = _b[1];
                                            var key = _this.normalizeOptionalString(model);
                                            if (!key) {
                                                return;
                                            }
                                            var fallbackModel = _this.normalizeOptionalString(entry === null || entry === void 0 ? void 0 : entry.fallbackModel);
                                            var expiresAt = Number(entry === null || entry === void 0 ? void 0 : entry.expiresAt);
                                            var updatedAt = Number(entry === null || entry === void 0 ? void 0 : entry.updatedAt);
                                            if (!fallbackModel || !Number.isFinite(expiresAt) || expiresAt <= Date.now()) {
                                                return;
                                            }
                                            CodexClient.modelFallbackPreferences.set(key, {
                                                fallbackModel: fallbackModel,
                                                expiresAt: Math.floor(expiresAt),
                                                updatedAt: Number.isFinite(updatedAt) ? Math.floor(updatedAt) : Date.now()
                                            });
                                        });
                                        return [3 /*break*/, 4];
                                    case 2:
                                        _a = _b.sent();
                                        return [3 /*break*/, 4];
                                    case 3:
                                        CodexClient.modelFallbackPreferencesLoaded = true;
                                        CodexClient.modelFallbackPreferencesLoadPromise = null;
                                        return [7 /*endfinally*/];
                                    case 4: return [2 /*return*/];
                                }
                            });
                        }); })();
                        return [4 /*yield*/, CodexClient.modelFallbackPreferencesLoadPromise];
                    case 3:
                        _a.sent();
                        this.pruneModelFallbackPreferences();
                        return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.pruneModelFallbackPreferences = function (now) {
        if (now === void 0) { now = Date.now(); }
        Array.from(CodexClient.modelFallbackPreferences.entries()).forEach(function (_a) {
            var _b = __read(_a, 2), model = _b[0], entry = _b[1];
            if (!entry || !Number.isFinite(entry.expiresAt) || entry.expiresAt <= now) {
                CodexClient.modelFallbackPreferences.delete(model);
            }
        });
    };
    CodexClient.prototype.getModelFallbackPreference = function (model) {
        var normalizedModel = this.normalizeOptionalString(model);
        if (!normalizedModel) {
            return '';
        }
        this.pruneModelFallbackPreferences();
        var entry = CodexClient.modelFallbackPreferences.get(normalizedModel);
        if (!entry || entry.expiresAt <= Date.now()) {
            if (entry) {
                CodexClient.modelFallbackPreferences.delete(normalizedModel);
            }
            return '';
        }
        return entry.fallbackModel;
    };
    CodexClient.prototype.rememberModelFallbackPreference = function (model, fallbackModel) {
        return __awaiter(this, void 0, void 0, function () {
            var normalizedModel, normalizedFallback, now;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        normalizedModel = this.normalizeOptionalString(model);
                        normalizedFallback = this.normalizeOptionalString(fallbackModel);
                        if (!normalizedModel || !normalizedFallback || normalizedModel === normalizedFallback) {
                            return [2 /*return*/];
                        }
                        now = Date.now();
                        CodexClient.modelFallbackPreferences.set(normalizedModel, {
                            fallbackModel: normalizedFallback,
                            expiresAt: now + this.modelUnavailableTtlMs,
                            updatedAt: now
                        });
                        this.pruneModelFallbackPreferences(now);
                        return [4 /*yield*/, this.persistModelFallbackPreferences()];
                    case 1:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.clearModelFallbackPreference = function (model) {
        return __awaiter(this, void 0, void 0, function () {
            var normalizedModel;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        normalizedModel = this.normalizeOptionalString(model);
                        if (!normalizedModel) {
                            return [2 /*return*/];
                        }
                        if (!CodexClient.modelFallbackPreferences.has(normalizedModel)) {
                            return [2 /*return*/];
                        }
                        CodexClient.modelFallbackPreferences.delete(normalizedModel);
                        return [4 /*yield*/, this.persistModelFallbackPreferences()];
                    case 1:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.persistModelFallbackPreferences = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _a, serialized, _b;
            return __generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        this.pruneModelFallbackPreferences();
                        if (!!CodexClient.modelFallbackPreferences.size) return [3 /*break*/, 5];
                        _c.label = 1;
                    case 1:
                        _c.trys.push([1, 3, , 4]);
                        return [4 /*yield*/, fs_1.promises.unlink(CodexClient.MODEL_UNAVAILABLE_FALLBACK_FILE)];
                    case 2:
                        _c.sent();
                        return [3 /*break*/, 4];
                    case 3:
                        _a = _c.sent();
                        return [3 /*break*/, 4];
                    case 4: return [2 /*return*/];
                    case 5:
                        serialized = {};
                        CodexClient.modelFallbackPreferences.forEach(function (entry, model) {
                            serialized[model] = entry;
                        });
                        _c.label = 6;
                    case 6:
                        _c.trys.push([6, 8, , 9]);
                        return [4 /*yield*/, fs_1.promises.writeFile(CodexClient.MODEL_UNAVAILABLE_FALLBACK_FILE, JSON.stringify(serialized), 'utf8')];
                    case 7:
                        _c.sent();
                        return [3 /*break*/, 9];
                    case 8:
                        _b = _c.sent();
                        return [3 /*break*/, 9];
                    case 9: return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.sleep = function (ms) {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, (0, promises_1.setTimeout)(ms)];
                    case 1:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.ensureCodex = function () {
        return __awaiter(this, void 0, void 0, function () {
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (this.codex) {
                            return [2 /*return*/];
                        }
                        if (!(this.codexInit !== null)) return [3 /*break*/, 2];
                        return [4 /*yield*/, this.codexInit];
                    case 1:
                        _a.sent();
                        return [2 /*return*/];
                    case 2:
                        this.codexInit = (function () { return __awaiter(_this, void 0, void 0, function () {
                            var importer, mod, CodexCtor, env;
                            var _a;
                            return __generator(this, function (_b) {
                                switch (_b.label) {
                                    case 0:
                                        this.log('Loading AI SDK module...');
                                        importer = new Function('specifier', 'return import(specifier)');
                                        return [4 /*yield*/, importer('@openai/codex-sdk')];
                                    case 1:
                                        mod = _b.sent();
                                        CodexCtor = (mod === null || mod === void 0 ? void 0 : mod.Codex) || ((_a = mod === null || mod === void 0 ? void 0 : mod.default) === null || _a === void 0 ? void 0 : _a.Codex) || (mod === null || mod === void 0 ? void 0 : mod.default) || mod;
                                        if (!CodexCtor) {
                                            throw new Error('AI SDK export not found.');
                                        }
                                        this.log('AI SDK module loaded.');
                                        return [4 /*yield*/, this.buildCodexEnv()];
                                    case 2:
                                        env = _b.sent();
                                        this.codex = new CodexCtor({
                                            apiKey: this.config.apiKey,
                                            baseUrl: this.config.baseUrl,
                                            model: this.config.model,
                                            env: env
                                        });
                                        this.log('AI client initialized.');
                                        return [2 /*return*/];
                                }
                            });
                        }); })();
                        return [4 /*yield*/, this.codexInit];
                    case 3:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.log = function (message) {
        if (!this.debugEnabled) {
            return;
        }
        console.log("[AI-Dashboard][AI] ".concat(message));
    };
    CodexClient.prototype.resolveDefaultTimeoutMs = function () {
        var raw = Number(process.env.AI_DASHBOARD_CODEX_TIMEOUT_MS || process.env.AI_DASHBOARD_AGENT_TIMEOUT_MS);
        if (Number.isFinite(raw) && raw > 0) {
            return Math.floor(raw);
        }
        return 600000;
    };
    CodexClient.prototype.resolveStreamEnabled = function () {
        var raw = (process.env.AI_DASHBOARD_CODEX_STREAM || '').trim().toLowerCase();
        if (!raw) {
            return this.debugEnabled;
        }
        if (['true', '1', 'yes', 'y', 'on'].includes(raw)) {
            return true;
        }
        if (['false', '0', 'no', 'n', 'off'].includes(raw)) {
            return false;
        }
        return this.debugEnabled;
    };
    CodexClient.prototype.resolveCleanZdotdirEnabled = function () {
        var _a;
        var raw = ((_a = process.env.AI_DASHBOARD_CODEX_CLEAN_ZDOTDIR) !== null && _a !== void 0 ? _a : '').trim().toLowerCase();
        if (!raw) {
            return true;
        }
        if (['false', '0', 'no', 'n', 'off'].includes(raw)) {
            return false;
        }
        if (['true', '1', 'yes', 'y', 'on'].includes(raw)) {
            return true;
        }
        return true;
    };
    CodexClient.prototype.buildCodexEnv = function () {
        return __awaiter(this, void 0, void 0, function () {
            var env, _a, _b, _c, key, value, fallbackHome, _d;
            var e_3, _e;
            return __generator(this, function (_f) {
                switch (_f.label) {
                    case 0:
                        env = {};
                        try {
                            for (_a = __values(Object.entries(process.env)), _b = _a.next(); !_b.done; _b = _a.next()) {
                                _c = __read(_b.value, 2), key = _c[0], value = _c[1];
                                if (typeof value === 'string') {
                                    env[key] = value;
                                }
                            }
                        }
                        catch (e_3_1) { e_3 = { error: e_3_1 }; }
                        finally {
                            try {
                                if (_b && !_b.done && (_e = _a.return)) _e.call(_a);
                            }
                            finally { if (e_3) throw e_3.error; }
                        }
                        if (!this.normalizeOptionalString(env.HOME)) {
                            fallbackHome = this.normalizeOptionalString(process.env.HOME || os.homedir());
                            if (fallbackHome) {
                                env.HOME = fallbackHome;
                            }
                        }
                        return [4 /*yield*/, this.ensureCodexHome(env)];
                    case 1:
                        _f.sent();
                        if (!this.cleanZdotdirEnabled) return [3 /*break*/, 3];
                        _d = env;
                        return [4 /*yield*/, this.ensureZdotdir()];
                    case 2:
                        _d.ZDOTDIR = _f.sent();
                        _f.label = 3;
                    case 3: return [2 /*return*/, env];
                }
            });
        });
    };
    CodexClient.prototype.ensureCodexHome = function (env) {
        return __awaiter(this, void 0, void 0, function () {
            var current, homeRoot, primary, _a, fallback;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        current = this.normalizeOptionalString(env.CODEX_HOME || process.env.CODEX_HOME);
                        homeRoot = this.normalizeOptionalString(env.HOME || process.env.HOME || os.homedir());
                        primary = current || (homeRoot ? path.join(homeRoot, '.codex') : path.join(os.tmpdir(), 'resolveio-codex-home'));
                        _b.label = 1;
                    case 1:
                        _b.trys.push([1, 3, , 5]);
                        return [4 /*yield*/, fs_1.promises.mkdir(path.join(primary, 'sessions'), { recursive: true })];
                    case 2:
                        _b.sent();
                        env.CODEX_HOME = primary;
                        process.env.CODEX_HOME = primary;
                        return [2 /*return*/];
                    case 3:
                        _a = _b.sent();
                        fallback = path.join(os.tmpdir(), 'resolveio-codex-home');
                        return [4 /*yield*/, fs_1.promises.mkdir(path.join(fallback, 'sessions'), { recursive: true })];
                    case 4:
                        _b.sent();
                        env.CODEX_HOME = fallback;
                        process.env.CODEX_HOME = fallback;
                        return [3 /*break*/, 5];
                    case 5: return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.prototype.ensureZdotdir = function () {
        return __awaiter(this, void 0, void 0, function () {
            var override, dir;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        if (this.zDotDir) {
                            return [2 /*return*/, this.zDotDir];
                        }
                        override = (process.env.AI_DASHBOARD_CODEX_ZDOTDIR || '').trim();
                        dir = override || path.join(os.tmpdir(), 'codex-zdotdir');
                        return [4 /*yield*/, fs_1.promises.mkdir(dir, { recursive: true })];
                    case 1:
                        _a.sent();
                        return [4 /*yield*/, Promise.allSettled([
                                fs_1.promises.writeFile(path.join(dir, '.zshrc'), '', { flag: 'a' }),
                                fs_1.promises.writeFile(path.join(dir, '.zprofile'), '', { flag: 'a' })
                            ])];
                    case 2:
                        _a.sent();
                        this.zDotDir = dir;
                        return [2 /*return*/, dir];
                }
            });
        });
    };
    CodexClient.prototype.resolvePingEnabled = function () {
        return this.normalizeBoolean(process.env.AI_DASHBOARD_CODEX_PING, false);
    };
    CodexClient.prototype.resolvePingTimeoutMs = function () {
        var raw = Number(process.env.AI_DASHBOARD_CODEX_PING_TIMEOUT_MS);
        if (Number.isFinite(raw) && raw > 0) {
            return Math.floor(raw);
        }
        return 10000;
    };
    CodexClient.prototype.resolveDefaultThreadOptions = function () {
        var approvalPolicy = this.normalizeApprovalPolicy(process.env.AI_DASHBOARD_CODEX_APPROVAL_POLICY);
        var sandboxMode = this.normalizeSandboxMode(process.env.AI_DASHBOARD_CODEX_SANDBOX_MODE, 'workspace-write');
        var skipGitRepoCheck = this.normalizeBoolean(process.env.AI_DASHBOARD_CODEX_SKIP_GIT_CHECK, true);
        var webSearchMode = this.normalizeWebSearchMode(process.env.AI_DASHBOARD_CODEX_WEB_SEARCH_MODE);
        var webSearchEnabled = this.normalizeBoolean(process.env.AI_DASHBOARD_CODEX_WEB_SEARCH_ENABLED, false);
        var networkAccessEnabled = this.normalizeBoolean(process.env.AI_DASHBOARD_CODEX_NETWORK_ACCESS_ENABLED, false);
        var modelReasoningEffort = this.normalizeModelReasoningEffort(process.env.AI_DASHBOARD_CODEX_REASONING_EFFORT);
        return {
            model: this.config.model,
            approvalPolicy: approvalPolicy,
            sandboxMode: sandboxMode,
            skipGitRepoCheck: skipGitRepoCheck,
            webSearchMode: webSearchMode,
            webSearchEnabled: webSearchEnabled,
            networkAccessEnabled: networkAccessEnabled,
            modelReasoningEffort: modelReasoningEffort
        };
    };
    CodexClient.prototype.mergeThreadOptions = function (overrides) {
        var merged = __assign(__assign({}, this.defaultThreadOptions), (overrides || {}));
        var effectiveModel = this.normalizeOptionalString(merged.model || this.config.model);
        var normalizedEffort = this.normalizeModelReasoningEffortForModel(effectiveModel, merged.modelReasoningEffort);
        if (normalizedEffort && normalizedEffort !== merged.modelReasoningEffort) {
            this.log("normalized reasoning effort for model=".concat(effectiveModel || 'default', ": ").concat(merged.modelReasoningEffort, " -> ").concat(normalizedEffort));
            merged.modelReasoningEffort = normalizedEffort;
        }
        var cleaned = Object.entries(merged).reduce(function (acc, _a) {
            var _b = __read(_a, 2), key = _b[0], value = _b[1];
            if (value === undefined || value === null || value === '') {
                return acc;
            }
            acc[key] = value;
            return acc;
        }, {});
        return Object.keys(cleaned).length ? cleaned : undefined;
    };
    CodexClient.prototype.normalizeApprovalPolicy = function (value) {
        var normalized = (value || '').trim().toLowerCase();
        if (normalized === 'never' || normalized === 'on-request' || normalized === 'on-failure' || normalized === 'untrusted') {
            return normalized;
        }
        return 'never';
    };
    CodexClient.prototype.normalizeSandboxMode = function (value, fallback) {
        if (fallback === void 0) { fallback = 'read-only'; }
        var normalized = (value || '').trim().toLowerCase();
        if (normalized === 'read-only' || normalized === 'workspace-write' || normalized === 'danger-full-access') {
            return normalized;
        }
        return fallback;
    };
    CodexClient.prototype.normalizeWebSearchMode = function (value) {
        var normalized = (value || '').trim().toLowerCase();
        if (normalized === 'disabled' || normalized === 'cached' || normalized === 'live') {
            return normalized;
        }
        return undefined;
    };
    CodexClient.prototype.normalizeModelReasoningEffort = function (value) {
        var normalized = (value || '').trim().toLowerCase();
        if (normalized === 'minimal' || normalized === 'none' || normalized === 'low' || normalized === 'medium' || normalized === 'high' || normalized === 'xhigh') {
            return normalized;
        }
        return undefined;
    };
    CodexClient.prototype.normalizeModelReasoningEffortForModel = function (model, effort) {
        if (!effort) {
            return effort;
        }
        var normalizedModel = this.normalizeOptionalString(model).toLowerCase();
        if (effort === 'minimal' && (!normalizedModel || normalizedModel.startsWith('gpt-5') || normalizedModel.includes('codex'))) {
            return 'low';
        }
        return effort;
    };
    CodexClient.prototype.normalizeBoolean = function (value, fallback) {
        if (!value) {
            return fallback;
        }
        var normalized = value.trim().toLowerCase();
        if (['true', '1', 'yes', 'y', 'on'].includes(normalized)) {
            return true;
        }
        if (['false', '0', 'no', 'n', 'off'].includes(normalized)) {
            return false;
        }
        return fallback;
    };
    CodexClient.prototype.formatThreadOptions = function (options) {
        var summary = {};
        Object.entries(options).forEach(function (_a) {
            var _b = __read(_a, 2), key = _b[0], value = _b[1];
            if (value === undefined || value === null) {
                return;
            }
            summary[key] = String(value);
        });
        return JSON.stringify(summary);
    };
    CodexClient.prototype.buildThreadOptionsKey = function (options) {
        if (!options) {
            return '';
        }
        var ordered = {};
        Object.keys(options)
            .sort()
            .forEach(function (key) {
            var value = options[key];
            if (value === undefined || value === null) {
                return;
            }
            ordered[key] = Array.isArray(value) ? JSON.stringify(value) : String(value);
        });
        return JSON.stringify(ordered);
    };
    CodexClient.prototype.buildThreadCacheKey = function (threadKey, options) {
        if (threadKey) {
            return "thread:".concat(threadKey);
        }
        var model = (options === null || options === void 0 ? void 0 : options.model) || this.config.model;
        var workingDirectory = options === null || options === void 0 ? void 0 : options.workingDirectory;
        if (!model && !workingDirectory) {
            return null;
        }
        return "thread:auto:".concat(model || 'default', ":").concat(workingDirectory || 'root');
    };
    CodexClient.prototype.isPingPrompt = function (prompt) {
        return prompt.trim() === CodexClient.PING_PROMPT;
    };
    CodexClient.prototype.runPing = function (threadOptions) {
        return __awaiter(this, void 0, void 0, function () {
            var content, trimmed, preview, error_7, message;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        this.log("runPing start (timeoutMs=".concat(this.pingTimeoutMs, ")"));
                        _a.label = 1;
                    case 1:
                        _a.trys.push([1, 3, , 4]);
                        return [4 /*yield*/, this.runOnce(CodexClient.PING_PROMPT, {
                                timeoutMs: this.pingTimeoutMs,
                                threadOptions: threadOptions,
                                reuseThread: false
                            })];
                    case 2:
                        content = _a.sent();
                        trimmed = content.trim();
                        preview = trimmed.length > 80 ? "".concat(trimmed.slice(0, 80), "\u2026") : trimmed;
                        this.log("runPing response: ".concat(preview));
                        return [3 /*break*/, 4];
                    case 3:
                        error_7 = _a.sent();
                        message = error_7 instanceof Error ? error_7.message : String(error_7 || 'Unknown error');
                        this.log("runPing failed: ".concat(message));
                        throw error_7;
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    CodexClient.PING_PROMPT = "Say 'pong'";
    CodexClient.MODEL_UNAVAILABLE_FALLBACK_FILE = path.join(os.tmpdir(), 'resolveio-codex-model-fallbacks.json');
    CodexClient.DEFAULT_MODEL_UNAVAILABLE_TTL_MS = 6 * 60 * 60 * 1000;
    CodexClient.MIN_MODEL_UNAVAILABLE_TTL_MS = 60 * 1000;
    CodexClient.modelFallbackPreferences = new Map();
    CodexClient.modelFallbackPreferencesLoaded = false;
    CodexClient.modelFallbackPreferencesLoadPromise = null;
    CodexClient.cwdFallbackRunning = false;
    return CodexClient;
}());
exports.CodexClient = CodexClient;

//# sourceMappingURL=codex-client.js.map
