"use strict";
/**
 * Per-participant fallback-swap sidecar.
 *
 * Lives at `<participantDir>/_swaps.json` next to `answer.md` /
 * `_stats.json`. Mirrors the existing sidecar pattern — JSON, read by
 * the run-artifacts route at refresh time, no DB schema change.
 *
 * Why a sidecar and not the DB:
 *   - phase_events packs warnings as opaque text (`output: "[lineage_fallback]
 *     <message>"`). Reconstructing structured fromLineage/toModel/etc. on
 *     replay would mean parsing that string — fragile.
 *   - The SSE stream shuts off for terminal chats, so reload-after-done
 *     loses the cli_warning events entirely.
 *   - Sidecar survives indefinitely on disk and is cheap to read.
 *
 * Append-only — multiple swaps in a single slot's chain (rare, but
 * possible: codex → openrouter-gpt → claude) all land in one file.
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.appendSwapSidecar = appendSwapSidecar;
exports.readSwapSidecar = readSwapSidecar;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const SIDECAR_NAME = '_swaps.json';
/**
 * Append a swap entry to the participant's sidecar. Reads the current
 * file (treats missing / malformed as empty), pushes the entry, writes
 * the result back. Synchronous + best-effort: a failed write is logged
 * to console.error and otherwise swallowed — the SSE event still went
 * out, so the live UI shows the swap; only the post-reload card is
 * affected.
 */
function appendSwapSidecar(participantDir, entry) {
    try {
        const filePath = path_1.default.join(participantDir, SIDECAR_NAME);
        let existing = [];
        if (fs_1.default.existsSync(filePath)) {
            try {
                const raw = fs_1.default.readFileSync(filePath, 'utf-8');
                const parsed = JSON.parse(raw);
                if (Array.isArray(parsed)) {
                    existing = parsed;
                }
                else {
                    // Non-array payload — preserve the bad file before overwriting
                    // so a manual recovery is possible (vs. silently wiping it).
                    renameToCorrupt(filePath);
                }
            }
            catch {
                // Truncated / unparseable JSON, almost certainly from a crash
                // mid-write of a prior version (pre-atomic). Side-band it instead
                // of dropping; next append starts fresh.
                renameToCorrupt(filePath);
            }
        }
        existing.push(entry);
        // Atomic write: stage to <name>.tmp then renameSync. POSIX rename is
        // atomic within the same directory — readers either see the old
        // file or the new one, never a half-written intermediate.
        const tmpPath = `${filePath}.tmp`;
        fs_1.default.writeFileSync(tmpPath, JSON.stringify(existing, null, 2), 'utf-8');
        fs_1.default.renameSync(tmpPath, filePath);
    }
    catch (err) {
        console.error('[chorus] failed to write swap sidecar:', err instanceof Error ? err.message : String(err));
    }
}
function renameToCorrupt(filePath) {
    try {
        fs_1.default.renameSync(filePath, `${filePath}.corrupt-${Date.now()}`);
    }
    catch {
        /* best-effort — if the rename fails, the next writeFileSync
         * overwrites the bad file anyway. */
    }
}
/**
 * Read all swap entries from a participant's sidecar. Used by the
 * run-artifacts route to surface fallback swaps on the run page even
 * after the SSE stream has closed.
 */
function readSwapSidecar(participantDir) {
    const filePath = path_1.default.join(participantDir, SIDECAR_NAME);
    if (!fs_1.default.existsSync(filePath))
        return [];
    try {
        const raw = fs_1.default.readFileSync(filePath, 'utf-8');
        const parsed = JSON.parse(raw);
        if (Array.isArray(parsed))
            return parsed;
    }
    catch {
        /* malformed — treat as empty */
    }
    return [];
}
//# sourceMappingURL=swap-sidecar.js.map