"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 __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.AiAssistantCodexManager = void 0;
var ai_terminal_conversation_collection_1 = require("../collections/ai-terminal-conversation.collection");
var ai_terminal_issue_report_collection_1 = require("../collections/ai-terminal-issue-report.collection");
var ai_terminal_message_collection_1 = require("../collections/ai-terminal-message.collection");
var fs_1 = require("fs");
var os = require("os");
var path = require("path");
var child_process_1 = require("child_process");
var util_1 = require("util");
var DEFAULT_POLL_INTERVAL_MS = 15000;
var DEFAULT_LOOKBACK_MINUTES = 120;
var DEFAULT_MAX_MESSAGES_PER_POLL = 100;
var DEFAULT_MAX_REMEDIATIONS_PER_POLL = 3;
var DEFAULT_REMEDIATION_TIMEOUT_MS = 20 * 60 * 1000;
var DEFAULT_REMEDIATION_MAX_BUFFER_BYTES = 1024 * 1024;
var DEFAULT_REMEDIATION_MAX_ATTEMPTS_PER_ISSUE = 2;
var DEFAULT_REMEDIATION_COOLDOWN_MINUTES = 15;
var DEFAULT_REPLAY_TIMEOUT_MS = 5 * 60 * 1000;
var DEFAULT_REPLAY_MAX_BUFFER_BYTES = 1024 * 1024;
var DEFAULT_REPLAY_MAX_ATTEMPTS_PER_ISSUE = 2;
var DEFAULT_REPLAY_COOLDOWN_MINUTES = 10;
var MAX_STORED_OUTPUT_CHARS = 4000;
var execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
function normalizeOptionalString(value) {
    return typeof value === 'string' ? value.trim() : '';
}
function parseBooleanEnv(value, fallback) {
    var normalized = normalizeOptionalString(value).toLowerCase();
    if (!normalized) {
        return fallback;
    }
    if (['1', 'true', 'yes', 'on', 'enabled'].includes(normalized)) {
        return true;
    }
    if (['0', 'false', 'no', 'off', 'disabled'].includes(normalized)) {
        return false;
    }
    return fallback;
}
function parsePositiveInt(value, fallback, min) {
    if (min === void 0) { min = 1; }
    var parsed = parseInt(String(value !== null && value !== void 0 ? value : '').trim(), 10);
    if (!Number.isFinite(parsed) || Number.isNaN(parsed) || parsed < min) {
        return fallback;
    }
    return parsed;
}
function parsePositiveIntWithMax(value, fallback, min, max) {
    var parsed = parsePositiveInt(value, fallback, min);
    return Math.min(parsed, max);
}
function resolveEnabledFlag() {
    var _a;
    var explicitValue = (_a = process.env.AI_ASSISTANT_CODEX_MANAGER_ENABLED) !== null && _a !== void 0 ? _a : process.env.AI_ASSISTANT_QUALITY_MANAGER_ENABLED;
    if (explicitValue !== undefined && explicitValue !== null && String(explicitValue).trim() !== '') {
        return parseBooleanEnv(explicitValue, false);
    }
    return false;
}
var AiAssistantCodexManager = /** @class */ (function () {
    function AiAssistantCodexManager(config, runtime) {
        this._interval = null;
        this._inFlight = false;
        this._cursorMessageId = '';
        this.config = config;
        this.runtime = runtime;
        this._cursorCreatedAt = new Date(Date.now() - (config.lookbackMinutes * 60 * 1000));
    }
    AiAssistantCodexManager.createIfEnabled = function (runtime) {
        var config = this.resolveConfig();
        if (!config.enabled) {
            return null;
        }
        if (!this.shouldRunOnCurrentProcess(config, runtime)) {
            return null;
        }
        var manager = new AiAssistantCodexManager(config, runtime);
        manager.initialize();
        return manager;
    };
    AiAssistantCodexManager.resolveConfig = function () {
        var targetWorkerIndex = normalizeOptionalString(process.env.AI_ASSISTANT_CODEX_MANAGER_WORKER_INDEX
            || process.env.AI_ASSISTANT_CODEX_WORKER_INDEX
            || process.env.CODEX_WORKER_INDEX
            || 'ai-assistant-manager') || 'ai-assistant-manager';
        var targetWorkerInstance = normalizeOptionalString(process.env.AI_ASSISTANT_CODEX_MANAGER_WORKER_INSTANCE) || null;
        return {
            enabled: resolveEnabledFlag(),
            runOnAnyWorker: parseBooleanEnv(process.env.AI_ASSISTANT_CODEX_MANAGER_RUN_ANY_WORKER, false),
            targetWorkerIndex: targetWorkerIndex,
            targetWorkerInstance: targetWorkerInstance,
            pollIntervalMs: parsePositiveInt(process.env.AI_ASSISTANT_CODEX_MANAGER_INTERVAL_MS, DEFAULT_POLL_INTERVAL_MS, 1000),
            lookbackMinutes: parsePositiveInt(process.env.AI_ASSISTANT_CODEX_MANAGER_LOOKBACK_MINUTES, DEFAULT_LOOKBACK_MINUTES, 1),
            maxMessagesPerPoll: parsePositiveIntWithMax(process.env.AI_ASSISTANT_CODEX_MANAGER_MAX_MESSAGES_PER_POLL, DEFAULT_MAX_MESSAGES_PER_POLL, 1, 1000),
            maxRemediationsPerPoll: parsePositiveIntWithMax(process.env.AI_ASSISTANT_CODEX_MANAGER_MAX_REMEDIATIONS_PER_POLL, DEFAULT_MAX_REMEDIATIONS_PER_POLL, 1, 100),
            autoReportEnabled: parseBooleanEnv(process.env.AI_ASSISTANT_CODEX_MANAGER_AUTO_REPORT, true),
            autoRemediationEnabled: parseBooleanEnv(process.env.AI_ASSISTANT_CODEX_MANAGER_AUTO_REMEDIATE, false),
            remediationHookPath: normalizeOptionalString(process.env.AI_ASSISTANT_CODEX_MANAGER_REMEDIATE_HOOK),
            remediationTimeoutMs: parsePositiveInt(process.env.AI_ASSISTANT_CODEX_MANAGER_REMEDIATE_TIMEOUT_MS, DEFAULT_REMEDIATION_TIMEOUT_MS, 1000),
            remediationMaxBufferBytes: parsePositiveInt(process.env.AI_ASSISTANT_CODEX_MANAGER_REMEDIATE_MAX_BUFFER_BYTES, DEFAULT_REMEDIATION_MAX_BUFFER_BYTES, 1024),
            remediationMaxAttemptsPerIssue: parsePositiveInt(process.env.AI_ASSISTANT_CODEX_MANAGER_REMEDIATE_MAX_ATTEMPTS_PER_ISSUE, DEFAULT_REMEDIATION_MAX_ATTEMPTS_PER_ISSUE, 1),
            remediationCooldownMinutes: parsePositiveInt(process.env.AI_ASSISTANT_CODEX_MANAGER_REMEDIATE_COOLDOWN_MINUTES, DEFAULT_REMEDIATION_COOLDOWN_MINUTES, 1),
            autoReplayEnabled: parseBooleanEnv(process.env.AI_ASSISTANT_CODEX_MANAGER_REPLAY_ENABLED, false),
            replayCommand: normalizeOptionalString(process.env.AI_ASSISTANT_CODEX_MANAGER_REPLAY_COMMAND),
            replayTimeoutMs: parsePositiveInt(process.env.AI_ASSISTANT_CODEX_MANAGER_REPLAY_TIMEOUT_MS, DEFAULT_REPLAY_TIMEOUT_MS, 1000),
            replayMaxBufferBytes: parsePositiveInt(process.env.AI_ASSISTANT_CODEX_MANAGER_REPLAY_MAX_BUFFER_BYTES, DEFAULT_REPLAY_MAX_BUFFER_BYTES, 1024),
            replayMaxAttemptsPerIssue: parsePositiveInt(process.env.AI_ASSISTANT_CODEX_MANAGER_REPLAY_MAX_ATTEMPTS_PER_ISSUE, DEFAULT_REPLAY_MAX_ATTEMPTS_PER_ISSUE, 1),
            replayCooldownMinutes: parsePositiveInt(process.env.AI_ASSISTANT_CODEX_MANAGER_REPLAY_COOLDOWN_MINUTES, DEFAULT_REPLAY_COOLDOWN_MINUTES, 1),
            debug: parseBooleanEnv(process.env.AI_ASSISTANT_CODEX_MANAGER_DEBUG, false)
        };
    };
    AiAssistantCodexManager.shouldRunOnCurrentProcess = function (config, runtime) {
        var workerIndex = normalizeOptionalString(runtime.workerIndex);
        var workerInstance = normalizeOptionalString(runtime.workerInstance);
        if (!runtime.isWorkersEnabled) {
            return true;
        }
        if (!runtime.isWorkerInstance) {
            return false;
        }
        if (config.runOnAnyWorker) {
            if (config.targetWorkerInstance) {
                return workerInstance === config.targetWorkerInstance;
            }
            return true;
        }
        if (workerIndex !== config.targetWorkerIndex) {
            return false;
        }
        if (config.targetWorkerInstance && workerInstance !== config.targetWorkerInstance) {
            return false;
        }
        return true;
    };
    AiAssistantCodexManager.prototype.initialize = function () {
        var _this = this;
        console.log(new Date(), '[AI Assistant Codex Manager] started', {
            workerIndex: process.env.WORKER_INDEX || null,
            workerInstance: process.env.NODE_APP_INSTANCE || null,
            pollIntervalMs: this.config.pollIntervalMs,
            maxMessagesPerPoll: this.config.maxMessagesPerPoll,
            lookbackMinutes: this.config.lookbackMinutes,
            autoRemediationEnabled: this.config.autoRemediationEnabled,
            remediationHookPath: this.config.remediationHookPath || null,
            autoReplayEnabled: this.config.autoReplayEnabled
        });
        setTimeout(function () { return __awaiter(_this, void 0, void 0, function () {
            var error_1;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 2, , 3]);
                        return [4 /*yield*/, this.pollOnce()];
                    case 1:
                        _a.sent();
                        return [3 /*break*/, 3];
                    case 2:
                        error_1 = _a.sent();
                        console.error(new Date(), '[AI Assistant Codex Manager] initial poll failed', error_1);
                        return [3 /*break*/, 3];
                    case 3: return [2 /*return*/];
                }
            });
        }); }, 2500);
        this._interval = setInterval(function () { return __awaiter(_this, void 0, void 0, function () {
            var error_2;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 2, , 3]);
                        return [4 /*yield*/, this.pollOnce()];
                    case 1:
                        _a.sent();
                        return [3 /*break*/, 3];
                    case 2:
                        error_2 = _a.sent();
                        console.error(new Date(), '[AI Assistant Codex Manager] poll failed', error_2);
                        return [3 /*break*/, 3];
                    case 3: return [2 /*return*/];
                }
            });
        }); }, this.config.pollIntervalMs);
    };
    AiAssistantCodexManager.prototype.pollOnce = function () {
        return __awaiter(this, void 0, void 0, function () {
            var query, messages, messages_1, messages_1_1, message, createdAt, e_1_1;
            var e_1, _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        if (this._inFlight) {
                            return [2 /*return*/];
                        }
                        this._inFlight = true;
                        _b.label = 1;
                    case 1:
                        _b.trys.push([1, , 13, 14]);
                        query = {
                            role: 'assistant',
                            $or: [
                                { createdAt: { $gt: this._cursorCreatedAt } },
                                { createdAt: this._cursorCreatedAt, _id: { $gt: this._cursorMessageId || '' } }
                            ]
                        };
                        return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.find(query, {
                                sort: { createdAt: 1, _id: 1 },
                                limit: this.config.maxMessagesPerPoll
                            })];
                    case 2:
                        messages = _b.sent();
                        if (!(Array.isArray(messages) && messages.length)) return [3 /*break*/, 10];
                        _b.label = 3;
                    case 3:
                        _b.trys.push([3, 8, 9, 10]);
                        messages_1 = __values(messages), messages_1_1 = messages_1.next();
                        _b.label = 4;
                    case 4:
                        if (!!messages_1_1.done) return [3 /*break*/, 7];
                        message = messages_1_1.value;
                        createdAt = (message === null || message === void 0 ? void 0 : message.createdAt) ? new Date(message.createdAt) : null;
                        if (createdAt && Number.isFinite(createdAt.getTime())) {
                            this._cursorCreatedAt = createdAt;
                        }
                        this._cursorMessageId = normalizeOptionalString(message === null || message === void 0 ? void 0 : message._id);
                        return [4 /*yield*/, this.processMessage(message)];
                    case 5:
                        _b.sent();
                        _b.label = 6;
                    case 6:
                        messages_1_1 = messages_1.next();
                        return [3 /*break*/, 4];
                    case 7: return [3 /*break*/, 10];
                    case 8:
                        e_1_1 = _b.sent();
                        e_1 = { error: e_1_1 };
                        return [3 /*break*/, 10];
                    case 9:
                        try {
                            if (messages_1_1 && !messages_1_1.done && (_a = messages_1.return)) _a.call(messages_1);
                        }
                        finally { if (e_1) throw e_1.error; }
                        return [7 /*endfinally*/];
                    case 10:
                        if (!this.config.autoRemediationEnabled) return [3 /*break*/, 12];
                        return [4 /*yield*/, this.pollRemediationQueue()];
                    case 11:
                        _b.sent();
                        _b.label = 12;
                    case 12: return [3 /*break*/, 14];
                    case 13:
                        this._inFlight = false;
                        return [7 /*endfinally*/];
                    case 14: return [2 /*return*/];
                }
            });
        });
    };
    AiAssistantCodexManager.prototype.processMessage = function (message) {
        return __awaiter(this, void 0, void 0, function () {
            var messageId, conversationId, metadata, decision, issueReportId;
            var _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        messageId = normalizeOptionalString(message === null || message === void 0 ? void 0 : message._id);
                        conversationId = normalizeOptionalString(message === null || message === void 0 ? void 0 : message.id_conversation);
                        if (!messageId || !conversationId) {
                            return [2 /*return*/];
                        }
                        metadata = this.normalizeMetadata(message === null || message === void 0 ? void 0 : message.metadata);
                        if (metadata.pending === true) {
                            return [2 /*return*/];
                        }
                        if ((_a = metadata.quality_manager) === null || _a === void 0 ? void 0 : _a.checked_at) {
                            return [2 /*return*/];
                        }
                        decision = this.evaluateMessageQuality(message, metadata);
                        issueReportId = '';
                        if (!(decision.status === 'needs_review' && this.config.autoReportEnabled)) return [3 /*break*/, 2];
                        return [4 /*yield*/, this.ensureAutomatedIssueReport(message, decision)];
                    case 1:
                        issueReportId = _b.sent();
                        _b.label = 2;
                    case 2: return [4 /*yield*/, this.markMessageQualityReviewed(messageId, decision, issueReportId)];
                    case 3:
                        _b.sent();
                        if (!(issueReportId && this.config.autoRemediationEnabled)) return [3 /*break*/, 5];
                        return [4 /*yield*/, this.runIssueRemediation(issueReportId, { source: 'auto', trigger: 'message_quality' })];
                    case 4:
                        _b.sent();
                        _b.label = 5;
                    case 5: return [2 /*return*/];
                }
            });
        });
    };
    AiAssistantCodexManager.prototype.evaluateMessageQuality = function (message, metadata) {
        var _a, _b;
        var content = normalizeOptionalString(message === null || message === void 0 ? void 0 : message.content);
        var toolError = normalizeOptionalString((_b = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.tool_execution) === null || _a === void 0 ? void 0 : _a.outcome) === null || _b === void 0 ? void 0 : _b.error);
        if (metadata.failed === true) {
            return {
                status: 'needs_review',
                reason: 'Assistant response finalized in failed state.',
                code: 'metadata_failed'
            };
        }
        if (/I ran into an internal error while preparing that response/i.test(content)) {
            return {
                status: 'needs_review',
                reason: 'Assistant returned internal error text.',
                code: 'internal_error_copy'
            };
        }
        if (/That took longer than expected\./i.test(content)) {
            return {
                status: 'needs_review',
                reason: 'Assistant response timed out.',
                code: 'timeout_copy'
            };
        }
        if (/I could not finish this request within the assistant time budget/i.test(content)) {
            return {
                status: 'needs_review',
                reason: 'Assistant run exceeded configured time budget.',
                code: 'run_budget_exceeded_copy'
            };
        }
        if (toolError) {
            return {
                status: 'needs_review',
                reason: "Assistant tool execution error: ".concat(toolError).slice(0, 500),
                code: 'tool_execution_error'
            };
        }
        return {
            status: 'pass',
            reason: 'Quality check passed.',
            code: 'ok'
        };
    };
    AiAssistantCodexManager.prototype.ensureAutomatedIssueReport = function (message, decision) {
        return __awaiter(this, void 0, void 0, function () {
            var messageId, conversationId, existing, conversation, assistantContent, requestId, userPrompt, now, doc, insertResult, issueId;
            var _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        messageId = normalizeOptionalString(message === null || message === void 0 ? void 0 : message._id);
                        conversationId = normalizeOptionalString(message === null || message === void 0 ? void 0 : message.id_conversation);
                        if (!messageId || !conversationId) {
                            return [2 /*return*/, ''];
                        }
                        return [4 /*yield*/, ai_terminal_issue_report_collection_1.AiTerminalIssueReports.findOne({
                                id_message: messageId,
                                source: 'automated'
                            })];
                    case 1:
                        existing = _b.sent();
                        if (existing === null || existing === void 0 ? void 0 : existing._id) {
                            return [2 /*return*/, normalizeOptionalString(existing._id)];
                        }
                        return [4 /*yield*/, ai_terminal_conversation_collection_1.AiTerminalConversations.findById(conversationId)];
                    case 2:
                        conversation = _b.sent();
                        if (!conversation) {
                            return [2 /*return*/, ''];
                        }
                        assistantContent = normalizeOptionalString(message === null || message === void 0 ? void 0 : message.content);
                        requestId = normalizeOptionalString((_a = message === null || message === void 0 ? void 0 : message.metadata) === null || _a === void 0 ? void 0 : _a.request_id);
                        return [4 /*yield*/, this.resolveClosestUserPrompt(conversationId, message === null || message === void 0 ? void 0 : message.createdAt)];
                    case 3:
                        userPrompt = _b.sent();
                        now = new Date();
                        doc = __assign(__assign(__assign(__assign(__assign(__assign(__assign(__assign({ id_conversation: conversationId, status: 'open', source: 'automated', reason: decision.reason }, (userPrompt ? { user_prompt: userPrompt } : {})), (assistantContent ? { assistant_content: assistantContent } : {})), (requestId ? { request_id: requestId } : {})), { id_message: messageId }), (normalizeOptionalString(conversation === null || conversation === void 0 ? void 0 : conversation.id_client) ? { id_client: normalizeOptionalString(conversation === null || conversation === void 0 ? void 0 : conversation.id_client) } : {})), (normalizeOptionalString(conversation === null || conversation === void 0 ? void 0 : conversation.id_app) ? { id_app: normalizeOptionalString(conversation === null || conversation === void 0 ? void 0 : conversation.id_app) } : {})), (normalizeOptionalString(conversation === null || conversation === void 0 ? void 0 : conversation.id_user) ? { id_user: normalizeOptionalString(conversation === null || conversation === void 0 ? void 0 : conversation.id_user) } : {})), { metadata: {
                                quality_manager: {
                                    code: decision.code,
                                    checked_at: now,
                                    worker_index: normalizeOptionalString(process.env.WORKER_INDEX),
                                    worker_instance: normalizeOptionalString(process.env.NODE_APP_INSTANCE)
                                }
                            }, createdAt: now, updatedAt: now });
                        return [4 /*yield*/, ai_terminal_issue_report_collection_1.AiTerminalIssueReports.insertOne(doc)];
                    case 4:
                        insertResult = _b.sent();
                        issueId = normalizeOptionalString(insertResult === null || insertResult === void 0 ? void 0 : insertResult._id);
                        console.log(new Date(), '[AI Assistant Codex Manager] created automated issue report', {
                            id_issue_report: issueId || null,
                            id_conversation: conversationId,
                            id_message: messageId,
                            code: decision.code
                        });
                        return [2 /*return*/, issueId];
                }
            });
        });
    };
    AiAssistantCodexManager.prototype.pollRemediationQueue = function () {
        return __awaiter(this, void 0, void 0, function () {
            var issues, issues_1, issues_1_1, issue, issueId, remediationResult, e_2_1;
            var e_2, _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0: return [4 /*yield*/, ai_terminal_issue_report_collection_1.AiTerminalIssueReports.find({
                            source: 'automated',
                            status: { $in: ['open', 'triaged'] },
                            $or: [
                                { 'metadata.quality_manager.remediation.status': { $exists: false } },
                                { 'metadata.quality_manager.remediation.status': { $in: ['queued', 'failed', 'skipped'] } }
                            ]
                        }, {
                            sort: { updatedAt: 1, createdAt: 1 },
                            limit: this.config.maxRemediationsPerPoll
                        })];
                    case 1:
                        issues = _b.sent();
                        if (!Array.isArray(issues) || !issues.length) {
                            return [2 /*return*/];
                        }
                        _b.label = 2;
                    case 2:
                        _b.trys.push([2, 7, 8, 9]);
                        issues_1 = __values(issues), issues_1_1 = issues_1.next();
                        _b.label = 3;
                    case 3:
                        if (!!issues_1_1.done) return [3 /*break*/, 6];
                        issue = issues_1_1.value;
                        issueId = normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue._id);
                        if (!issueId) {
                            return [3 /*break*/, 5];
                        }
                        return [4 /*yield*/, this.runIssueRemediation(issueId, { source: 'auto', trigger: 'poll' })];
                    case 4:
                        remediationResult = _b.sent();
                        if ((remediationResult === null || remediationResult === void 0 ? void 0 : remediationResult.status) === 'success' || (remediationResult === null || remediationResult === void 0 ? void 0 : remediationResult.status) === 'running') {
                            return [3 /*break*/, 6];
                        }
                        _b.label = 5;
                    case 5:
                        issues_1_1 = issues_1.next();
                        return [3 /*break*/, 3];
                    case 6: return [3 /*break*/, 9];
                    case 7:
                        e_2_1 = _b.sent();
                        e_2 = { error: e_2_1 };
                        return [3 /*break*/, 9];
                    case 8:
                        try {
                            if (issues_1_1 && !issues_1_1.done && (_a = issues_1.return)) _a.call(issues_1);
                        }
                        finally { if (e_2) throw e_2.error; }
                        return [7 /*endfinally*/];
                    case 9: return [2 /*return*/];
                }
            });
        });
    };
    AiAssistantCodexManager.prototype.runIssueRemediation = function (issueReportId_1) {
        return __awaiter(this, arguments, void 0, function (issueReportId, options) {
            var issueId, issue, force, source, now, metadata, qualityManager, remediation, existingStatus, attemptsUsed, maxAttempts, cooldownMinutes, cooldownMs, lastAttemptAt, ageMs, attemptCount, startedAtMs, contextPath, parsedOutput, execResult, finishedAt, durationMs, stdout, stderr, outputStatus, success, remediationStatus, remediationReason, replayResult, error_3, finishedAt, durationMs, err, stdout, stderr, exitCode, timeoutHit, reason, nextAttemptAt, _a;
            if (options === void 0) { options = {}; }
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        issueId = normalizeOptionalString(issueReportId);
                        if (!issueId) {
                            return [2 /*return*/, {
                                    status: 'failed',
                                    reason: 'Issue report id is required.'
                                }];
                        }
                        if (!this.config.autoRemediationEnabled) {
                            return [2 /*return*/, {
                                    status: 'skipped',
                                    reason: 'Auto remediation is disabled.'
                                }];
                        }
                        if (!this.config.remediationHookPath) {
                            return [2 /*return*/, {
                                    status: 'skipped',
                                    reason: 'Remediation hook path is not configured.'
                                }];
                        }
                        return [4 /*yield*/, ai_terminal_issue_report_collection_1.AiTerminalIssueReports.findById(issueId)];
                    case 1:
                        issue = _b.sent();
                        if (!issue) {
                            return [2 /*return*/, {
                                    status: 'not_found',
                                    reason: 'Issue report not found.'
                                }];
                        }
                        force = options.force === true;
                        source = options.source === 'manual' ? 'manual' : 'auto';
                        now = new Date();
                        metadata = this.normalizeMetadata(issue.metadata);
                        qualityManager = this.normalizeMetadata(metadata.quality_manager);
                        remediation = this.normalizeMetadata(qualityManager.remediation);
                        existingStatus = normalizeOptionalString(remediation.status).toLowerCase();
                        attemptsUsed = Number.isFinite(Number(remediation.attempt_count)) ? Number(remediation.attempt_count) : 0;
                        maxAttempts = this.config.remediationMaxAttemptsPerIssue;
                        cooldownMinutes = this.config.remediationCooldownMinutes;
                        cooldownMs = cooldownMinutes * 60 * 1000;
                        lastAttemptAt = this.parseDate(remediation.last_attempt_at);
                        if (!force && existingStatus === 'running') {
                            return [2 /*return*/, {
                                    status: 'running',
                                    reason: 'Remediation already running.',
                                    issueId: issueId
                                }];
                        }
                        if (!force && maxAttempts > 0 && attemptsUsed >= maxAttempts) {
                            return [2 /*return*/, {
                                    status: 'skipped',
                                    reason: "Remediation attempt budget reached (".concat(attemptsUsed, "/").concat(maxAttempts, ")."),
                                    issueId: issueId
                                }];
                        }
                        if (!force && existingStatus === 'failed' && lastAttemptAt) {
                            ageMs = now.getTime() - lastAttemptAt.getTime();
                            if (ageMs >= 0 && ageMs < cooldownMs) {
                                return [2 /*return*/, {
                                        status: 'skipped',
                                        reason: 'Remediation cooldown active.',
                                        issueId: issueId,
                                        nextAttemptAt: new Date(lastAttemptAt.getTime() + cooldownMs)
                                    }];
                            }
                        }
                        attemptCount = attemptsUsed + 1;
                        return [4 /*yield*/, ai_terminal_issue_report_collection_1.AiTerminalIssueReports.updateOne({ _id: issueId }, {
                                $set: {
                                    'metadata.quality_manager.remediation': __assign(__assign({}, remediation), { status: 'running', source: source, trigger: normalizeOptionalString(options.trigger) || 'unspecified', attempt_count: attemptCount, max_attempts: maxAttempts, cooldown_minutes: cooldownMinutes, hook: this.config.remediationHookPath, last_attempt_at: now, updated_at: now, last_error: '', last_exit_code: null }),
                                    updatedAt: now
                                }
                            })];
                    case 2:
                        _b.sent();
                        startedAtMs = Date.now();
                        return [4 /*yield*/, this.writeRemediationContextFile(issue, {
                                issueId: issueId,
                                attemptCount: attemptCount,
                                source: source,
                                trigger: normalizeOptionalString(options.trigger) || 'unspecified'
                            })];
                    case 3:
                        contextPath = _b.sent();
                        parsedOutput = null;
                        _b.label = 4;
                    case 4:
                        _b.trys.push([4, 9, 11, 16]);
                        return [4 /*yield*/, execFileAsync(this.config.remediationHookPath, [contextPath], {
                                timeout: this.config.remediationTimeoutMs,
                                maxBuffer: this.config.remediationMaxBufferBytes,
                                env: __assign(__assign({}, process.env), { RIO_AI_ASSISTANT_REMEDIATION_CONTEXT: contextPath, RIO_AI_ASSISTANT_REMEDIATION_ISSUE_ID: issueId })
                            })];
                    case 5:
                        execResult = _b.sent();
                        finishedAt = new Date();
                        durationMs = Date.now() - startedAtMs;
                        stdout = this.toSafeOutput(execResult === null || execResult === void 0 ? void 0 : execResult.stdout);
                        stderr = this.toSafeOutput(execResult === null || execResult === void 0 ? void 0 : execResult.stderr);
                        parsedOutput = this.parseOutputJson(stdout);
                        outputStatus = normalizeOptionalString(parsedOutput === null || parsedOutput === void 0 ? void 0 : parsedOutput.status).toLowerCase();
                        success = outputStatus ? ['success', 'ok', 'completed', 'pass'].includes(outputStatus) : true;
                        remediationStatus = success ? 'success' : 'failed';
                        remediationReason = normalizeOptionalString(parsedOutput === null || parsedOutput === void 0 ? void 0 : parsedOutput.reason)
                            || (success ? 'Remediation hook completed successfully.' : 'Remediation hook reported a non-success status.');
                        return [4 /*yield*/, ai_terminal_issue_report_collection_1.AiTerminalIssueReports.updateOne({ _id: issueId }, {
                                $set: __assign(__assign({ 'metadata.quality_manager.remediation': __assign(__assign({}, remediation), { status: remediationStatus, source: source, trigger: normalizeOptionalString(options.trigger) || 'unspecified', attempt_count: attemptCount, max_attempts: maxAttempts, cooldown_minutes: cooldownMinutes, hook: this.config.remediationHookPath, last_attempt_at: now, last_success_at: success ? finishedAt : remediation.last_success_at, last_error: success ? '' : remediationReason, last_exit_code: success ? 0 : null, last_duration_ms: durationMs, last_stdout: stdout, last_stderr: stderr, last_output: parsedOutput || undefined, updated_at: finishedAt }) }, (success ? { status: 'triaged' } : {})), { updatedAt: finishedAt })
                            })];
                    case 6:
                        _b.sent();
                        replayResult = null;
                        if (!(success && this.config.autoReplayEnabled)) return [3 /*break*/, 8];
                        return [4 /*yield*/, this.runIssueReplay(issueId, {
                                source: source,
                                trigger: normalizeOptionalString(options.trigger) || 'post_remediation'
                            })];
                    case 7:
                        replayResult = _b.sent();
                        _b.label = 8;
                    case 8:
                        console.log(new Date(), '[AI Assistant Codex Manager] remediation completed', {
                            id_issue_report: issueId,
                            status: remediationStatus,
                            attempt: attemptCount,
                            durationMs: durationMs,
                            replayStatus: (replayResult === null || replayResult === void 0 ? void 0 : replayResult.status) || null
                        });
                        return [2 /*return*/, {
                                status: remediationStatus,
                                reason: remediationReason,
                                issueId: issueId,
                                attemptCount: attemptCount,
                                durationMs: durationMs,
                                replayStatus: (replayResult === null || replayResult === void 0 ? void 0 : replayResult.status) || '',
                                replayReason: (replayResult === null || replayResult === void 0 ? void 0 : replayResult.reason) || ''
                            }];
                    case 9:
                        error_3 = _b.sent();
                        finishedAt = new Date();
                        durationMs = Date.now() - startedAtMs;
                        err = error_3 || {};
                        stdout = this.toSafeOutput(err.stdout);
                        stderr = this.toSafeOutput(err.stderr);
                        exitCode = Number.isFinite(Number(err.code)) ? Number(err.code) : null;
                        timeoutHit = (err === null || err === void 0 ? void 0 : err.killed) === true || normalizeOptionalString(err === null || err === void 0 ? void 0 : err.signal).toUpperCase() === 'SIGTERM';
                        reason = timeoutHit
                            ? "Remediation hook timed out after ".concat(this.config.remediationTimeoutMs, "ms.")
                            : (normalizeOptionalString(err === null || err === void 0 ? void 0 : err.message) || 'Remediation hook failed.');
                        nextAttemptAt = new Date(finishedAt.getTime() + cooldownMs);
                        return [4 /*yield*/, ai_terminal_issue_report_collection_1.AiTerminalIssueReports.updateOne({ _id: issueId }, {
                                $set: {
                                    'metadata.quality_manager.remediation': __assign(__assign({}, remediation), { status: 'failed', source: source, trigger: normalizeOptionalString(options.trigger) || 'unspecified', attempt_count: attemptCount, max_attempts: maxAttempts, cooldown_minutes: cooldownMinutes, hook: this.config.remediationHookPath, last_attempt_at: now, last_error: reason, last_exit_code: exitCode, last_duration_ms: durationMs, last_stdout: stdout, last_stderr: stderr, last_output: parsedOutput || undefined, next_attempt_at: nextAttemptAt, updated_at: finishedAt }),
                                    updatedAt: finishedAt
                                }
                            })];
                    case 10:
                        _b.sent();
                        console.error(new Date(), '[AI Assistant Codex Manager] remediation failed', {
                            id_issue_report: issueId,
                            attempt: attemptCount,
                            reason: reason,
                            exitCode: exitCode,
                            durationMs: durationMs
                        });
                        return [2 /*return*/, {
                                status: 'failed',
                                reason: reason,
                                issueId: issueId,
                                attemptCount: attemptCount,
                                durationMs: durationMs,
                                exitCode: exitCode
                            }];
                    case 11:
                        if (!contextPath) return [3 /*break*/, 15];
                        _b.label = 12;
                    case 12:
                        _b.trys.push([12, 14, , 15]);
                        return [4 /*yield*/, fs_1.promises.unlink(contextPath)];
                    case 13:
                        _b.sent();
                        return [3 /*break*/, 15];
                    case 14:
                        _a = _b.sent();
                        return [3 /*break*/, 15];
                    case 15: return [7 /*endfinally*/];
                    case 16: return [2 /*return*/];
                }
            });
        });
    };
    AiAssistantCodexManager.prototype.runIssueReplay = function (issueReportId_1) {
        return __awaiter(this, arguments, void 0, function (issueReportId, options) {
            var issueId, source, issue, force, now, metadata, qualityManager, replay, existingStatus, attemptsUsed, maxAttempts, cooldownMinutes, cooldownMs, lastAttemptAt, ageMs, attemptCount, startedAtMs, contextPath, parsedOutput, execResult, finishedAt, durationMs, stdout, stderr, outputStatus, success, replayStatus, replayReason, error_4, finishedAt, durationMs, err, stdout, stderr, exitCode, timeoutHit, reason, nextAttemptAt, _a;
            if (options === void 0) { options = {}; }
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        issueId = normalizeOptionalString(issueReportId);
                        if (!issueId) {
                            return [2 /*return*/, {
                                    status: 'failed',
                                    reason: 'Issue report id is required.'
                                }];
                        }
                        source = options.source === 'manual' ? 'manual' : 'auto';
                        if (!this.config.autoReplayEnabled && source !== 'manual') {
                            return [2 /*return*/, {
                                    status: 'skipped',
                                    reason: 'Auto replay is disabled.'
                                }];
                        }
                        if (!this.config.replayCommand) {
                            return [2 /*return*/, {
                                    status: 'skipped',
                                    reason: 'Replay command is not configured.'
                                }];
                        }
                        return [4 /*yield*/, ai_terminal_issue_report_collection_1.AiTerminalIssueReports.findById(issueId)];
                    case 1:
                        issue = _b.sent();
                        if (!issue) {
                            return [2 /*return*/, {
                                    status: 'not_found',
                                    reason: 'Issue report not found.'
                                }];
                        }
                        force = options.force === true;
                        now = new Date();
                        metadata = this.normalizeMetadata(issue.metadata);
                        qualityManager = this.normalizeMetadata(metadata.quality_manager);
                        replay = this.normalizeMetadata(qualityManager.replay);
                        existingStatus = normalizeOptionalString(replay.status).toLowerCase();
                        attemptsUsed = Number.isFinite(Number(replay.attempt_count)) ? Number(replay.attempt_count) : 0;
                        maxAttempts = this.config.replayMaxAttemptsPerIssue;
                        cooldownMinutes = this.config.replayCooldownMinutes;
                        cooldownMs = cooldownMinutes * 60 * 1000;
                        lastAttemptAt = this.parseDate(replay.last_attempt_at);
                        if (!force && existingStatus === 'running') {
                            return [2 /*return*/, {
                                    status: 'running',
                                    reason: 'Replay already running.',
                                    issueId: issueId
                                }];
                        }
                        if (!force && existingStatus === 'success') {
                            return [2 /*return*/, {
                                    status: 'skipped',
                                    reason: 'Replay already succeeded.',
                                    issueId: issueId
                                }];
                        }
                        if (!force && maxAttempts > 0 && attemptsUsed >= maxAttempts) {
                            return [2 /*return*/, {
                                    status: 'skipped',
                                    reason: "Replay attempt budget reached (".concat(attemptsUsed, "/").concat(maxAttempts, ")."),
                                    issueId: issueId
                                }];
                        }
                        if (!force && existingStatus === 'failed' && lastAttemptAt) {
                            ageMs = now.getTime() - lastAttemptAt.getTime();
                            if (ageMs >= 0 && ageMs < cooldownMs) {
                                return [2 /*return*/, {
                                        status: 'skipped',
                                        reason: 'Replay cooldown active.',
                                        issueId: issueId,
                                        nextAttemptAt: new Date(lastAttemptAt.getTime() + cooldownMs)
                                    }];
                            }
                        }
                        attemptCount = attemptsUsed + 1;
                        return [4 /*yield*/, ai_terminal_issue_report_collection_1.AiTerminalIssueReports.updateOne({ _id: issueId }, {
                                $set: {
                                    'metadata.quality_manager.replay': __assign(__assign({}, replay), { status: 'running', source: source, trigger: normalizeOptionalString(options.trigger) || 'unspecified', attempt_count: attemptCount, max_attempts: maxAttempts, cooldown_minutes: cooldownMinutes, command: this.config.replayCommand, last_attempt_at: now, updated_at: now, last_error: '', last_exit_code: null }),
                                    updatedAt: now
                                }
                            })];
                    case 2:
                        _b.sent();
                        startedAtMs = Date.now();
                        return [4 /*yield*/, this.writeReplayContextFile(issue, {
                                issueId: issueId,
                                attemptCount: attemptCount,
                                source: source,
                                trigger: normalizeOptionalString(options.trigger) || 'unspecified'
                            })];
                    case 3:
                        contextPath = _b.sent();
                        parsedOutput = null;
                        _b.label = 4;
                    case 4:
                        _b.trys.push([4, 7, 9, 14]);
                        return [4 /*yield*/, execFileAsync('/bin/bash', ['-lc', this.config.replayCommand], {
                                timeout: this.config.replayTimeoutMs,
                                maxBuffer: this.config.replayMaxBufferBytes,
                                env: __assign(__assign({}, process.env), { RIO_AI_ASSISTANT_REPLAY_CONTEXT: contextPath, RIO_AI_ASSISTANT_REPLAY_ISSUE_ID: issueId })
                            })];
                    case 5:
                        execResult = _b.sent();
                        finishedAt = new Date();
                        durationMs = Date.now() - startedAtMs;
                        stdout = this.toSafeOutput(execResult === null || execResult === void 0 ? void 0 : execResult.stdout);
                        stderr = this.toSafeOutput(execResult === null || execResult === void 0 ? void 0 : execResult.stderr);
                        parsedOutput = this.parseOutputJson(stdout);
                        outputStatus = normalizeOptionalString(parsedOutput === null || parsedOutput === void 0 ? void 0 : parsedOutput.status).toLowerCase();
                        success = outputStatus ? ['success', 'ok', 'completed', 'pass'].includes(outputStatus) : true;
                        replayStatus = success ? 'success' : 'failed';
                        replayReason = normalizeOptionalString(parsedOutput === null || parsedOutput === void 0 ? void 0 : parsedOutput.reason)
                            || (success ? 'Replay command completed successfully.' : 'Replay command reported a non-success status.');
                        return [4 /*yield*/, ai_terminal_issue_report_collection_1.AiTerminalIssueReports.updateOne({ _id: issueId }, {
                                $set: {
                                    'metadata.quality_manager.replay': __assign(__assign({}, replay), { status: replayStatus, source: source, trigger: normalizeOptionalString(options.trigger) || 'unspecified', attempt_count: attemptCount, max_attempts: maxAttempts, cooldown_minutes: cooldownMinutes, command: this.config.replayCommand, last_attempt_at: now, last_success_at: success ? finishedAt : replay.last_success_at, last_error: success ? '' : replayReason, last_exit_code: success ? 0 : null, last_duration_ms: durationMs, last_stdout: stdout, last_stderr: stderr, last_output: parsedOutput || undefined, updated_at: finishedAt }),
                                    updatedAt: finishedAt
                                }
                            })];
                    case 6:
                        _b.sent();
                        console.log(new Date(), '[AI Assistant Codex Manager] replay completed', {
                            id_issue_report: issueId,
                            status: replayStatus,
                            attempt: attemptCount,
                            durationMs: durationMs
                        });
                        return [2 /*return*/, {
                                status: replayStatus,
                                reason: replayReason,
                                issueId: issueId,
                                attemptCount: attemptCount,
                                durationMs: durationMs
                            }];
                    case 7:
                        error_4 = _b.sent();
                        finishedAt = new Date();
                        durationMs = Date.now() - startedAtMs;
                        err = error_4 || {};
                        stdout = this.toSafeOutput(err.stdout);
                        stderr = this.toSafeOutput(err.stderr);
                        exitCode = Number.isFinite(Number(err.code)) ? Number(err.code) : null;
                        timeoutHit = (err === null || err === void 0 ? void 0 : err.killed) === true || normalizeOptionalString(err === null || err === void 0 ? void 0 : err.signal).toUpperCase() === 'SIGTERM';
                        reason = timeoutHit
                            ? "Replay command timed out after ".concat(this.config.replayTimeoutMs, "ms.")
                            : (normalizeOptionalString(err === null || err === void 0 ? void 0 : err.message) || 'Replay command failed.');
                        nextAttemptAt = new Date(finishedAt.getTime() + cooldownMs);
                        return [4 /*yield*/, ai_terminal_issue_report_collection_1.AiTerminalIssueReports.updateOne({ _id: issueId }, {
                                $set: {
                                    'metadata.quality_manager.replay': __assign(__assign({}, replay), { status: 'failed', source: source, trigger: normalizeOptionalString(options.trigger) || 'unspecified', attempt_count: attemptCount, max_attempts: maxAttempts, cooldown_minutes: cooldownMinutes, command: this.config.replayCommand, last_attempt_at: now, last_error: reason, last_exit_code: exitCode, last_duration_ms: durationMs, last_stdout: stdout, last_stderr: stderr, last_output: parsedOutput || undefined, next_attempt_at: nextAttemptAt, updated_at: finishedAt }),
                                    updatedAt: finishedAt
                                }
                            })];
                    case 8:
                        _b.sent();
                        console.error(new Date(), '[AI Assistant Codex Manager] replay failed', {
                            id_issue_report: issueId,
                            attempt: attemptCount,
                            reason: reason,
                            exitCode: exitCode,
                            durationMs: durationMs
                        });
                        return [2 /*return*/, {
                                status: 'failed',
                                reason: reason,
                                issueId: issueId,
                                attemptCount: attemptCount,
                                durationMs: durationMs,
                                exitCode: exitCode
                            }];
                    case 9:
                        if (!contextPath) return [3 /*break*/, 13];
                        _b.label = 10;
                    case 10:
                        _b.trys.push([10, 12, , 13]);
                        return [4 /*yield*/, fs_1.promises.unlink(contextPath)];
                    case 11:
                        _b.sent();
                        return [3 /*break*/, 13];
                    case 12:
                        _a = _b.sent();
                        return [3 /*break*/, 13];
                    case 13: return [7 /*endfinally*/];
                    case 14: return [2 /*return*/];
                }
            });
        });
    };
    AiAssistantCodexManager.prototype.markMessageQualityReviewed = function (messageId_1, decision_1) {
        return __awaiter(this, arguments, void 0, function (messageId, decision, issueReportId) {
            var now, qualityPayload;
            if (issueReportId === void 0) { issueReportId = ''; }
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        now = new Date();
                        qualityPayload = {
                            status: decision.status,
                            reason: decision.reason,
                            code: decision.code,
                            checked_at: now,
                            worker_index: normalizeOptionalString(process.env.WORKER_INDEX),
                            worker_instance: normalizeOptionalString(process.env.NODE_APP_INSTANCE)
                        };
                        if (issueReportId) {
                            qualityPayload.id_issue_report = issueReportId;
                        }
                        return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.updateOne({ _id: messageId }, {
                                $set: {
                                    'metadata.quality_manager': qualityPayload,
                                    updatedAt: now
                                }
                            })];
                    case 1:
                        _a.sent();
                        if (this.config.debug) {
                            console.log(new Date(), '[AI Assistant Codex Manager] checked message', {
                                id_message: messageId,
                                status: decision.status,
                                code: decision.code,
                                id_issue_report: issueReportId || null
                            });
                        }
                        return [2 /*return*/];
                }
            });
        });
    };
    AiAssistantCodexManager.prototype.resolveClosestUserPrompt = function (conversationId, assistantCreatedAt) {
        return __awaiter(this, void 0, void 0, function () {
            var query, createdAt, userMessage;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        query = {
                            id_conversation: conversationId,
                            role: 'user'
                        };
                        createdAt = assistantCreatedAt ? new Date(assistantCreatedAt) : null;
                        if (createdAt && Number.isFinite(createdAt.getTime())) {
                            query.createdAt = { $lte: createdAt };
                        }
                        return [4 /*yield*/, ai_terminal_message_collection_1.AiTerminalMessages.findOne(query, { sort: { createdAt: -1 } })];
                    case 1:
                        userMessage = _a.sent();
                        return [2 /*return*/, normalizeOptionalString(userMessage === null || userMessage === void 0 ? void 0 : userMessage.content)];
                }
            });
        });
    };
    AiAssistantCodexManager.prototype.writeRemediationContextFile = function (issue, options) {
        return __awaiter(this, void 0, void 0, function () {
            var issueId, filePath, payload;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        issueId = normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue._id);
                        filePath = path.join(os.tmpdir(), "resolveio-ai-assistant-remediation-".concat(issueId, "-").concat(Date.now(), ".json"));
                        payload = {
                            created_at: new Date().toISOString(),
                            issue_report: {
                                _id: issueId,
                                status: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.status),
                                source: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.source),
                                reason: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.reason),
                                id_conversation: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.id_conversation),
                                id_message: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.id_message),
                                id_client: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.id_client),
                                id_app: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.id_app),
                                id_user: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.id_user),
                                request_id: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.request_id),
                                user_prompt: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.user_prompt),
                                assistant_content: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.assistant_content)
                            },
                            remediation: {
                                source: normalizeOptionalString(options === null || options === void 0 ? void 0 : options.source),
                                trigger: normalizeOptionalString(options === null || options === void 0 ? void 0 : options.trigger),
                                attempt_count: Number(options === null || options === void 0 ? void 0 : options.attemptCount) || 0,
                                max_attempts: this.config.remediationMaxAttemptsPerIssue,
                                cooldown_minutes: this.config.remediationCooldownMinutes
                            }
                        };
                        return [4 /*yield*/, fs_1.promises.writeFile(filePath, JSON.stringify(payload, null, 2), 'utf8')];
                    case 1:
                        _a.sent();
                        return [2 /*return*/, filePath];
                }
            });
        });
    };
    AiAssistantCodexManager.prototype.writeReplayContextFile = function (issue, options) {
        return __awaiter(this, void 0, void 0, function () {
            var issueId, metadata, qualityManager, remediation, filePath, payload;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        issueId = normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue._id);
                        metadata = this.normalizeMetadata(issue === null || issue === void 0 ? void 0 : issue.metadata);
                        qualityManager = this.normalizeMetadata(metadata.quality_manager);
                        remediation = this.normalizeMetadata(qualityManager.remediation);
                        filePath = path.join(os.tmpdir(), "resolveio-ai-assistant-replay-".concat(issueId, "-").concat(Date.now(), ".json"));
                        payload = {
                            created_at: new Date().toISOString(),
                            issue_report: {
                                _id: issueId,
                                status: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.status),
                                source: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.source),
                                reason: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.reason),
                                id_conversation: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.id_conversation),
                                id_message: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.id_message),
                                id_client: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.id_client),
                                id_app: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.id_app),
                                id_user: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.id_user),
                                request_id: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.request_id),
                                user_prompt: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.user_prompt),
                                assistant_content: normalizeOptionalString(issue === null || issue === void 0 ? void 0 : issue.assistant_content)
                            },
                            remediation: {
                                status: normalizeOptionalString(remediation.status),
                                last_attempt_at: remediation.last_attempt_at || null,
                                last_success_at: remediation.last_success_at || null,
                                last_error: normalizeOptionalString(remediation.last_error),
                                attempt_count: Number(remediation.attempt_count) || 0
                            },
                            replay: {
                                source: normalizeOptionalString(options === null || options === void 0 ? void 0 : options.source),
                                trigger: normalizeOptionalString(options === null || options === void 0 ? void 0 : options.trigger),
                                attempt_count: Number(options === null || options === void 0 ? void 0 : options.attemptCount) || 0,
                                max_attempts: this.config.replayMaxAttemptsPerIssue,
                                cooldown_minutes: this.config.replayCooldownMinutes,
                                command: this.config.replayCommand
                            }
                        };
                        return [4 /*yield*/, fs_1.promises.writeFile(filePath, JSON.stringify(payload, null, 2), 'utf8')];
                    case 1:
                        _a.sent();
                        return [2 /*return*/, filePath];
                }
            });
        });
    };
    AiAssistantCodexManager.prototype.parseOutputJson = function (stdout) {
        var text = normalizeOptionalString(stdout);
        if (!text) {
            return null;
        }
        var firstChar = text.charAt(0);
        if (firstChar !== '{' && firstChar !== '[') {
            return null;
        }
        try {
            var parsed = JSON.parse(text);
            if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
                return null;
            }
            return parsed;
        }
        catch (_a) {
            return null;
        }
    };
    AiAssistantCodexManager.prototype.toSafeOutput = function (value) {
        var asString = typeof value === 'string'
            ? value
            : (Buffer.isBuffer(value) ? value.toString('utf8') : String(value || ''));
        var normalized = asString.trim();
        if (!normalized) {
            return '';
        }
        if (normalized.length <= MAX_STORED_OUTPUT_CHARS) {
            return normalized;
        }
        return normalized.slice(0, MAX_STORED_OUTPUT_CHARS);
    };
    AiAssistantCodexManager.prototype.parseDate = function (value) {
        if (!value) {
            return null;
        }
        var date = value instanceof Date ? value : new Date(value);
        if (!Number.isFinite(date.getTime())) {
            return null;
        }
        return date;
    };
    AiAssistantCodexManager.prototype.normalizeMetadata = function (value) {
        if (!value || typeof value !== 'object' || Array.isArray(value)) {
            return {};
        }
        return value;
    };
    return AiAssistantCodexManager;
}());
exports.AiAssistantCodexManager = AiAssistantCodexManager;

//# sourceMappingURL=ai-assistant-codex-manager.manager.js.map
