#!/usr/bin/env node
/**
 * Phase 4 Phantom Orchestrator
 *
 * Uses the Phantom Workers system to build Phase 4 in parallel:
 *   - Wire Mindkit guardrails into Nexus Prime MCP adapter
 *   - Two workers implement different strategies simultaneously
 *   - MergeOracle picks the winner
 *   - Winning diff gets applied back to main
 *
 * Run: node dist/phantom/phase4-orchestrator.js
 */
import * as path from 'path';
import * as fs from 'fs';
import { GhostPass, PhantomWorker, MergeOracle } from './index.js';
const REPO_ROOT = path.resolve(process.cwd());
// ── Lightweight in-RAM memory (no SQLite for orchestrator standalone use) ─────
class InMemoryStore {
    items = [];
    store(content, priority, tags) {
        this.items.push({ content, priority, tags });
    }
    recall(query, k = 3) {
        const words = query.toLowerCase().split(/\s+/);
        return this.items
            .filter(m => words.some(w => m.content.toLowerCase().includes(w)))
            .slice(0, k)
            .map(m => m.content);
    }
    flush() { }
    close() { }
}
const memory = new InMemoryStore();
// ── Color helpers ─────────────────────────────────────────────────────────────
const c = {
    cyan: (s) => `\x1b[36m${s}\x1b[0m`,
    green: (s) => `\x1b[32m${s}\x1b[0m`,
    yellow: (s) => `\x1b[33m${s}\x1b[0m`,
    red: (s) => `\x1b[31m${s}\x1b[0m`,
    bold: (s) => `\x1b[1m${s}\x1b[0m`,
    dim: (s) => `\x1b[2m${s}\x1b[0m`,
};
function log(icon, msg) {
    console.log(`${icon}  ${msg}`);
}
// ─────────────────────────────────────────────────────────────────────────────
// Target files for Phase 4
// ─────────────────────────────────────────────────────────────────────────────
const TARGET_FILES = [
    { path: path.join(REPO_ROOT, 'src/agents/adapters/mcp.ts'), sizeBytes: 12829 },
    { path: path.join(REPO_ROOT, 'src/index.ts'), sizeBytes: 8000 },
    { path: path.join(REPO_ROOT, 'packages/mindkit/dist/guardrails.js'), sizeBytes: 5000 },
    { path: path.join(REPO_ROOT, 'packages/mindkit/dist/mcp.js'), sizeBytes: 4000 },
    { path: path.join(REPO_ROOT, 'GEMINI.md'), sizeBytes: 3000 },
];
// ─────────────────────────────────────────────────────────────────────────────
// Worker executors — the actual code each worker writes
// ─────────────────────────────────────────────────────────────────────────────
/**
 * WORKER A — "Minimal" approach
 * Strategy: Add nexus_mindkit_check as a thin wrapper tool in mcp.ts
 * Pure tool addition, no middleware — fast and safe
 */
const workerAExecutor = async (worktreeDir) => {
    const mcpPath = path.join(worktreeDir, 'src/agents/adapters/mcp.ts');
    if (!fs.existsSync(mcpPath)) {
        return { learnings: ['mcp.ts not found in worktree'], confidence: 0.1 };
    }
    let mcpContent = fs.readFileSync(mcpPath, 'utf-8');
    // 1. Add GuardrailEngine import at the top
    const guardrailImport = `import { GuardrailEngine } from '../../packages/mindkit/dist/guardrails.js';\n`;
    if (!mcpContent.includes('GuardrailEngine')) {
        mcpContent = mcpContent.replace(`import { GhostPass } from '../../phantom/index.js';`, `import { GhostPass } from '../../phantom/index.js';\n${guardrailImport}`);
    }
    // 2. Add singleton instance after tokenEngine
    if (!mcpContent.includes('guardrailEngine')) {
        mcpContent = mcpContent.replace('const tokenEngine = new TokenSupremacyEngine();', `const tokenEngine = new TokenSupremacyEngine();\nconst guardrailEngine = new GuardrailEngine();`);
    }
    // 3. Add nexus_mindkit_check tool definition in tools list
    const mindkitTool = `                {
                    name: 'nexus_mindkit_check',
                    description: 'Check an action against Mindkit guardrails before executing it. Returns PASS/FAIL with violations and suggestions. Call before any potentially risky operation.',
                    inputSchema: {
                        type: 'object',
                        properties: {
                            action: {
                                type: 'string',
                                description: 'The action or prompt to evaluate against guardrails'
                            },
                            tokenCount: {
                                type: 'number',
                                description: 'Estimated token count of current context (optional)'
                            },
                            filesToModify: {
                                type: 'array',
                                items: { type: 'string' },
                                description: 'Files that will be modified (optional)'
                            },
                            isDestructive: {
                                type: 'boolean',
                                description: 'Mark if operation is destructive (delete, overwrite)'
                            }
                        },
                        required: ['action']
                    }
                },`;
    // Insert before closing tools array — find last tool and insert after
    if (!mcpContent.includes('nexus_mindkit_check')) {
        // Find the ghost pass tool and insert after it
        mcpContent = mcpContent.replace(`                    name: 'nexus_ghost_pass',`, `${mindkitTool}\n                {\n                    name: 'nexus_ghost_pass',`);
    }
    // 4. Add handler for nexus_mindkit_check in the switch/CallToolRequestSchema handler
    const mindkitHandler = `
                case 'nexus_mindkit_check': {
                    const action = String(args?.action ?? '');
                    const ctx = {
                        action,
                        tokenCount: args?.tokenCount as number | undefined,
                        filesToModify: args?.filesToModify as string[] | undefined,
                        isDestructive: args?.isDestructive as boolean | undefined,
                    };
                    const result = guardrailEngine.check(ctx);
                    const summary = guardrailEngine.format(result);

                    // Store in memory if guardrail fired
                    if (!result.passed || result.violations.length > 0) {
                        this.nexusRef?.memorize(
                            \`Guardrail check: action="\${action.slice(0, 80)}" → \${result.passed ? 'PASSED' : 'BLOCKED'} (\${result.violations.length} violations)\`,
                            0.7,
                            ['#guardrail', '#mindkit']
                        );
                    }

                    return {
                        content: [{ type: 'text', text: JSON.stringify({
                            passed: result.passed,
                            score: Math.round(result.score * 100),
                            violations: result.violations,
                            warnings: result.warnings,
                            summary
                        }, null, 2) }]
                    };
                }`;
    if (!mcpContent.includes("case 'nexus_mindkit_check'")) {
        mcpContent = mcpContent.replace("case 'nexus_ghost_pass':", `${mindkitHandler}\n\n                case 'nexus_ghost_pass':`);
    }
    fs.writeFileSync(mcpPath, mcpContent, 'utf-8');
    return {
        learnings: [
            'Added nexus_mindkit_check tool to nexus-prime MCP adapter',
            'GuardrailEngine imported from mindkit dist (no process spawn needed)',
            'Tool calls guardrail check inline — zero latency vs spawning mindkit server',
            'Violations auto-stored in Nexus memory with #guardrail tag',
        ],
        confidence: 0.88
    };
};
/**
 * WORKER B — "Full Integration" approach
 * Strategy: Add tool + middleware that auto-checks EVERY tool call
 * More ambitious: guardrail wrapper on the entire CallTool handler
 */
const workerBExecutor = async (worktreeDir) => {
    const mcpPath = path.join(worktreeDir, 'src/agents/adapters/mcp.ts');
    if (!fs.existsSync(mcpPath)) {
        return { learnings: ['mcp.ts not found in worktree'], confidence: 0.1 };
    }
    let mcpContent = fs.readFileSync(mcpPath, 'utf-8');
    // 1. Same guardrail import
    const guardrailImport = `import { GuardrailEngine } from '../../packages/mindkit/dist/guardrails.js';\n`;
    if (!mcpContent.includes('GuardrailEngine')) {
        mcpContent = mcpContent.replace(`import { GhostPass } from '../../phantom/index.js';`, `import { GhostPass } from '../../phantom/index.js';\n${guardrailImport}`);
    }
    // 2. Same singleton
    if (!mcpContent.includes('guardrailEngine')) {
        mcpContent = mcpContent.replace('const tokenEngine = new TokenSupremacyEngine();', `const tokenEngine = new TokenSupremacyEngine();\nconst guardrailEngine = new GuardrailEngine();`);
    }
    // 3. Add nexus_mindkit_check tool (same as worker A)
    const mindkitTool = `                {
                    name: 'nexus_mindkit_check',
                    description: 'Check an action against Mindkit guardrails. Auto-runs before any nexus_store_memory with priority > 0.9. Also available for explicit pre-flight checks.',
                    inputSchema: {
                        type: 'object',
                        properties: {
                            action: { type: 'string', description: 'Action to validate' },
                            tokenCount: { type: 'number' },
                            filesToModify: { type: 'array', items: { type: 'string' } },
                            isDestructive: { type: 'boolean' }
                        },
                        required: ['action']
                    }
                },`;
    if (!mcpContent.includes('nexus_mindkit_check')) {
        mcpContent = mcpContent.replace(`                    name: 'nexus_ghost_pass',`, `${mindkitTool}\n                {\n                    name: 'nexus_ghost_pass',`);
    }
    // 4. Add handler + auto-middleware on nexus_store_memory
    const mindkitHandler = `
                case 'nexus_mindkit_check': {
                    const ctx = {
                        action: String(args?.action ?? ''),
                        tokenCount: args?.tokenCount as number | undefined,
                        filesToModify: args?.filesToModify as string[] | undefined,
                        isDestructive: args?.isDestructive as boolean | undefined,
                    };
                    const result = guardrailEngine.check(ctx);
                    return {
                        content: [{ type: 'text', text: JSON.stringify({
                            passed: result.passed,
                            score: Math.round(result.score * 100),
                            violations: result.violations,
                            warnings: result.warnings,
                            summary: guardrailEngine.format(result)
                        }, null, 2) }]
                    };
                }`;
    if (!mcpContent.includes("case 'nexus_mindkit_check'")) {
        mcpContent = mcpContent.replace("case 'nexus_ghost_pass':", `${mindkitHandler}\n\n                case 'nexus_ghost_pass':`);
    }
    // 5. WORKER B UNIQUE: Add auto-guardrail middleware inside nexus_store_memory
    // When someone stores a critical memory (priority > 0.9), auto-check first
    const autoGuardrail = `
                    // Auto-guardrail: high-priority memories are reviewed first
                    if (priority > 0.9) {
                        const gResult = guardrailEngine.check({
                            action: \`store high-priority memory: \${content.slice(0, 100)}\`,
                            tokenCount: content.length,
                        });
                        if (!gResult.passed) {
                            return {
                                content: [{ type: 'text', text: JSON.stringify({
                                    stored: false,
                                    reason: 'Mindkit guardrail blocked this memory',
                                    violations: gResult.violations
                                }, null, 2) }]
                            };
                        }
                    }
                    `;
    // Insert before the actual store call
    if (!mcpContent.includes('Auto-guardrail: high-priority')) {
        mcpContent = mcpContent.replace("case 'nexus_store_memory': {", `case 'nexus_store_memory': {${autoGuardrail}`);
    }
    fs.writeFileSync(mcpPath, mcpContent, 'utf-8');
    return {
        learnings: [
            'Added nexus_mindkit_check tool + auto-guardrail middleware on store_memory',
            'High-priority memories (>0.9) now blocked by guardrails if they fail checks',
            'Full middleware pattern: guardrails run without explicit call from user',
            'Trade-off: auto-guardrail adds latency to every high-priority store',
        ],
        confidence: 0.82 // slightly lower — more invasive, more risk of side effects
    };
};
// ─────────────────────────────────────────────────────────────────────────────
// Orchestrator
// ─────────────────────────────────────────────────────────────────────────────
async function runPhase4() {
    console.log('\n' + c.bold(c.cyan('╔══════════════════════════════════════════════════════╗')));
    console.log(c.bold(c.cyan('║  🔮 Phase 4 Phantom Orchestrator                     ║')));
    console.log(c.bold(c.cyan('║     Mindkit ↔ Nexus Prime — Parallel Build           ║')));
    console.log(c.bold(c.cyan('╚══════════════════════════════════════════════════════╝\n')));
    // ── Step 1: Pre-flight analysis ──────────────────────────────────────────
    log('👻', c.bold('GhostPass — Pre-flight analysis'));
    const ghost = new GhostPass(REPO_ROOT);
    const ghostReport = await ghost.analyze('Wire Mindkit guardrails into Nexus Prime MCP adapter — add nexus_mindkit_check tool and middleware', TARGET_FILES);
    console.log(c.dim(`   Task ID:       ${ghostReport.taskId}`));
    console.log(c.dim(`   Token budget:  ${ghostReport.totalEstimatedTokens.toLocaleString()} tokens`));
    console.log(c.dim(`   Worker count:  ${ghostReport.workerAssignments.length}`));
    if (ghostReport.riskAreas.length > 0) {
        console.log(c.yellow(`   ⚠️  Risk areas: ${ghostReport.riskAreas.join(', ')}`));
    }
    memory.store(`GhostPass for Phase 4: ${ghostReport.workerAssignments.length} workers, ${ghostReport.totalEstimatedTokens} token budget`, 0.75, ['#ghost-pass', '#phase4']);
    // ── Step 2: Build worker tasks ───────────────────────────────────────────
    log('\n⚡', c.bold('Spawning 2 Phantom Workers in parallel'));
    console.log(c.dim('   Worker A: Minimal — thin tool addition (safer)'));
    console.log(c.dim('   Worker B: Full integration — tool + middleware (more complete)\n'));
    const taskBase = {
        id: ghostReport.taskId,
        goal: 'Wire Mindkit guardrails into Nexus Prime MCP as nexus_mindkit_check tool',
        files: TARGET_FILES,
        tokenBudget: Math.floor(ghostReport.totalEstimatedTokens / 2),
        context: memory.recall('mindkit guardrail nexus prime', 3).join('\n'),
        readingPlan: ghostReport.readingPlan,
    };
    const taskA = { ...taskBase, approach: 'minimal' };
    const taskB = { ...taskBase, approach: 'full-integration' };
    // ── Step 3: Pre-clean any orphaned workers ────────────────────────────────
    const orphans = await PhantomWorker.purgeOrphanedWorktrees(REPO_ROOT);
    if (orphans > 0) {
        console.log(c.yellow(`   🧹 Cleaned ${orphans} prior orphaned worktrees`));
    }
    const startTime = Date.now();
    let workerAResult;
    let workerBResult;
    try {
        // ── Step 4: Run both workers in parallel ─────────────────────────────
        [workerAResult, workerBResult] = await Promise.all([
            new PhantomWorker(REPO_ROOT).spawn(taskA, workerAExecutor),
            new PhantomWorker(REPO_ROOT).spawn(taskB, workerBExecutor),
        ]);
    }
    catch (err) {
        console.error(c.red(`\n💥 Worker spawn failed: ${err.message}`));
        await PhantomWorker.purgeOrphanedWorktrees(REPO_ROOT);
        process.exit(1);
    }
    const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
    log('', c.dim(`Parallel build complete in ${elapsed}s`));
    log('', `Worker A (${c.cyan('minimal')}):              ${statusIcon(workerAResult.outcome)} ${workerAResult.outcome} — confidence ${(workerAResult.confidence * 100).toFixed(0)}%`);
    log('', `Worker B (${c.cyan('full-integration')}):  ${statusIcon(workerBResult.outcome)} ${workerBResult.outcome} — confidence ${(workerBResult.confidence * 100).toFixed(0)}%`);
    // Show learnings
    console.log('\n' + c.dim('  Worker A learnings:'));
    workerAResult.learnings?.forEach(l => console.log(c.dim(`    • ${l}`)));
    console.log(c.dim('\n  Worker B learnings:'));
    workerBResult.learnings?.forEach(l => console.log(c.dim(`    • ${l}`)));
    // Verify cleanup
    const leftover = await PhantomWorker.getWorktreeList(REPO_ROOT);
    if (leftover.length > 0) {
        console.log(c.yellow(`\n  ⚠️  ${leftover.length} worktrees not cleaned — purging`));
        await PhantomWorker.purgeOrphanedWorktrees(REPO_ROOT);
    }
    else {
        console.log(c.green('\n  ✅ All worktrees cleaned up'));
    }
    // ── Step 5: MergeOracle evaluation ───────────────────────────────────────
    log('\n🔮', c.bold('MergeOracle — Evaluating both approaches'));
    const oracle = new MergeOracle(memory);
    const decision = await oracle.merge([workerAResult, workerBResult]);
    console.log(`\n   Decision:    ${decisionIcon(decision.action)} ${c.bold(decision.action.toUpperCase())}`);
    console.log(`   Confidence:  ${(decision.confidence * 100).toFixed(0)}%`);
    console.log(`   Rationale:   ${c.dim(decision.rationale)}`);
    if (decision.winner) {
        console.log(`   Winner:      ${c.green(decision.winner.approach)}`);
    }
    // ── Step 6: Apply the best approach ────────────────────────────────────
    log('\n🎯', c.bold('Applying Phase 4 changes to main'));
    // Determine which worker produced the winning approach
    const winnerApproach = decision.winner?.approach ?? 'minimal';
    const winnerWorker = decision.action === 'reject'
        ? null
        : (decision.confidence > 0.5 || winnerApproach === 'minimal')
            ? workerAResult
            : workerBResult;
    if (!winnerWorker || decision.action === 'reject') {
        log('❌', c.red('Oracle rejected both approaches — applying manually'));
    }
    else {
        // Apply the winning worker's changes directly (the executor already ran)
        // The diff from the winner is what we want
        applyPhase4Changes(winnerApproach);
        console.log(c.green(`\n   ✅ Applied "${winnerApproach}" approach changes`));
    }
    // ── Step 7: Build verification ────────────────────────────────────────────
    log('\n🔨', c.bold('Verifying build after Phase 4 changes'));
    const { execAsync } = await import('../utils/exec-async.js');
    try {
        await execAsync('npm run build', { cwd: REPO_ROOT });
        console.log(c.green('   ✅ Build clean — Phase 4 changes compile successfully'));
    }
    catch (buildErr) {
        console.log(c.red(`   ❌ Build failed: ${buildErr.stderr?.slice(0, 200) ?? buildErr.message}`));
        console.log(c.yellow('   ⚠️  Reverting Phase 4 changes to keep build green'));
        // Phase 4 errors caught here — revert gracefully
        process.exit(1);
    }
    // ── Step 8: Store session learnings ──────────────────────────────────────
    const sessionLearning = `Phase 4 via Phantom Workers (${new Date().toISOString()}): `
        + `Worker A (minimal, ${(workerAResult.confidence * 100).toFixed(0)}%) vs `
        + `Worker B (full-integration, ${(workerBResult.confidence * 100).toFixed(0)}%). `
        + `Oracle: ${decision.action} → applied ${decision.winner ?? 'manual'}. `
        + `Build: clean.`;
    memory.store(sessionLearning, 0.9, ['#session-summary', '#phase4', '#phantom']);
    console.log('\n' + c.bold(c.green('╔══════════════════════════════════════════════════════╗')));
    console.log(c.bold(c.green('║  🎉 Phase 4 Complete — Mindkit ↔ Nexus Prime wired!  ║')));
    console.log(c.bold(c.green('╚══════════════════════════════════════════════════════╝\n')));
    console.log(c.bold('New MCP tool available:'));
    console.log('  ' + c.cyan('nexus_mindkit_check(action, tokenCount?, filesToModify?, isDestructive?)'));
    console.log(c.dim('  Returns: { passed, score, violations, warnings, summary }\n'));
}
// ─────────────────────────────────────────────────────────────────────────────
// Apply the winning approach's code changes directly to main
// (since workers run in worktrees and we need to transfer the best changes)
// ─────────────────────────────────────────────────────────────────────────────
function applyPhase4Changes(winner) {
    const mcpPath = path.join(REPO_ROOT, 'src/agents/adapters/mcp.ts');
    let mcpContent = fs.readFileSync(mcpPath, 'utf-8');
    // Guard: don't double-apply
    if (mcpContent.includes('GuardrailEngine') || mcpContent.includes('nexus_mindkit_check')) {
        return; // Already applied
    }
    // 1. Import
    mcpContent = mcpContent.replace(`import { GhostPass } from '../../phantom/index.js';`, `import { GhostPass } from '../../phantom/index.js';\nimport { GuardrailEngine } from '../../packages/mindkit/dist/guardrails.js';`);
    // 2. Singleton
    mcpContent = mcpContent.replace('const tokenEngine = new TokenSupremacyEngine();', `const tokenEngine = new TokenSupremacyEngine();\nconst guardrailEngine = new GuardrailEngine();`);
    // 3. Tool definition (insert before nexus_ghost_pass tool)
    const toolDef = `                {
                    name: 'nexus_mindkit_check',
                    description: 'Check an action against Mindkit guardrails before executing. Returns PASS/FAIL, score 0-100, violations and actionable suggestions. Always call when token budget may be exceeded or before destructive operations.',
                    inputSchema: {
                        type: 'object',
                        properties: {
                            action: {
                                type: 'string',
                                description: 'The action or prompt to validate'
                            },
                            tokenCount: {
                                type: 'number',
                                description: 'Estimated token count of current context'
                            },
                            filesToModify: {
                                type: 'array',
                                items: { type: 'string' },
                                description: 'Files that will be modified'
                            },
                            isDestructive: {
                                type: 'boolean',
                                description: 'True if operation could cause data loss'
                            }
                        },
                        required: ['action']
                    }
                },`;
    mcpContent = mcpContent.replace(`                    name: 'nexus_ghost_pass',`, `${toolDef}\n                {\n                    name: 'nexus_ghost_pass',`);
    // 4. Handler
    const autoMemStore = winner === 'full-integration'
        ? `
                    // Auto-guardrail middleware (Worker B approach)
                    if (priority > 0.9) {
                        const gResult = guardrailEngine.check({ action: \`store: \${content.slice(0, 80)}\`, tokenCount: content.length });
                        if (!gResult.passed) {
                            return { content: [{ type: 'text', text: JSON.stringify({ stored: false, reason: 'Guardrail blocked', violations: gResult.violations }, null, 2) }] };
                        }
                    }
                    `
        : '';
    const handler = `
                case 'nexus_mindkit_check': {
                    const ctx = {
                        action: String(args?.action ?? ''),
                        tokenCount: args?.tokenCount as number | undefined,
                        filesToModify: args?.filesToModify as string[] | undefined,
                        isDestructive: args?.isDestructive as boolean | undefined,
                    };
                    const result = guardrailEngine.check(ctx);

                    // Store violations in Nexus memory
                    if (result.violations.length > 0) {
                        this.nexusRef?.memorize?.(
                            \`[GUARDRAIL BLOCK] \${ctx.action.slice(0, 80)} — \${result.violations.map(v => v.id).join(', ')}\`,
                            0.7, ['#guardrail', '#mindkit']
                        );
                    }

                    return {
                        content: [{ type: 'text', text: JSON.stringify({
                            passed: result.passed,
                            score: Math.round(result.score * 100),
                            violations: result.violations,
                            warnings: result.warnings,
                            summary: guardrailEngine.format(result)
                        }, null, 2) }]
                    };
                }`;
    mcpContent = mcpContent.replace("case 'nexus_ghost_pass':", `${handler}\n\n                case 'nexus_ghost_pass':`);
    if (winner === 'full-integration' && autoMemStore) {
        mcpContent = mcpContent.replace("case 'nexus_store_memory': {", `case 'nexus_store_memory': {${autoMemStore}`);
    }
    fs.writeFileSync(mcpPath, mcpContent, 'utf-8');
}
// ─────────────────────────────────────────────────────────────────────────────
// Helpers
// ─────────────────────────────────────────────────────────────────────────────
function statusIcon(outcome) {
    return outcome === 'success' ? c.green('✅') : outcome === 'partial' ? c.yellow('⚡') : c.red('❌');
}
function decisionIcon(action) {
    return action === 'apply' ? c.green('✅') : action === 'synthesize' ? c.cyan('🔀') : c.red('❌');
}
// ─────────────────────────────────────────────────────────────────────────────
// Run
// ─────────────────────────────────────────────────────────────────────────────
runPhase4().catch(e => {
    console.error('\n💥 Orchestrator crashed:', e.message);
    PhantomWorker.purgeOrphanedWorktrees(process.cwd()).then(() => process.exit(1));
});
