"use strict";
// Versioned prompts — version-controlled system prompts with registry,
// rollback, diffing, and Markdown history rendering.
//
// Each named prompt (e.g. "main-system-prompt") has its own registry stored
// at <projectDir>/.harness/prompts/<name>.json. Versions are append-only
// and auto-incremented.
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.getVersion = getVersion;
exports.diffVersions = diffVersions;
exports.renderPromptHistory = renderPromptHistory;
exports.loadRegistry = loadRegistry;
exports.listRegistries = listRegistries;
exports.savePromptVersion = savePromptVersion;
exports.getActivePrompt = getActivePrompt;
exports.setActiveVersion = setActiveVersion;
exports.rollback = rollback;
const crypto = __importStar(require("crypto"));
const fs = __importStar(require("fs/promises"));
const path = __importStar(require("path"));
// ─── Helpers ────────────────────────────────────────────────────────
function sanitizeName(name) {
    return name.replace(/[^a-zA-Z0-9\-_]/g, '-');
}
function promptsDir(projectDir) {
    return path.join(projectDir, '.harness', 'prompts');
}
function registryPath(projectDir, name) {
    return path.join(promptsDir(projectDir), `${sanitizeName(name)}.json`);
}
// ─── HMAC integrity ─────────────────────────────────────────────────
// Use a fixed key derived from the harness identity (not a secret — just tamper detection)
const HMAC_KEY = 'harness-prompt-integrity-v1';
function signVersion(v) {
    return crypto
        .createHmac('sha256', HMAC_KEY)
        .update(`${v.version}:${v.label}:${v.content}:${v.createdAt}`)
        .digest('hex')
        .slice(0, 32);
}
function verifyVersion(v) {
    if (!v.signature)
        return true; // legacy versions without signature pass through
    return v.signature === signVersion(v);
}
// ─── Pure helpers ───────────────────────────────────────────────────
function getVersion(registry, version) {
    return registry.versions.find((v) => v.version === version);
}
function diffVersions(registry, fromVersion, toVersion) {
    const from = getVersion(registry, fromVersion);
    const to = getVersion(registry, toVersion);
    if (!from || !to)
        return undefined;
    const fromLines = from.content.split('\n');
    const toLines = to.content.split('\n');
    const fromSet = new Set(fromLines);
    const toSet = new Set(toLines);
    const removed = fromLines.filter((l) => !toSet.has(l)).map((l) => `-${l}`);
    const added = toLines.filter((l) => !fromSet.has(l)).map((l) => `+${l}`);
    const totalChanges = added.length + removed.length;
    const maxLines = Math.max(fromLines.length, toLines.length, 1);
    const similarity = 1 - totalChanges / maxLines;
    return {
        fromVersion,
        toVersion,
        added,
        removed,
        totalChanges,
        similarity: Math.max(0, Math.min(1, similarity)),
    };
}
function renderPromptHistory(registry) {
    const lines = [`# Prompt History: ${registry.name}`, ''];
    for (const v of registry.versions) {
        const active = v.version === registry.activeVersion ? ' **(active)**' : '';
        lines.push(`## v${v.version} — ${v.label}${active}`);
        lines.push(`- **Date:** ${v.createdAt}`);
        if (v.author)
            lines.push(`- **Author:** ${v.author}`);
        if (v.changelog)
            lines.push(`- **Changelog:** ${v.changelog}`);
        if (v.tags && v.tags.length > 0)
            lines.push(`- **Tags:** ${v.tags.join(', ')}`);
        lines.push('');
    }
    return lines.join('\n');
}
// ─── Persistence ────────────────────────────────────────────────────
async function loadRegistry(projectDir, name) {
    const filePath = registryPath(projectDir, name);
    try {
        const raw = await fs.readFile(filePath, 'utf-8');
        const parsed = JSON.parse(raw);
        if (parsed.versions) {
            const validVersions = parsed.versions.filter((v) => {
                if (!verifyVersion(v)) {
                    console.warn(`[versionedPrompts] Version ${v.version} of "${parsed.name}" failed integrity check — skipping`);
                    return false;
                }
                return true;
            });
            parsed.versions = validVersions;
        }
        return parsed;
    }
    catch {
        return undefined;
    }
}
async function saveRegistry(projectDir, registry) {
    const dir = promptsDir(projectDir);
    await fs.mkdir(dir, { recursive: true });
    const filePath = registryPath(projectDir, registry.name);
    await fs.writeFile(filePath, JSON.stringify(registry, null, 2), 'utf-8');
}
async function listRegistries(projectDir) {
    const dir = promptsDir(projectDir);
    try {
        const entries = await fs.readdir(dir);
        return entries
            .filter((e) => e.endsWith('.json'))
            .map((e) => e.replace(/\.json$/, ''));
    }
    catch {
        return [];
    }
}
async function savePromptVersion(projectDir, name, content, opts) {
    const existing = await loadRegistry(projectDir, name);
    const registry = existing ?? {
        name,
        versions: [],
        activeVersion: 0,
    };
    const nextVersion = registry.versions.length > 0
        ? registry.versions[registry.versions.length - 1].version + 1
        : 1;
    const newVersion = {
        version: nextVersion,
        label: opts?.label ?? `v${nextVersion}`,
        content,
        createdAt: new Date().toISOString(),
        ...(opts?.author !== undefined && { author: opts.author }),
        ...(opts?.changelog !== undefined && { changelog: opts.changelog }),
        ...(opts?.tags !== undefined && { tags: opts.tags }),
    };
    const signed = { ...newVersion, signature: signVersion(newVersion) };
    registry.versions.push(signed);
    registry.activeVersion = nextVersion;
    await saveRegistry(projectDir, registry);
    return signed;
}
async function getActivePrompt(projectDir, name) {
    const registry = await loadRegistry(projectDir, name);
    if (!registry)
        return undefined;
    return getVersion(registry, registry.activeVersion);
}
async function setActiveVersion(projectDir, name, version) {
    const registry = await loadRegistry(projectDir, name);
    if (!registry)
        return false;
    if (!getVersion(registry, version))
        return false;
    registry.activeVersion = version;
    await saveRegistry(projectDir, registry);
    return true;
}
async function rollback(projectDir, name) {
    const registry = await loadRegistry(projectDir, name);
    if (!registry)
        return undefined;
    const prev = registry.activeVersion - 1;
    const prevVersion = getVersion(registry, prev);
    if (!prevVersion)
        return undefined;
    registry.activeVersion = prev;
    await saveRegistry(projectDir, registry);
    return prevVersion;
}
//# sourceMappingURL=versionedPrompts.js.map