"use strict";
// src/orchestrator/CatalogPromotion.ts
// Phase 6 of catalog→execution: the feedback loop. Records each agent
// execution outcome into the PerformanceScorecard and auto-promotes a draft
// catalog agent (status: draft → active) once it has proven itself over enough
// successful runs. Closes the loop: gap detected → draft generated → executed →
// scored → promoted (or left draft if it underperforms).
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.CatalogPromotion = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const PerformanceScorecard_1 = require("./PerformanceScorecard");
function agentRoots() {
    const env = process.env.OPENLIFE_AGENT_ROOTS;
    if (env)
        return env.split(':').filter(Boolean);
    const cwdRoot = path.join(process.cwd(), '.catalog', 'agents');
    const packageRoot = path.join(__dirname, '..', '..', '.catalog', 'agents');
    return cwdRoot === packageRoot ? [cwdRoot] : [cwdRoot, packageRoot];
}
/** Resolve a catalog agent's AGENT.md path (project root preferred). Returns
 *  null if the agent isn't a writable catalog agent. */
function catalogFile(id) {
    if (!id || id.includes('/') || id.includes('\\') || id.includes('..'))
        return null;
    for (const root of agentRoots()) {
        const file = path.resolve(root, id, 'AGENT.md');
        if (!file.startsWith(path.resolve(root) + path.sep))
            continue;
        if (fs.existsSync(file))
            return file;
    }
    return null;
}
/** Read the `status:` from the first frontmatter block. */
function readStatus(content) {
    const fm = content.match(/^---\n([\s\S]*?)\n---/);
    if (!fm)
        return null;
    return fm[1].match(/^status:\s*(\S+)/m)?.[1]?.trim() ?? null;
}
class CatalogPromotion {
    scorecard;
    minSuccesses;
    minScore;
    constructor(opts = {}) {
        this.scorecard = opts.scorecard ?? new PerformanceScorecard_1.PerformanceScorecard();
        this.minSuccesses = opts.minSuccesses ?? 3;
        this.minScore = opts.minScore ?? 4;
    }
    /** ExecutionRecorder surface — called by CatalogAgentExecutor after a run. */
    recordExecution(agentId, success) {
        this.recordOutcome(agentId, success);
        this.maybePromote(agentId);
    }
    recordOutcome(agentId, success) {
        this.scorecard.record({
            entityId: agentId,
            entityType: 'agent',
            status: success ? 'success' : 'failed',
            reviewScore: success ? 1 : 0,
            timestamp: new Date().toISOString(),
        });
    }
    /** Promote a draft catalog agent to active if it has earned it. Idempotent:
     *  re-running after promotion is a no-op. Never throws. */
    maybePromote(agentId) {
        const file = catalogFile(agentId);
        if (!file)
            return { agentId, promoted: false, reason: 'not_a_catalog_agent' };
        let content;
        try {
            content = fs.readFileSync(file, 'utf-8');
        }
        catch {
            return { agentId, promoted: false, reason: 'unreadable' };
        }
        const status = readStatus(content);
        if (status !== 'draft') {
            return { agentId, promoted: false, reason: status ? `already_${status}` : 'no_status_field' };
        }
        const agg = this.scorecard.get(agentId);
        if (!agg)
            return { agentId, promoted: false, reason: 'no_track_record' };
        if (agg.successes < this.minSuccesses || agg.score < this.minScore) {
            return {
                agentId, promoted: false, reason: 'below_threshold',
                runs: agg.runs, successes: agg.successes, score: agg.score,
            };
        }
        // Flip status: draft → active in the first frontmatter block only.
        const promoted = content.replace(/(^---\n[\s\S]*?\n)status:\s*draft/m, '$1status: active');
        try {
            fs.writeFileSync(file, promoted, 'utf-8');
        }
        catch {
            return { agentId, promoted: false, reason: 'write_failed' };
        }
        return {
            agentId, promoted: true, reason: 'promoted',
            runs: agg.runs, successes: agg.successes, score: agg.score,
        };
    }
}
exports.CatalogPromotion = CatalogPromotion;
