"use strict";
// src/test_openlife_method_inventory.ts
// Invariants for the v1.9.0 OpenLife method framework layer.
//
// Verifies:
//  1. 12 deep persona files exist under .openlife/method/agents/
//  2. 12 ambassador shims per host under dist-templates/<host>/agents/
//  3. 12 workflows under dist-templates/workflows/ all parse cleanly
//  4. 36 slash commands per host under dist-templates/<host>/commands/openlife/
//  5. .openlife/method/agents/ files have valid frontmatter
//  6. No string "aiox" appears in any shipped file under dist-templates/ or
//     .openlife/method/ (policy enforcement: no AIOX brand leaks)
//
// Fail-fast: any drift from expected counts surfaces immediately.
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 });
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const WorkflowParser_1 = require("./orchestrator/workflow/WorkflowParser");
const REPO_ROOT = path.resolve(__dirname, '..');
const HOSTS = ['claude-code', 'gemini-cli', 'codex'];
const EXPECTED_PERSONAS = [
    'maestro', 'lyra', 'forge', 'atlas', 'genesis',
    'builder', 'sentinel', 'steward', 'conductor', 'vortex', 'mesh', 'prism',
];
const EXPECTED_WORKFLOWS = [
    'greenfield-fullstack', 'greenfield-service', 'greenfield-ui',
    'brownfield-blueprint', 'brownfield-fullstack', 'brownfield-service', 'brownfield-ui',
    'story-development-cycle', 'qa-loop', 'spec-pipeline',
    'epic-orchestration', 'continuous-deployment',
];
let passed = 0;
let failed = 0;
const failures = [];
function check(name, cond, detail) {
    if (cond) {
        passed++;
    }
    else {
        failed++;
        const msg = detail ? `${name} — ${detail}` : name;
        failures.push(msg);
    }
}
function readUtf8(fp) {
    return fs.readFileSync(fp, 'utf-8');
}
// ── 1. Deep personas ───────────────────────────────────────────────────
console.log('[1] Deep personas in .openlife/method/agents/');
const personasDir = path.join(REPO_ROOT, '.openlife', 'method', 'agents');
for (const id of EXPECTED_PERSONAS) {
    const fp = path.join(personasDir, `${id}.md`);
    check(`persona ${id}.md exists`, fs.existsSync(fp));
    if (fs.existsSync(fp)) {
        const content = readUtf8(fp);
        check(`persona ${id} has frontmatter`, /^---\n[\s\S]+?\n---/.test(content));
        check(`persona ${id} declares id field`, new RegExp(`id: openlife-${id}`).test(content));
        check(`persona ${id} has Commands section`, /## Commands/.test(content));
        // Each agent must document who it hands work to — either heading satisfies
        // the contract ("Delegates To" is the v2.0 canonical name for hand-offs).
        check(`persona ${id} documents hand-offs`, /## (Hand-offs|Delegates To)/.test(content));
    }
}
// ── 2. Ambassador shims (one per host) ─────────────────────────────────
console.log('[2] Ambassador shims');
for (const host of HOSTS) {
    const dir = path.join(REPO_ROOT, 'dist-templates', host, 'agents');
    check(`host dir ${host}/agents exists`, fs.existsSync(dir));
    for (const id of EXPECTED_PERSONAS) {
        const fp = path.join(dir, `openlife-${id}.md`);
        check(`${host}/agents/openlife-${id}.md exists`, fs.existsSync(fp));
        if (fs.existsSync(fp)) {
            const content = readUtf8(fp);
            check(`${host}/${id} ambassador frontmatter`, /^---\nname: openlife-/.test(content));
            check(`${host}/${id} ambassador points to runtime`, content.includes(`.openlife/method/agents/${id}.md`));
        }
    }
}
// ── 3. Workflows ───────────────────────────────────────────────────────
console.log('[3] Workflows in dist-templates/workflows/');
const workflowsDir = path.join(REPO_ROOT, 'dist-templates', 'workflows');
for (const id of EXPECTED_WORKFLOWS) {
    const fp = path.join(workflowsDir, `${id}.yaml`);
    check(`workflow ${id}.yaml exists`, fs.existsSync(fp));
    if (fs.existsSync(fp)) {
        const parsed = (0, WorkflowParser_1.parseWorkflowFile)(fp);
        check(`workflow ${id} parses cleanly`, !parsed.errors || parsed.errors.length === 0, parsed.errors ? parsed.errors[0]?.message?.slice(0, 80) : undefined);
        if (parsed.workflow) {
            check(`workflow ${id} id matches filename`, parsed.workflow.id === id);
            check(`workflow ${id} has sequence`, (parsed.workflow.sequence || []).length > 0);
        }
    }
}
// ── 4. Slash commands ──────────────────────────────────────────────────
console.log('[4] Slash commands per host');
const EXPECTED_TOP = ['ask', 'doctor', 'status', 'dream', 'start', 'plan', 'story', 'review', 'ship', 'explore', 'audit', 'health'];
const EXPECTED_FLOWS = ['greenfield-fullstack', 'greenfield-service', 'greenfield-ui', 'brownfield-blueprint', 'brownfield-fullstack', 'brownfield-service', 'brownfield-ui', 'story-cycle', 'qa-loop', 'spec-pipeline', 'epic', 'release'];
// v1.10.0+: commands classified as host-native must NOT primarily shell
// out to `openlife <verb>`. They use the host LLM's own reasoning.
// Runtime-state commands DO shell out (real diagnostics).
const HOST_NATIVE_TOP = new Set(['ask', 'dream', 'start', 'plan', 'story', 'review', 'ship', 'explore', 'audit', 'health']);
const RUNTIME_TOP = new Set(['doctor', 'status']);
for (const host of HOSTS) {
    const base = path.join(REPO_ROOT, 'dist-templates', host, 'commands', 'openlife');
    for (const name of EXPECTED_TOP) {
        const fp = path.join(base, `${name}.md`);
        check(`${host}/commands/openlife/${name}.md exists`, fs.existsSync(fp));
        if (!fs.existsSync(fp))
            continue;
        const content = readUtf8(fp);
        if (HOST_NATIVE_TOP.has(name)) {
            check(`${host}/${name} declares host-native mode`, /\*\*Mode:\*\*\s*host-native/.test(content));
        }
        if (RUNTIME_TOP.has(name)) {
            // Runtime commands SHOULD shell out (legitimate diagnostic invocation)
            check(`${host}/${name} (runtime) invokes openlife shell command`, /`openlife\s+/.test(content));
        }
    }
    for (const id of EXPECTED_PERSONAS) {
        const fp = path.join(base, 'agents', `${id}.md`);
        check(`${host}/commands/openlife/agents/${id}.md exists`, fs.existsSync(fp));
        if (!fs.existsSync(fp))
            continue;
        const content = readUtf8(fp);
        check(`${host}/agents/${id} declares host-native mode`, /\*\*Mode:\*\*\s*host-native/.test(content));
        check(`${host}/agents/${id} references persona file at runtime path`, content.includes(`.openlife/method/agents/${id}.md`));
    }
    for (const flow of EXPECTED_FLOWS) {
        const fp = path.join(base, 'flow', `${flow}.md`);
        check(`${host}/commands/openlife/flow/${flow}.md exists`, fs.existsSync(fp));
        if (!fs.existsSync(fp))
            continue;
        const content = readUtf8(fp);
        check(`${host}/flow/${flow} declares host-native mode`, /\*\*Mode:\*\*\s*host-native/.test(content));
        check(`${host}/flow/${flow} references the workflow YAML`, /dist-templates\/workflows\/[\w-]+\.yaml/.test(content));
    }
}
// ── 5. No "aiox" leak in shipped content ───────────────────────────────
console.log('[5] AIOX brand leak check');
function scanForAiox(root) {
    const hits = [];
    if (!fs.existsSync(root))
        return hits;
    function walk(dir) {
        for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
            const fp = path.join(dir, entry.name);
            if (entry.isDirectory()) {
                walk(fp);
                continue;
            }
            if (!/\.(md|yaml|yml|json|js|ts)$/.test(entry.name))
                continue;
            try {
                const content = fs.readFileSync(fp, 'utf-8');
                if (/\baiox\b/i.test(content)) {
                    hits.push(path.relative(REPO_ROOT, fp));
                }
            }
            catch { /* skip binary */ }
        }
    }
    walk(root);
    return hits;
}
const aioxInDistTemplates = scanForAiox(path.join(REPO_ROOT, 'dist-templates'));
const aioxInOpenLifeMethod = scanForAiox(path.join(REPO_ROOT, '.openlife', 'method'));
check('no aiox leak in dist-templates/', aioxInDistTemplates.length === 0, aioxInDistTemplates.length > 0 ? `found in ${aioxInDistTemplates.length} files: ${aioxInDistTemplates.slice(0, 3).join(', ')}` : undefined);
check('no aiox leak in .openlife/method/', aioxInOpenLifeMethod.length === 0, aioxInOpenLifeMethod.length > 0 ? `found in ${aioxInOpenLifeMethod.length} files: ${aioxInOpenLifeMethod.slice(0, 3).join(', ')}` : undefined);
// ── 6. Summary ─────────────────────────────────────────────────────────
console.log('');
console.log(`Results: ${passed} passed, ${failed} failed`);
if (failed > 0) {
    console.error('TEST_OPENLIFE_METHOD_INVENTORY_FAIL');
    console.error('Failures:');
    for (const f of failures.slice(0, 25))
        console.error('  - ' + f);
    if (failures.length > 25)
        console.error(`  ... and ${failures.length - 25} more`);
    process.exit(1);
}
console.log('TEST_OPENLIFE_METHOD_INVENTORY_OK');
