#!/usr/bin/env node
/**
 * Nexus Prime CLI
 */
import 'dotenv/config';
import { flushPrimedMcpStdioInput, primeMcpStdioInput } from './agents/adapters/mcp/stdio-buffer.js';
import { Command } from 'commander';
import { createNexusPrime } from './index.js';
import { TokenSupremacyEngine, formatReadingPlan } from './engines/token-supremacy.js';
import { summarizeExecution } from './phantom/index.js';
import fs from 'fs';
import { writeFileSync, mkdirSync, existsSync, readFileSync } from 'fs';
import { homedir } from 'os';
import path from 'path';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import { PODNetwork } from './engines/pod-network.js';
import { InstructionGateway } from './engines/instruction-gateway.js';
import { ensureBootstrap, collectBootstrapManifest, validateTargetPath, resolveCodexConfigPath, renderCodexMcpTomlConfig, writeCodexMcpConfig, hasExpectedCodexConfig, } from './engines/client-bootstrap.js';
import { resolveNexusStateDir } from './engines/runtime-registry.js';
import { runStartupHygiene } from './engines/runtime-hygiene.js';
import { buildNexusMcpServerConfig, isStableNexusMcpServerConfig } from './engines/mcp-entrypoint.js';
import { SessionDNAManager } from './engines/session-dna.js';
import { nexusEventBus } from './engines/event-bus.js';
import { buildRuntimeSetupCommand } from './cli-setup.js';
import { nexusPrimeSubBrand, sciFiPhaseHeader, runInstallBootSequence } from './utils/ascii-art.js';
import { drawCard } from './utils/ascii-card.js';
import { detectCallerIDE, getMcpConfigForIDE } from './agents/adapters/ide-compat.js';
import { cliSetup, configureIDE, computeFileHash, readSetupMarker, writeSetupMarker, SETUP_MARKER_VERSION } from './cli/install-wizard.js';
import { isNewUser, promptLicenseKey, printReturningUserBanner } from './cli/interactive-setup.js';
import { runHookBootstrap, runHookMemory, runHookMindkit, runHookGhostPass, runHookSessionDna } from './cli/hook.js';
import { resolveWorkspaceContext } from './engines/workspace-resolver.js';
import { ensureDaemonReady, getDaemonStatus, pingDaemonHealth, stopDaemon } from './daemon/client.js';
import { NexusDaemonServer } from './daemon/server.js';
import { DaemonSupervisor } from './daemon/supervisor.js';
import { startDaemonBackedMcpProxy } from './daemon/proxy.js';
import { getSharedLicenseManager, snapshotPCU, formatPCUStatus, loginFromCLI, isLoggedIn, logout, readAuthInfo } from './licensing/index.js';
import { syncLicense, requestUpgrade } from './licensing/license-sync.js';
import { runReset } from './cli/reset.js';
import { runUninstall } from './cli/uninstall.js';
import { runCleanup } from './cli/cleanup.js';
import { runDoctorStorage } from './cli/doctor-storage.js';
import { formatNexusProofReport, verifyNexusProof } from './engines/nexus-proof.js';
const tokenEngine = new TokenSupremacyEngine();
import { getNexusHookSpec, writeNexusClaudeCodeHooks, } from './install/claude-code-hooks.js';
/**
 * Write (or merge) nexus-prime Claude Code hook entries into ~/.claude/settings.json.
 * Idempotent — delegates to the shared writer in install/claude-code-hooks.ts
 * so cli.ts and install-wizard.ts cannot drift on the hook spec or dedup logic.
 */
function writeClaudeCodeHooks(settingsPath, dryRun) {
    const result = writeNexusClaudeCodeHooks(settingsPath, { dryRun });
    if (dryRun) {
        console.log('Hooks preview (would write to ~/.claude/settings.json):');
        console.log(JSON.stringify(getNexusHookSpec(), null, 2));
        return;
    }
    console.log(`   Hooks: ${settingsPath}${result.changed ? '' : ' (no change)'}`);
    result.events.forEach((ev) => {
        const tail = ev.toLowerCase().replace('tooluse', '').trim() || ev;
        console.log(`     ${ev} → nexus-prime hook ${tail}`);
    });
}
const program = new Command();
let nexus = null;
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const PACKAGE_ROOT = join(__dirname, '..');
const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
const CODEX_MANAGED_START = '<!-- nexus-prime:codex-bootstrap:start -->';
const CODEX_MANAGED_END = '<!-- nexus-prime:codex-bootstrap:end -->';
const CLAUDE_MANAGED_START = '<!-- nexus-prime:claude-bootstrap:start -->';
const CLAUDE_MANAGED_END = '<!-- nexus-prime:claude-bootstrap:end -->';
const CLINE_MANAGED_START = '<!-- nexus-prime:cline-bootstrap:start -->';
const CLINE_MANAGED_END = '<!-- nexus-prime:cline-bootstrap:end -->';
const SETUP_CLIENTS = ['codex', 'cursor', 'claude-code', 'claude-desktop', 'opencode', 'windsurf', 'antigravity', 'openclaw', 'hermes', 'nanoclaw', 'picoclaw', 'aider', 'continue', 'cline'];
const HOME_SKILL_BUNDLE_DIRS = {
    antigravity: join(homedir(), '.antigravity', 'skills', 'nexus-prime'),
    openclaw: join(homedir(), '.openclaw', 'skills', 'nexus-prime'),
    hermes: join(homedir(), '.hermes', 'skills', 'nexus-prime'),
    nanoclaw: join(homedir(), '.nanoclaw', 'skills', 'nexus-prime'),
    picoclaw: join(homedir(), '.picoclaw', 'skills', 'nexus-prime'),
};
function getWorkspaceContext() {
    return resolveWorkspaceContext();
}
function getWorkspaceRoot() {
    return getWorkspaceContext().workspaceRoot;
}
function getCliEntrypoint() {
    return path.resolve(process.argv[1] || fileURLToPath(import.meta.url));
}
function formatDaemonAddress(record) {
    return record.port ? `127.0.0.1:${record.port}` : 'pending';
}
async function ensureDaemonManaged(options = {}) {
    const workspaceContext = resolveWorkspaceContext({ workspaceRoot: getWorkspaceRoot() });
    if (options.force) {
        await stopDaemon(workspaceContext, { force: true }).catch(() => undefined);
    }
    return ensureDaemonReady(workspaceContext, {
        entrypoint: getCliEntrypoint(),
    });
}
async function ensureNexusRunning(config = {}) {
    if (!nexus) {
        nexus = createNexusPrime({
            ...config,
            runtime: {
                workspaceRoot: getWorkspaceRoot(),
            },
        });
        await nexus.start();
    }
    return nexus;
}
async function waitForAdapterConnection(activeNexus, adapterType, timeoutMs = 20_000) {
    const deadline = Date.now() + timeoutMs;
    while (Date.now() < deadline) {
        const adapter = activeNexus.getAdapters().find((candidate) => candidate.type === adapterType && candidate.connected);
        if (adapter) {
            return true;
        }
        await new Promise((resolve) => setTimeout(resolve, 50));
    }
    return false;
}
async function withDashboardSuppressed(task) {
    const previous = process.env.NEXUS_DASHBOARD_DISABLED;
    process.env.NEXUS_DASHBOARD_DISABLED = '1';
    try {
        return await task();
    }
    finally {
        if (previous === undefined) {
            delete process.env.NEXUS_DASHBOARD_DISABLED;
        }
        else {
            process.env.NEXUS_DASHBOARD_DISABLED = previous;
        }
    }
}
function printExecutionSummary(execution) {
    const verifiedWorkers = execution.workerResults.filter(result => result.verified).length;
    const modifiedFiles = execution.workerResults.reduce((sum, result) => sum + result.modifiedFiles.length, 0);
    console.log(sciFiPhaseHeader('Execution Summary', 1));
    console.log(`🧠 Runtime: ${summarizeExecution(execution)}`);
    console.log(`📁 Artifacts: ${execution.artifactsPath}`);
    console.log(`🧪 Verified Workers: ${verifiedWorkers}/${execution.workerResults.length}`);
    console.log(`📝 Modified Files: ${modifiedFiles}`);
    console.log(`⚖️  Decision: ${execution.finalDecision?.action ?? 'none'}`);
    console.log(`🛠️  Backends: memory=${execution.selectedBackends.memoryBackend}, compression=${execution.selectedBackends.compressionBackend}, consensus=${execution.selectedBackends.consensusPolicy}, dsl=${execution.selectedBackends.dslCompiler}`);
    console.log(`🧭 Workflows: ${execution.activeWorkflows.length > 0 ? execution.activeWorkflows.map(workflow => workflow.name).join(', ') : 'none'}`);
    console.log(`🎯 Promotions: ${execution.promotionDecisions.length > 0 ? execution.promotionDecisions.map(decision => `${decision.kind}:${decision.target}:${decision.approved ? 'approved' : 'held'}`).join(', ') : 'none'}`);
}
function renderTerminalCockpit(activeNexus) {
    const envelope = activeNexus.getRuntimeHealthEnvelope();
    const runtime = activeNexus.getRuntime();
    const usage = runtime.getUsageSnapshot();
    const selected = usage?.artifactSelectionAudit;
    const lines = [
        nexusPrimeSubBrand('Nexus Prime Terminal Cockpit'),
        sciFiPhaseHeader('Runtime Truth', 1),
        `Status      ${envelope.status.toUpperCase()} · workspace=${envelope.workspace.workspaceRoot}`,
        `Repo Root   ${envelope.workspace.repoRoot}`,
        `Workspace   ${envelope.workspace.source}`,
        `Synapse     ${envelope.engines.synapse.mode} · ${envelope.engines.synapse.dbPath || 'n/a'}${envelope.engines.synapse.fallbackApplied ? ' (fallback)' : ''}`,
        `Architects  ${envelope.engines.architects.mode} · ${envelope.engines.architects.dbPath || 'n/a'}${envelope.engines.architects.fallbackApplied ? ' (fallback)' : ''}`,
        `Client      ${envelope.clients.primaryClientId || 'none'} · ${envelope.clients.active}/${envelope.clients.total} active`,
        `Memory      ${envelope.memory.activeDbPath || 'n/a'}${envelope.memory.fallbackApplied ? ' (fallback)' : ''}`,
        `Worktrees   ${envelope.worktree.status}`,
        sciFiPhaseHeader('Selection Ledger', 2),
        `Summary     ${envelope.selection.summary}`,
        `Assets      selected=${envelope.selection.selected} rejected=${envelope.selection.rejected}`,
        `Ledger      ${(usage?.executionLedger?.steps?.length || 0)} steps`,
        sciFiPhaseHeader('Action Surface', 3),
        'Commands    nexus-prime doctor · nexus-prime cockpit --watch · nexus-prime bootstrap runtime',
    ];
    if (envelope.degradedReasons.length) {
        lines.push('', 'Degraded Reasons');
        envelope.degradedReasons.forEach((reason) => lines.push(`  - ${reason}`));
    }
    if (selected?.selected?.length) {
        lines.push('', 'Chosen Assets');
        selected.selected.slice(0, 6).forEach((entry) => lines.push(`  - ${entry.kind}:${entry.name} · ${entry.reason}`));
    }
    return lines.join('\n');
}
function ensureParentDir(targetPath) {
    mkdirSync(dirname(targetPath), { recursive: true });
}
function readJson(targetPath) {
    if (!existsSync(targetPath))
        return {};
    try {
        return JSON.parse(readFileSync(targetPath, 'utf8'));
    }
    catch {
        return {};
    }
}
function buildStandardMcpServerConfig(workspaceRoot) {
    return buildNexusMcpServerConfig(workspaceRoot);
}
function writeStandardMcpConfig(targetPath, workspaceRoot) {
    const existing = readJson(targetPath);
    existing.mcpServers = existing.mcpServers ?? {};
    existing.mcpServers['nexus-prime'] = buildStandardMcpServerConfig(workspaceRoot);
    delete existing.mcpServers['code-review-graph'];
    if (isNexusManagedGraphPeer(existing.mcpServers['atlas'])) {
        delete existing.mcpServers['atlas'];
    }
    ensureParentDir(targetPath);
    writeFileSync(targetPath, JSON.stringify(existing, null, 2));
}
function isNexusManagedGraphPeer(server) {
    if (!server || typeof server !== 'object' || Array.isArray(server))
        return false;
    const record = server;
    const args = Array.isArray(record['args']) ? record['args'].map(String) : [];
    return record['command'] === 'goatlas' && args.length === 1 && args[0] === 'mcp';
}
function jsonExposesInternalGraphPeer(parsed) {
    const servers = parsed?.mcpServers ?? parsed?.mcp ?? {};
    return Boolean(servers?.['code-review-graph']
        || isNexusManagedGraphPeer(servers?.['atlas']));
}
function writeOpencodeConfig(targetPath, workspaceRoot) {
    const existing = readJson(targetPath);
    const mcpConfig = buildStandardMcpServerConfig(workspaceRoot);
    const server = {
        type: 'local',
        command: mcpConfig.command,
        args: mcpConfig.args,
        environment: {
            ...mcpConfig.env,
        }
    };
    existing.mcp = existing.mcp ?? {};
    existing.mcp['nexus-prime'] = server;
    delete existing.mcp.servers;
    ensureParentDir(targetPath);
    writeFileSync(targetPath, JSON.stringify(existing, null, 2));
}
function renderCodexManagedBlock(content) {
    return [
        CODEX_MANAGED_START,
        '## Nexus Prime Bootstrap (managed)',
        '',
        '> This block is managed by `nexus-prime setup codex` or automatic bootstrap.',
        '> Keep your project-specific Codex guidance above or below it.',
        '',
        content.trim(),
        CODEX_MANAGED_END,
    ].join('\n');
}
function ensureFinalNewline(content) {
    return content.endsWith('\n') ? content : `${content}\n`;
}
function mergeCodexAgentsContent(existingContent, content) {
    const managedBlock = renderCodexManagedBlock(content);
    const existing = existingContent ?? '';
    if (!existing.trim()) {
        return [
            '# AGENTS.md',
            '',
            'This file is used by Codex and other repo-local agent tooling.',
            '',
            managedBlock,
            '',
        ].join('\n');
    }
    const startIndex = existing.indexOf(CODEX_MANAGED_START);
    const endIndex = existing.indexOf(CODEX_MANAGED_END);
    if (startIndex >= 0 && endIndex > startIndex) {
        const before = existing.slice(0, startIndex).trimEnd();
        const after = existing.slice(endIndex + CODEX_MANAGED_END.length).trim();
        return ensureFinalNewline([
            before,
            before ? '' : undefined,
            managedBlock,
            after ? '' : undefined,
            after,
        ].filter((value) => value !== undefined).join('\n'));
    }
    return ensureFinalNewline([
        existing.trimEnd(),
        '',
        managedBlock,
    ].join('\n'));
}
function hasCurrentCodexManagedBlock(targetPath, content) {
    if (!existsSync(targetPath))
        return 'missing';
    const existing = readFileSync(targetPath, 'utf8');
    const startIndex = existing.indexOf(CODEX_MANAGED_START);
    const endIndex = existing.indexOf(CODEX_MANAGED_END);
    if (startIndex < 0 || endIndex <= startIndex)
        return 'drifted';
    const currentBlock = existing.slice(startIndex, endIndex + CODEX_MANAGED_END.length).trim();
    return currentBlock === renderCodexManagedBlock(content).trim() ? 'installed' : 'drifted';
}
function renderClaudeManagedBlock(content) {
    return [
        CLAUDE_MANAGED_START,
        '## Nexus Prime Bootstrap (managed)',
        '',
        '> This block is managed by `nexus-prime setup claude`.',
        '> Keep your project-specific Claude guidance above or below it.',
        '',
        content.trim(),
        CLAUDE_MANAGED_END,
    ].join('\n');
}
function mergeClaudeContent(existingContent, content) {
    const managedBlock = renderClaudeManagedBlock(content);
    const existing = existingContent ?? '';
    if (!existing.trim()) {
        return [managedBlock, ''].join('\n');
    }
    const startIndex = existing.indexOf(CLAUDE_MANAGED_START);
    const endIndex = existing.indexOf(CLAUDE_MANAGED_END);
    if (startIndex >= 0 && endIndex > startIndex) {
        const before = existing.slice(0, startIndex).trimEnd();
        const after = existing.slice(endIndex + CLAUDE_MANAGED_END.length).trim();
        return ensureFinalNewline([
            before,
            before ? '' : undefined,
            managedBlock,
            after ? '' : undefined,
            after,
        ].filter((value) => value !== undefined).join('\n'));
    }
    return ensureFinalNewline([existing.trimEnd(), '', managedBlock].join('\n'));
}
function hasCurrentClaudeManagedBlock(targetPath, content) {
    if (!existsSync(targetPath))
        return 'missing';
    const existing = readFileSync(targetPath, 'utf8');
    const startIndex = existing.indexOf(CLAUDE_MANAGED_START);
    const endIndex = existing.indexOf(CLAUDE_MANAGED_END);
    if (startIndex < 0 || endIndex <= startIndex)
        return 'drifted';
    const currentBlock = existing.slice(startIndex, endIndex + CLAUDE_MANAGED_END.length).trim();
    return currentBlock === renderClaudeManagedBlock(content).trim() ? 'installed' : 'drifted';
}
function renderClineManagedBlock(content) {
    return [
        CLINE_MANAGED_START,
        '## Nexus Prime Bootstrap (managed)',
        '',
        '> This block is managed by `nexus-prime setup cline`.',
        '> Keep your project-specific Cline guidance above or below it.',
        '',
        content.trim(),
        CLINE_MANAGED_END,
    ].join('\n');
}
function mergeClinerules(existingContent, content) {
    const managedBlock = renderClineManagedBlock(content);
    const existing = existingContent ?? '';
    if (!existing.trim()) {
        return [managedBlock, ''].join('\n');
    }
    const startIndex = existing.indexOf(CLINE_MANAGED_START);
    const endIndex = existing.indexOf(CLINE_MANAGED_END);
    if (startIndex >= 0 && endIndex > startIndex) {
        const before = existing.slice(0, startIndex).trimEnd();
        const after = existing.slice(endIndex + CLINE_MANAGED_END.length).trim();
        return ensureFinalNewline([
            before,
            before ? '' : undefined,
            managedBlock,
            after ? '' : undefined,
            after,
        ].filter((value) => value !== undefined).join('\n'));
    }
    return ensureFinalNewline([existing.trimEnd(), '', managedBlock].join('\n'));
}
function hasCurrentClineManagedBlock(targetPath, content) {
    if (!existsSync(targetPath))
        return 'missing';
    const existing = readFileSync(targetPath, 'utf8');
    const startIndex = existing.indexOf(CLINE_MANAGED_START);
    const endIndex = existing.indexOf(CLINE_MANAGED_END);
    if (startIndex < 0 || endIndex <= startIndex)
        return 'drifted';
    const currentBlock = existing.slice(startIndex, endIndex + CLINE_MANAGED_END.length).trim();
    return currentBlock === renderClineManagedBlock(content).trim() ? 'installed' : 'drifted';
}
function buildInstructionFiles(clientId) {
    const gateway = new InstructionGateway(PACKAGE_ROOT);
    const gatewayClientId = (clientId === 'claude' || clientId === 'claude-desktop') ? 'claude-code' : clientId;
    const bundle = gateway.renderClientBootstrapBundle(gatewayClientId, {
        toolProfile: 'autonomous',
    });
    const workspaceRoot = getWorkspaceRoot();
    if (clientId === 'codex') {
        return bundle.artifacts.map((artifact) => ({
            path: join(workspaceRoot, 'AGENTS.md'),
            content: artifact.content,
            mode: 'codex-managed-agents',
        }));
    }
    if (clientId === 'cursor') {
        return bundle.artifacts.map((artifact) => ({
            path: join(workspaceRoot, '.cursor', 'rules', artifact.fileName),
            content: artifact.content,
        }));
    }
    if (clientId === 'windsurf') {
        return bundle.artifacts.map((artifact) => ({
            path: join(workspaceRoot, artifact.fileName),
            content: artifact.content,
        }));
    }
    const homeSkillDir = HOME_SKILL_BUNDLE_DIRS[clientId];
    if (homeSkillDir) {
        return bundle.artifacts.map((artifact) => ({
            path: join(homeSkillDir, artifact.fileName),
            content: artifact.content,
        }));
    }
    if (clientId === 'claude' || clientId === 'claude-code') {
        return bundle.artifacts.map((artifact) => ({
            path: join(workspaceRoot, 'CLAUDE.md'),
            content: artifact.content,
            mode: 'claude-managed',
        }));
    }
    if (clientId === 'claude-desktop') {
        return bundle.artifacts.map((artifact) => ({
            path: join(homedir(), '.claude', 'CLAUDE.md'),
            content: artifact.content,
            mode: 'claude-managed',
        }));
    }
    if (clientId === 'cline') {
        return bundle.artifacts.map((artifact) => ({
            path: join(workspaceRoot, '.clinerules'),
            content: artifact.content,
            mode: 'cline-managed',
        }));
    }
    // aider, continue: no standard auto-read location; use artifact.fileName under .agent/client-bootstrap/
    return bundle.artifacts.map((artifact) => ({
        path: join(workspaceRoot, '.agent', 'client-bootstrap', artifact.fileName),
        content: artifact.content,
    }));
}
function resolveClaudeDesktopConfigPath() {
    if (process.platform === 'darwin') {
        return join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
    }
    if (process.platform === 'win32') {
        return join(process.env.APPDATA || join(homedir(), 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');
    }
    return join(homedir(), '.claude', 'claude_desktop_config.json');
}
function getSetupDefinition(clientId) {
    const workspaceRoot = getWorkspaceRoot();
    const instructionFiles = buildInstructionFiles(clientId);
    if (clientId === 'codex') {
        return {
            id: clientId,
            label: 'Codex',
            workspaceRoot,
            configPath: resolveCodexConfigPath(),
            instructionFiles,
        };
    }
    if (clientId === 'cursor') {
        return {
            id: clientId,
            label: 'Cursor',
            workspaceRoot,
            configPath: join(homedir(), '.cursor', 'mcp.json'),
            instructionFiles,
        };
    }
    if (clientId === 'claude' || clientId === 'claude-code') {
        return {
            id: clientId,
            label: 'Claude Code',
            workspaceRoot,
            configPath: join(workspaceRoot, '.mcp.json'),
            instructionFiles,
        };
    }
    if (clientId === 'claude-desktop') {
        return {
            id: clientId,
            label: 'Claude Desktop',
            workspaceRoot,
            configPath: resolveClaudeDesktopConfigPath(),
            instructionFiles,
        };
    }
    if (clientId === 'opencode') {
        return {
            id: clientId,
            label: 'Opencode',
            workspaceRoot,
            configPath: join(homedir(), '.config', 'opencode', 'opencode.json'),
            instructionFiles,
        };
    }
    if (clientId === 'windsurf') {
        return {
            id: clientId,
            label: 'Windsurf',
            workspaceRoot,
            configPath: join(homedir(), '.windsurf', 'mcp.json'),
            instructionFiles,
        };
    }
    if (clientId === 'antigravity') {
        return {
            id: clientId,
            label: 'Antigravity / OpenClaw',
            workspaceRoot,
            configPath: join(homedir(), '.antigravity', 'mcp.json'),
            instructionFiles,
        };
    }
    if (clientId === 'aider') {
        return {
            id: clientId,
            label: 'Aider',
            workspaceRoot,
            configPath: join(homedir(), '.aider', 'mcp.json'),
            instructionFiles,
        };
    }
    if (clientId === 'continue') {
        return {
            id: clientId,
            label: 'Continue.dev',
            workspaceRoot,
            configPath: join(homedir(), '.continue', 'config.json'),
            instructionFiles,
        };
    }
    if (clientId === 'openclaw') {
        return {
            id: clientId,
            label: 'OpenClaw',
            workspaceRoot,
            configPath: join(homedir(), '.openclaw', 'openclaw.json'),
            instructionFiles,
        };
    }
    if (clientId === 'hermes') {
        return {
            id: clientId,
            label: 'Hermes',
            workspaceRoot,
            configPath: join(homedir(), '.hermes', 'mcp.json'),
            instructionFiles,
        };
    }
    if (clientId === 'nanoclaw') {
        return {
            id: clientId,
            label: 'NanoClaw',
            workspaceRoot,
            configPath: join(homedir(), '.nanoclaw', 'mcp.json'),
            instructionFiles,
        };
    }
    if (clientId === 'picoclaw') {
        return {
            id: clientId,
            label: 'PicoClaw',
            workspaceRoot,
            configPath: join(homedir(), '.picoclaw', 'mcp.json'),
            instructionFiles,
        };
    }
    return {
        id: clientId,
        label: 'Cline',
        workspaceRoot,
        configPath: join(homedir(), '.vscode', 'cline-mcp.json'),
        instructionFiles,
    };
}
function installSetup(definition) {
    ensureMemoryHookSeed(definition.workspaceRoot);
    if (definition.configPath) {
        if (definition.id === 'codex' && definition.configPath.endsWith('.toml')) {
            writeCodexMcpConfig(definition.configPath);
        }
        else if (definition.id === 'opencode') {
            writeOpencodeConfig(definition.configPath, definition.workspaceRoot);
        }
        else {
            writeStandardMcpConfig(definition.configPath, definition.workspaceRoot);
        }
    }
    for (const file of definition.instructionFiles) {
        ensureParentDir(file.path);
        if (file.mode === 'codex-managed-agents') {
            const existing = existsSync(file.path) ? readFileSync(file.path, 'utf8') : null;
            writeFileSync(file.path, mergeCodexAgentsContent(existing, file.content), 'utf8');
            continue;
        }
        if (file.mode === 'claude-managed') {
            const existing = existsSync(file.path) ? readFileSync(file.path, 'utf8') : null;
            writeFileSync(file.path, mergeClaudeContent(existing, file.content), 'utf8');
            continue;
        }
        if (file.mode === 'cline-managed') {
            const existing = existsSync(file.path) ? readFileSync(file.path, 'utf8') : null;
            writeFileSync(file.path, mergeClinerules(existing, file.content), 'utf8');
            continue;
        }
        writeFileSync(file.path, file.content, 'utf8');
    }
}
const MEMORY_HOOK_SEEDS = [
    {
        relativePath: '.agents/hooks/memory-stored-review.md',
        content: `---
name: memory-stored-review
description: Preferred repo-local review hook for important stored memories.
trigger: memory.stored
riskClass: read
domain: memory
---

Project-local hook seed. Customize this file when memory writes need repo-specific review rules.
`,
    },
    {
        relativePath: '.agent/hooks/memory-stored-review.md',
        content: `---
name: memory-stored-review
description: Local review hook for important stored memories.
trigger: memory.stored
riskClass: read
domain: memory
---

Project-local hook seed. Customize this file when memory writes need repo-specific review rules.
`,
    },
];
function ensureMemoryHookSeed(workspaceRoot) {
    for (const seed of MEMORY_HOOK_SEEDS) {
        const target = join(workspaceRoot, seed.relativePath);
        if (existsSync(target))
            continue;
        ensureParentDir(target);
        writeFileSync(target, seed.content, 'utf8');
    }
}
function printSetupPreview(definition) {
    console.log(`--- ${definition.label.toUpperCase()} SETUP PREVIEW ---`);
    if (definition.configPath) {
        console.log(`Config: ${definition.configPath}`);
        if (definition.id === 'codex' && definition.configPath.endsWith('.toml')) {
            console.log(renderCodexMcpTomlConfig());
        }
        else {
            console.log(JSON.stringify(definition.id === 'opencode'
                ? {
                    mcp: {
                        servers: [{ id: 'nexus-prime', ...buildStandardMcpServerConfig(definition.workspaceRoot) }]
                    }
                }
                : {
                    mcpServers: {
                        'nexus-prime': buildStandardMcpServerConfig(definition.workspaceRoot)
                    }
                }, null, 2));
        }
    }
    for (const file of definition.instructionFiles) {
        console.log(`Instruction: ${file.path}`);
        console.log(file.content);
    }
}
function hasExpectedConfig(definition) {
    if (!definition.configPath || !existsSync(definition.configPath))
        return false;
    if (definition.id === 'codex') {
        return hasExpectedCodexConfig(definition.configPath);
    }
    try {
        const parsed = JSON.parse(readFileSync(definition.configPath, 'utf8'));
        if (jsonExposesInternalGraphPeer(parsed))
            return false;
        if (definition.id === 'opencode') {
            const server = parsed?.mcp?.['nexus-prime'];
            return Boolean(server && isStableNexusMcpServerConfig(server, 'environment', definition.workspaceRoot));
        }
        const server = parsed?.mcpServers?.['nexus-prime'];
        return Boolean(server && isStableNexusMcpServerConfig(server, 'env', definition.workspaceRoot));
    }
    catch {
        return false;
    }
}
function instructionState(definition) {
    let hasAny = false;
    for (const file of definition.instructionFiles) {
        if (file.mode === 'codex-managed-agents') {
            const codexState = hasCurrentCodexManagedBlock(file.path, file.content);
            if (codexState === 'drifted')
                return 'drifted';
            if (codexState === 'installed')
                hasAny = true;
            continue;
        }
        if (file.mode === 'claude-managed') {
            const claudeState = hasCurrentClaudeManagedBlock(file.path, file.content);
            if (claudeState === 'drifted')
                return 'drifted';
            if (claudeState === 'installed')
                hasAny = true;
            continue;
        }
        if (file.mode === 'cline-managed') {
            const clineState = hasCurrentClineManagedBlock(file.path, file.content);
            if (clineState === 'drifted')
                return 'drifted';
            if (clineState === 'installed')
                hasAny = true;
            continue;
        }
        if (!existsSync(file.path))
            continue;
        hasAny = true;
        if (readFileSync(file.path, 'utf8') !== file.content) {
            return 'drifted';
        }
    }
    if (!hasAny)
        return 'missing';
    return definition.instructionFiles.every((file) => existsSync(file.path)) ? 'installed' : 'missing';
}
const MEMORY_HOOK_SETUP_CLIENTS = new Set(['codex', 'cursor', 'claude', 'claude-code', 'claude-desktop']);
function setupInstructionMentionsMemoryHook(content) {
    return content.includes('nexus_store_memory') && /memory hooks?/i.test(content);
}
function setupHasInstructionMemoryHook(definition) {
    return definition.instructionFiles.some((file) => {
        if (!existsSync(file.path))
            return false;
        try {
            return setupInstructionMentionsMemoryHook(readFileSync(file.path, 'utf8'));
        }
        catch {
            return false;
        }
    });
}
function setupHasRepoMemoryHookSeed(workspaceRoot) {
    return ['.agents/hooks/memory-stored-review.md', '.agent/hooks/memory-stored-review.md']
        .some((relativePath) => existsSync(join(workspaceRoot, relativePath)));
}
function setupHasClaudeCodeMemoryHook() {
    const settingsPath = join(homedir(), '.claude', 'settings.json');
    if (!existsSync(settingsPath))
        return false;
    try {
        const parsed = JSON.parse(readFileSync(settingsPath, 'utf8'));
        return Boolean(parsed?.hooks?.PostToolUse?.some((entry) => (entry?.hooks?.some((hook) => hook?.command === 'nexus-prime hook memory'))));
    }
    catch {
        return false;
    }
}
function setupMemoryHookStatus(definition) {
    if (!MEMORY_HOOK_SETUP_CLIENTS.has(definition.id)) {
        return { memoryHookReady: false, memoryHookSummary: 'Memory hook readiness is not tracked for this client' };
    }
    const instructionReady = setupHasInstructionMemoryHook(definition);
    const repoHookReady = setupHasRepoMemoryHookSeed(definition.workspaceRoot);
    const nativeHookRequired = definition.id === 'claude' || definition.id === 'claude-code';
    const nativeHookReady = nativeHookRequired ? setupHasClaudeCodeMemoryHook() : true;
    const memoryHookReady = instructionReady && repoHookReady && nativeHookReady;
    const missing = [
        instructionReady ? null : 'client instruction wording',
        repoHookReady ? null : 'repo memory.stored hook seed',
        nativeHookReady ? null : 'Claude Code PostToolUse hook',
    ].filter(Boolean);
    return {
        memoryHookReady,
        memoryHookSummary: memoryHookReady ? 'Memory hooks ready' : `Memory hooks incomplete: ${missing.join(', ')}`,
    };
}
function statusForDefinition(definition) {
    const configOk = definition.configPath ? hasExpectedConfig(definition) : true;
    const instructions = instructionState(definition);
    const memoryHook = setupMemoryHookStatus(definition);
    if (configOk && instructions === 'installed') {
        return {
            state: 'installed',
            summary: definition.configPath ? 'Config and client instructions are current' : 'Managed client instructions are current',
            ...memoryHook,
        };
    }
    if ((definition.configPath && existsSync(definition.configPath)) || instructions !== 'missing') {
        return {
            state: 'drifted',
            summary: definition.configPath
                ? 'Setup exists but is missing the autonomous profile or current instructions'
                : 'A client instruction file exists, but the managed Nexus Prime bootstrap block is missing or outdated',
            ...memoryHook,
        };
    }
    return {
        state: 'missing',
        summary: definition.configPath ? 'Setup not installed yet' : 'No managed client instruction file installed yet',
        ...memoryHook,
    };
}
program
    .name('nexus-prime')
    .description('🧬 Nexus Prime - Local-first MCP control plane for coding agents')
    .version(packageJson.version);
program.addHelpText('beforeAll', `\n${nexusPrimeSubBrand('Nexus Prime CLI Command Surface')}\n`);
program
    .command('init')
    .description('Initialize a new Nexus Prime network')
    .action(async () => {
    console.log('Initializing Nexus Prime...');
    nexus = createNexusPrime({
        adapters: ['openclaw'],
        runtime: {
            workspaceRoot: getWorkspaceRoot(),
        },
    });
    await nexus.start();
    console.log('✅ Nexus Prime initialized');
});
program
    .command('start')
    .description('Start Nexus Prime daemon')
    .option('--force', 'Force restart if already running')
    .action(async (options) => {
    try {
        const record = await ensureDaemonManaged({ force: options.force });
        const dashboardPort = process.env.NEXUS_DASHBOARD_PORT ?? '3377';
        const health = await pingDaemonHealth(record).catch(() => null);
        const dashboardUrl = health?.dashboardUrl ?? `http://localhost:${dashboardPort}`;
        console.log(`Nexus Prime daemon running (pid ${record.pid}, ${formatDaemonAddress(record)})`);
        console.log(`Dashboard: ${dashboardUrl}`);
    }
    catch (err) {
        console.error(`Failed to start daemon: ${err.message}`);
        process.exit(1);
    }
});
program
    .command('stop')
    .description('Stop Nexus Prime daemon')
    .option('--force', 'Force kill if graceful stop fails')
    .action(async (options) => {
    const workspaceContext = resolveWorkspaceContext({ workspaceRoot: getWorkspaceRoot() });
    try {
        const result = await stopDaemon(workspaceContext, { force: options.force });
        if (result.stopped) {
            console.log(result.stale
                ? 'Cleaned up stale daemon lock.'
                : `Nexus Prime daemon stopped (pid ${result.record?.pid ?? 'unknown'}).`);
        }
        else {
            console.log('No running daemon found.');
        }
    }
    catch (err) {
        console.error(`Failed to stop daemon: ${err.message}`);
        process.exit(1);
    }
});
program
    .command('install')
    .description('Install Nexus Prime into your environment (detects IDEs, writes MCP configs)')
    .option('--dry-run', 'Preview changes without writing files')
    .option('--silent', 'Suppress informational output')
    .action((opts) => {
    const args = [];
    if (opts.dryRun)
        args.push('--dry-run');
    if (opts.silent)
        args.push('--silent');
    void cliSetup(args);
});
program
    .command('bootstrap')
    .description('Internal auto-bootstrap support for install/startup flows')
    .addCommand(new Command('home')
    .option('--silent', 'Suppress console output')
    .action((options) => {
    const manifest = ensureBootstrap({
        packageRoot: PACKAGE_ROOT,
        workspaceRoot: getWorkspaceRoot(),
        phase: 'install',
        silent: options.silent,
    });
    if (!options.silent) {
        console.log('✅ Home-scoped Nexus Prime bootstrap refreshed');
        manifest.clients.forEach((client) => {
            console.log(`  - ${client.label}: ${client.state}`);
        });
    }
}))
    .addCommand(new Command('runtime')
    .option('--silent', 'Suppress console output')
    .action((options) => {
    const manifest = ensureBootstrap({
        packageRoot: PACKAGE_ROOT,
        workspaceRoot: getWorkspaceRoot(),
        phase: 'runtime',
        silent: options.silent,
    });
    if (!options.silent) {
        console.log('✅ Runtime bootstrap refreshed');
        manifest.clients.forEach((client) => {
            console.log(`  - ${client.label}: ${client.state}`);
        });
    }
}))
    .addCommand(new Command('status')
    .action(() => {
    const manifest = collectBootstrapManifest({
        packageRoot: PACKAGE_ROOT,
        workspaceRoot: getWorkspaceRoot(),
    });
    console.log(JSON.stringify(manifest, null, 2));
}));
program
    .command('daemon')
    .description('Daemon lifecycle (internal)')
    .addCommand(new Command('__serve')
    .description('Internal: run the daemon server process (do not call directly)')
    .action(async () => {
    // Opt the daemon into the deferred-bootstrap fast-start path so the
    // dashboard port listens before the (3+ second) workspace bootstrap
    // file I/O completes. Tests that construct NexusPrime directly do not
    // set this flag, so their synchronous workspace-file assertions still
    // see a fully-initialized state by the time start() resolves.
    if (process.env.NEXUS_DAEMON_FAST_START === undefined) {
        process.env.NEXUS_DAEMON_FAST_START = '1';
    }
    // Keep daemon startup fast, but do not disable workforce. Synapse and
    // Architects can lazily warm on first hire/tool call unless the operator
    // explicitly sets the NEXUS_DISABLE_WORKFORCE escape hatch.
    if (process.env.NEXUS_SYNAPSE_LAZY === undefined) {
        process.env.NEXUS_SYNAPSE_LAZY = '1';
    }
    if (process.env.NEXUS_ARCHITECTS_LAZY === undefined) {
        process.env.NEXUS_ARCHITECTS_LAZY = '1';
    }
    const workspaceContext = resolveWorkspaceContext({ workspaceRoot: getWorkspaceRoot() });
    const daemon = new NexusDaemonServer(workspaceContext);
    const { started, record } = await daemon.start();
    if (!started) {
        console.error(`Daemon already running (pid ${record.pid}, ${formatDaemonAddress(record)})`);
        process.exit(1);
    }
    console.error(`Nexus Prime daemon started (pid ${record.pid}, ${formatDaemonAddress(record)})`);
    // Liveness supervisor: pings /health every 30s; restarts the daemon if
    // 3 consecutive timeouts. Opt out with NEXUS_SUPERVISOR_DISABLED=1.
    const supervisor = new DaemonSupervisor({
        daemon,
        workspaceContext,
        getLockRecord: () => daemon.getLockRecord(),
    });
    supervisor.start();
}));
program
    .command('mcp')
    .description('Start Nexus Prime as an MCP Server over stdio')
    .option('--standalone', 'Skip daemon detection, run in-process (debug mode)')
    .action(async (options) => {
    // stdio transport requires strict JSON-RPC on stdout — no console.log here.
    primeMcpStdioInput();
    const workspaceContext = resolveWorkspaceContext({ workspaceRoot: getWorkspaceRoot() });
    const caller = detectCallerIDE();
    process.env.NEXUS_DAEMON_AUTOSPAWN ??= '0';
    process.env.NEXUS_DASHBOARD_IN_MCP ??= '0';
    process.env.NEXUS_ARCHITECTS_LAZY ??= '1';
    process.env.NEXUS_SYNAPSE_LAZY ??= '1';
    process.env.NEXUS_AUTOMATION_SCHEDULER_DISABLED ??= '1';
    const marker = readSetupMarker();
    const autoConfigEnabled = process.env.NEXUS_MCP_AUTO_CONFIG === '1';
    if (caller && autoConfigEnabled) {
        const isConfigured = marker?.configuredIDEs?.includes(caller) ?? false;
        const storedHash = marker?.writtenHash?.[caller];
        if (isConfigured && storedHash !== undefined) {
            // Drift check: re-configure if the MCP config was changed or removed on disk.
            const { configPath } = getMcpConfigForIDE(caller, workspaceContext.workspaceRoot);
            const currentHash = configPath ? computeFileHash(configPath) : null;
            if (currentHash !== storedHash) {
                console.error(`[nexus-prime] Config drift detected for ${caller} — restoring...`);
                try {
                    const result = await configureIDE(caller, {
                        workspaceRoot: workspaceContext.workspaceRoot,
                        verbose: false,
                    });
                    if (result.writtenHash !== null) {
                        writeSetupMarker({
                            version: SETUP_MARKER_VERSION,
                            configuredIDEs: marker?.configuredIDEs ?? [caller],
                            setupCompletedAt: marker?.setupCompletedAt ?? Date.now(),
                            writtenHash: { ...(marker?.writtenHash ?? {}), [caller]: result.writtenHash },
                        });
                    }
                    console.error(`[nexus-prime] ${caller} MCP config restored.`);
                }
                catch (err) {
                    console.error(`[nexus-prime] Drift re-configure failed: ${err?.message ?? err}`);
                }
            }
        }
        else if (!isConfigured) {
            // First run from this IDE — write config and record hash.
            console.error(`[nexus-prime] First run from ${caller} — writing MCP config...`);
            try {
                const result = await configureIDE(caller, {
                    workspaceRoot: workspaceContext.workspaceRoot,
                    verbose: false,
                });
                writeSetupMarker({
                    version: SETUP_MARKER_VERSION,
                    configuredIDEs: [...(marker?.configuredIDEs ?? []), caller],
                    setupCompletedAt: Date.now(),
                    writtenHash: {
                        ...(marker?.writtenHash ?? {}),
                        ...(result.writtenHash !== null ? { [caller]: result.writtenHash } : {}),
                    },
                });
                console.error(`[nexus-prime] ${caller} MCP config written. Future runs skip this step.`);
            }
            catch (err) {
                console.error(`[nexus-prime] Auto-config failed: ${err?.message ?? err}. Run \`nexus-prime setup\` manually.`);
            }
        }
    }
    // Try daemon-backed proxy first unless --standalone is passed
    const parsedDaemonTimeout = Number(process.env.NEXUS_MCP_DAEMON_TIMEOUT_MS ?? 5000);
    const mcpDaemonTimeoutMs = Number.isFinite(parsedDaemonTimeout)
        ? Math.max(1000, Math.min(parsedDaemonTimeout, 15000))
        : 5000;
    if (!options.standalone) {
        try {
            const status = await getDaemonStatus(workspaceContext);
            if (status.running && status.healthy) {
                console.error('Connecting to Nexus Prime daemon...');
                await startDaemonBackedMcpProxy(workspaceContext, {
                    entrypoint: getCliEntrypoint(),
                    timeoutMs: mcpDaemonTimeoutMs,
                });
                return;
            }
            // Daemon not running. Auto-spawn is on by default; set
            // NEXUS_DAEMON_AUTOSPAWN=0 to force standalone mode.
            // If enabled, spawn a
            // detached daemon and wait for the lock — exactly the dance
            // ensureDaemonReady already does. Otherwise fall through to
            // standalone with a loud hint.
            if (process.env.NEXUS_DAEMON_AUTOSPAWN !== '0') {
                console.error('[nexus-prime] No daemon running — auto-spawning shared daemon…');
                try {
                    await ensureDaemonReady(workspaceContext, {
                        entrypoint: getCliEntrypoint(),
                        timeoutMs: mcpDaemonTimeoutMs,
                    });
                    await startDaemonBackedMcpProxy(workspaceContext, {
                        entrypoint: getCliEntrypoint(),
                        timeoutMs: mcpDaemonTimeoutMs,
                    });
                    return;
                }
                catch (spawnError) {
                    console.error(`[nexus-prime] Auto-spawn failed: ${spawnError?.message ?? spawnError}`);
                    console.error('[nexus-prime] Falling back to standalone mode.');
                }
            }
        }
        catch {
            // Daemon unreachable — fall through to standalone
        }
    }
    // Standalone mode: run NexusPrime in-process (no daemon)
    if (!options.standalone) {
        drawCard({
            title: 'NEXUS PRIME IS RUNNING IN STANDALONE MODE',
            color: '33',
            width: 76,
            lines: [
                'This uses ~12 threads and ~80MB per IDE tab.',
                'IDE MCP configs keep daemon auto-spawn off to avoid host startup hangs.',
                'For shared single-instance mode run: nexus-prime daemon',
                'Queued-run insurance remains daemon-only; standalone tools run synchronously.',
            ],
        });
    }
    console.error('Starting Nexus Prime MCP Server (standalone)...');
    setTimeout(() => {
        void runStartupHygiene({
            repoRoot: workspaceContext.repoRoot,
            workspaceStateRoot: workspaceContext.stateRoot,
            mode: 'stale',
        }).catch((error) => {
            const message = error instanceof Error ? error.message : String(error);
            console.error(`[nexus-prime] Startup hygiene skipped: ${message}`);
        });
    }, 0);
    nexus = createNexusPrime({
        adapters: ['mcp'],
        runtime: {
            workspaceRoot: getWorkspaceRoot(),
        },
    });
    const startup = nexus.start();
    const adapterReady = await Promise.race([
        startup.then(() => true),
        waitForAdapterConnection(nexus, 'mcp'),
    ]);
    if (!adapterReady) {
        throw new Error('MCP adapter did not become ready before the startup deadline.');
    }
    flushPrimedMcpStdioInput();
    await startup;
    console.error('Nexus Prime MCP Server running on stdio (standalone)');
    console.error('Memory persistence: active (~/.nexus-prime/memory.db)');
    const shutdown = async (signal) => {
        nexusEventBus.emit('nexus.shutdown', { signal });
        nexus?.getOrchestrator().dispose();
        console.error('Flushing memory to disk...');
        nexus?.flushMemory();
        if (nexus)
            await nexus.stop();
        PODNetwork.instance?.destroy();
        process.exit(0);
    };
    const syncExitFallback = () => {
        nexus?.flushMemory();
    };
    process.on('SIGINT', () => void shutdown('SIGINT'));
    process.on('SIGTERM', () => void shutdown('SIGTERM'));
    process.once('exit', syncExitFallback);
});
program
    .command('optimize')
    .description('Generate a token-efficient reading plan for a task')
    .argument('<task>', 'Task description')
    .option('-f, --files <files...>', 'File paths to evaluate')
    .action(async (task, options) => {
    const files = await Promise.all((options.files ?? []).map(async (p) => {
        try {
            const stat = await fs.promises.stat(p);
            return { path: p, sizeBytes: stat.size, lastModified: stat.mtimeMs };
        }
        catch {
            return { path: p, sizeBytes: 0 };
        }
    }));
    const plan = await tokenEngine.plan(task, files);
    console.log(formatReadingPlan(plan));
});
program
    .command('adapter')
    .description('Manage adapters')
    .addCommand(new Command('add')
    .argument('<type>', 'Adapter type (openclaw, hermes, nanoclaw, picoclaw, claude-code, ruflo)')
    .action(async (type) => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    await nexus.addAdapter(type);
    console.log(`✅ Adapter ${type} added`);
}))
    .addCommand(new Command('list')
    .action(() => {
    if (!nexus) {
        console.log('⚠️  Nexus Prime not running. Run "nexus-prime start" first.');
        return;
    }
    const adapters = nexus.getAdapters();
    console.log('📦 Adapters:');
    adapters.forEach(a => {
        console.log(`  - ${a.name} (${a.type}) ${a.connected ? '✅' : '❌'}`);
    });
}));
program
    .command('agents')
    .description('Manage agents')
    .addCommand(new Command('list')
    .action(() => {
    if (!nexus) {
        console.log('⚠️  Nexus Prime not running. Run "nexus-prime start" first.');
        return;
    }
    const agents = nexus.getAllAgents();
    console.log('🤖 Agents:');
    agents.forEach(a => {
        console.log(`  - ${a.id} (${a.type}) - ${a.state.current}`);
    });
}))
    .addCommand(new Command('spawn')
    .argument('<type>', 'Agent type (researcher, coder, reviewer, etc.)')
    .option('-t, --task <task>', 'Initial task')
    .action(async (type, options) => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    const agent = await nexus.createAgent(type);
    console.log(`✅ Spawned agent: ${agent.id}`);
    if (options.task) {
        const result = await nexus.execute(agent.id, options.task);
        console.log(`📝 Result: ${result.result}`);
        printExecutionSummary(result.execution);
    }
}));
program
    .command('execute')
    .description('Execute a task with an agent')
    .argument('<agentId>', 'Agent ID')
    .argument('<task>', 'Task description')
    .option('-f, --files <files...>', 'Files relevant to the execution')
    .option('-w, --workers <number>', 'Number of coder workers')
    .option('--verify <commands...>', 'Verification commands')
    .option('--actions-file <path>', 'JSON file containing runtime action bindings')
    .option('--nxl-file <path>', 'NXL/YAML file to compile and execute')
    .option('--skills <skills...>', 'Runtime skill selectors')
    .option('--workflows <workflows...>', 'Runtime workflow selectors')
    .option('--hooks <hooks...>', 'Runtime hook selectors')
    .option('--automations <automations...>', 'Runtime automation selectors')
    .option('--memory-backend <id>', 'Memory backend selector')
    .option('--compression-backend <id>', 'Compression backend selector')
    .option('--dsl-compiler <id>', 'DSL compiler selector')
    .option('--backend-mode <mode>', 'Backend mode (default, shadow, experimental)')
    .option('--shield-policy <policy>', 'Security shield policy (balanced, strict, permissive)')
    .option('--memory-policy <policy>', 'Memory policy mode (balanced, strict, off)')
    .action(async (agentId, task, options) => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    const parsedWorkers = options.workers ? parseInt(options.workers, 10) : undefined;
    const actions = options.actionsFile
        ? JSON.parse(readFileSync(options.actionsFile, 'utf8'))
        : undefined;
    if (options.nxlFile) {
        const rawScript = readFileSync(options.nxlFile, 'utf8');
        const execution = await nexus.getRuntime().runNXL(task, rawScript, 'CLI');
        console.log(`📝 Result: ${execution.result}`);
        printExecutionSummary(execution);
        return;
    }
    const result = await nexus.execute(agentId, task, {
        files: options.files,
        workers: parsedWorkers,
        verifyCommands: options.verify,
        actions,
        skillNames: options.skills,
        workflowSelectors: options.workflows,
        hookSelectors: options.hooks,
        automationSelectors: options.automations,
        backendSelectors: {
            memoryBackend: options.memoryBackend,
            compressionBackend: options.compressionBackend,
            dslCompiler: options.dslCompiler,
        },
        backendMode: options.backendMode,
        shieldPolicy: options.shieldPolicy,
        memoryPolicy: options.memoryPolicy ? { mode: options.memoryPolicy, quarantineTag: '#quarantine' } : undefined,
    });
    console.log(`📝 Result: ${result.result}`);
    console.log(`📊 Value: ${result.experience.value.toFixed(2)}`);
    printExecutionSummary(result.execution);
});
program
    .command('memory')
    .description('Query memory')
    .addCommand(new Command('search')
    .argument('<query>', 'Search query')
    .option('-k, --top <number>', 'Number of results', '10')
    .action(async (query, options) => {
    if (!nexus) {
        console.log('⚠️  Nexus Prime not running. Run "nexus-prime start" first.');
        return;
    }
    const results = await nexus.recallMemory(query, parseInt(options.top));
    console.log('🔍 Results:');
    results.forEach(r => console.log(`  - ${r}`));
}))
    .addCommand(new Command('audit')
    .option('-l, --limit <number>', 'Maximum memories to scan', '80')
    .action(async (options) => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    const audit = nexus.getRuntime().auditMemory(parseInt(options.limit, 10));
    console.log(JSON.stringify(audit ?? { scanned: 0, quarantined: [], findings: [] }, null, 2));
}));
program
    .command('hook')
    .description('Manage runtime hooks and Claude Code hook subcommands')
    .addCommand(new Command('bootstrap')
    .description('UserPromptSubmit hook — auto-bootstrap session from user prompt (reads stdin JSON)')
    .action(async () => { await runHookBootstrap(); }))
    .addCommand(new Command('memory')
    .description('PostToolUse hook — write low-priority auto-memory after each tool call (reads stdin JSON)')
    .action(async () => { await runHookMemory(); }))
    .addCommand(new Command('mindkit')
    .description('PreToolUse hook — governance check before file mutations (reads stdin JSON, may exit 2 to block)')
    .action(async () => { await runHookMindkit(); }))
    .addCommand(new Command('ghost-pass')
    .description('PreToolUse hook — dry-run diff preview for MultiEdit >= 3 files (reads stdin JSON)')
    .action(async () => { await runHookGhostPass(); }))
    .addCommand(new Command('session-dna')
    .description('Stop hook — generate session DNA summary at session end (reads stdin JSON)')
    .action(async () => { await runHookSessionDna(); }))
    .addCommand(new Command('generate')
    .requiredOption('--name <name>', 'Hook name')
    .requiredOption('--description <description>', 'Hook description')
    .requiredOption('--trigger <trigger>', 'Hook trigger')
    .option('--risk-class <riskClass>', 'Risk class', 'orchestrate')
    .option('--scope <scope>', 'Hook scope', 'session')
    .action(async (options) => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    const hook = nexus.getRuntime().generateHook(options);
    console.log(JSON.stringify(hook, null, 2));
}))
    .addCommand(new Command('deploy')
    .argument('<hookId>', 'Hook id or name')
    .option('--scope <scope>', 'Deployment scope', 'session')
    .action(async (hookId, options) => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    const known = nexus.getRuntime().listHooks().find((hook) => hook.hookId === hookId || hook.name === hookId);
    console.log(JSON.stringify(known ? nexus.getRuntime().deployHook(known.hookId, options.scope) : { error: 'hook-not-found' }, null, 2));
}))
    .addCommand(new Command('revoke')
    .argument('<hookId>', 'Hook id or name')
    .action(async (hookId) => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    const known = nexus.getRuntime().listHooks().find((hook) => hook.hookId === hookId || hook.name === hookId);
    console.log(JSON.stringify(known ? nexus.getRuntime().revokeHook(known.hookId) : { error: 'hook-not-found' }, null, 2));
}));
program
    .command('automation')
    .description('Manage runtime automations')
    .addCommand(new Command('generate')
    .requiredOption('--name <name>', 'Automation name')
    .requiredOption('--description <description>', 'Automation description')
    .option('--trigger-mode <mode>', 'Trigger mode', 'event')
    .option('--event-trigger <trigger>', 'Event trigger')
    .option('--scope <scope>', 'Automation scope', 'session')
    .action(async (options) => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    const automation = nexus.getRuntime().generateAutomation(options);
    console.log(JSON.stringify(automation, null, 2));
}))
    .addCommand(new Command('deploy')
    .argument('<automationId>', 'Automation id or name')
    .option('--scope <scope>', 'Deployment scope', 'session')
    .action(async (automationId, options) => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    const known = nexus.getRuntime().listAutomations().find((automation) => automation.automationId === automationId || automation.name === automationId);
    console.log(JSON.stringify(known ? nexus.getRuntime().deployAutomation(known.automationId, options.scope) : { error: 'automation-not-found' }, null, 2));
}))
    .addCommand(new Command('revoke')
    .argument('<automationId>', 'Automation id or name')
    .action(async (automationId) => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    const known = nexus.getRuntime().listAutomations().find((automation) => automation.automationId === automationId || automation.name === automationId);
    console.log(JSON.stringify(known ? nexus.getRuntime().revokeAutomation(known.automationId) : { error: 'automation-not-found' }, null, 2));
}))
    .addCommand(new Command('run')
    .argument('<automationId>', 'Automation id or name')
    .option('--goal <goal>', 'Optional override goal')
    .action(async (automationId, options) => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    const execution = await nexus.getRuntime().runAutomation(automationId, options.goal);
    console.log(`📝 Result: ${execution.result}`);
    printExecutionSummary(execution);
}));
program
    .command('network')
    .description('Inspect local federation status')
    .action(async () => {
    if (!nexus) {
        await ensureNexusRunning();
    }
    console.log(JSON.stringify(nexus.getRuntime().getNetworkStatus(), null, 2));
});
program
    .command('cockpit')
    .description('Open the terminal cockpit with runtime, engine, and selection status')
    .option('--watch', 'Refresh continuously until interrupted')
    .action(async (options) => {
    const activeNexus = await ensureNexusRunning();
    const render = () => {
        if (options.watch) {
            process.stdout.write('\x1b[2J\x1b[H');
        }
        console.log(renderTerminalCockpit(activeNexus));
    };
    render();
    if (!options.watch) {
        return;
    }
    const timer = setInterval(render, 2000);
    timer.unref();
    const shutdown = async () => {
        clearInterval(timer);
        if (nexus) {
            await nexus.stop();
        }
        process.exit(0);
    };
    process.once('SIGINT', () => void shutdown());
    process.once('SIGTERM', () => void shutdown());
});
program
    .command('status')
    .description('Check Nexus Prime status')
    .action(async () => {
    const activeNexus = await withDashboardSuppressed(() => ensureNexusRunning({ startupProfile: 'inspect' }));
    try {
        const stats = activeNexus.getRuntimeStats();
        const envelope = activeNexus.getRuntimeHealthEnvelope();
        console.log(renderTerminalCockpit(activeNexus));
        console.log('');
        console.log('Runtime Totals');
        console.log(`  Agents: ${stats.agents}`);
        console.log(`  Adapters: ${stats.adapters}`);
        console.log(`  Grammar Rules: ${stats.grammarRules}`);
        console.log(`  Compatibility: ${envelope.compatibility.ready ? 'ready' : 'degraded'}`);
    }
    finally {
        await activeNexus.stop();
        nexus = null;
    }
});
program
    .command('evolution')
    .description('Evolution metrics')
    .addCommand(new Command('stats')
    .action(() => {
    if (!nexus) {
        console.log('⚠️  Nexus Prime not running');
        return;
    }
    const grammar = nexus.getGrammar();
    console.log('🧬 Evolution Stats:');
    console.log(`  Grammar Rules: ${grammar.length}`);
    grammar.forEach(r => {
        console.log(`    - ${r.pattern.join(' ')} (weight: ${r.weight.toFixed(2)})`);
    });
}));
program
    .command('setup')
    .description('Install MCP config plus client-native Nexus Prime instructions')
    .addCommand(buildRuntimeSetupCommand())
    .addCommand(new Command('codex')
    .description('Integrate with Codex by installing MCP config plus a managed AGENTS.md block')
    .option('--dry-run', 'Preview changes')
    .action((options) => {
    const definition = getSetupDefinition('codex');
    if (options.dryRun) {
        printSetupPreview(definition);
        return;
    }
    installSetup(definition);
    console.log(`✅ Nexus Prime installed for Codex`);
    console.log(`   MCP: ${definition.configPath}`);
    definition.instructionFiles.forEach((file) => console.log(`   AGENTS: ${file.path}`));
}))
    .addCommand(new Command('cursor')
    .description('Integrate with Cursor')
    .option('--dry-run', 'Preview changes')
    .action((options) => {
    const definition = getSetupDefinition('cursor');
    if (options.dryRun) {
        printSetupPreview(definition);
        return;
    }
    installSetup(definition);
    console.log(`✅ Nexus Prime installed for Cursor`);
    console.log(`   MCP: ${definition.configPath}`);
    definition.instructionFiles.forEach((file) => console.log(`   Rule: ${file.path}`));
}))
    .addCommand(new Command('claude-code')
    .alias('claude')
    .description('Integrate with Claude Code')
    .option('--dry-run', 'Preview changes')
    .option('--hooks', 'Install Claude Code hooks into ~/.claude/settings.json for auto-bootstrap, auto-memory, and governance (default)')
    .option('--no-hooks', 'Skip Claude Code hooks')
    .action((options) => {
    const definition = getSetupDefinition('claude-code');
    const shouldInstallHooks = options.hooks !== false;
    if (options.dryRun) {
        printSetupPreview(definition);
        if (shouldInstallHooks) {
            const settingsPath = join(homedir(), '.claude', 'settings.json');
            writeClaudeCodeHooks(settingsPath, true);
        }
        return;
    }
    installSetup(definition);
    console.log(`✅ Nexus Prime installed for Claude Code`);
    console.log(`   MCP: ${definition.configPath}`);
    definition.instructionFiles.forEach((file) => console.log(`   Instruction: ${file.path}`));
    if (shouldInstallHooks) {
        const settingsPath = join(homedir(), '.claude', 'settings.json');
        writeClaudeCodeHooks(settingsPath, false);
        console.log(`✅ Claude Code hooks installed (auto-bootstrap, auto-memory, governance)`);
    }
}))
    .addCommand(new Command('claude-desktop')
    .description('Integrate with Claude Desktop')
    .option('--dry-run', 'Preview changes')
    .action((options) => {
    const definition = getSetupDefinition('claude-desktop');
    if (options.dryRun) {
        printSetupPreview(definition);
        return;
    }
    installSetup(definition);
    console.log(`✅ Nexus Prime installed for Claude Desktop`);
    console.log(`   MCP: ${definition.configPath}`);
    definition.instructionFiles.forEach((file) => console.log(`   Instruction: ${file.path}`));
}))
    .addCommand(new Command('opencode')
    .description('Integrate with Opencode')
    .option('--dry-run', 'Preview changes')
    .action((options) => {
    const definition = getSetupDefinition('opencode');
    if (options.dryRun) {
        printSetupPreview(definition);
        return;
    }
    installSetup(definition);
    console.log(`✅ Nexus Prime installed for Opencode`);
    console.log(`   MCP: ${definition.configPath}`);
    definition.instructionFiles.forEach((file) => console.log(`   Instruction: ${file.path}`));
}))
    .addCommand(new Command('windsurf')
    .description('Integrate with Windsurf')
    .option('--dry-run', 'Preview changes')
    .action((options) => {
    const definition = getSetupDefinition('windsurf');
    if (options.dryRun) {
        printSetupPreview(definition);
        return;
    }
    installSetup(definition);
    console.log(`✅ Nexus Prime installed for Windsurf`);
    console.log(`   MCP: ${definition.configPath}`);
    definition.instructionFiles.forEach((file) => console.log(`   Rule: ${file.path}`));
}))
    .addCommand(new Command('antigravity')
    .description('Integrate with Antigravity')
    .option('--dry-run', 'Preview changes')
    .action((options) => {
    const definition = getSetupDefinition('antigravity');
    if (options.dryRun) {
        printSetupPreview(definition);
        return;
    }
    installSetup(definition);
    console.log(`✅ Nexus Prime installed for Antigravity`);
    console.log(`   MCP: ${definition.configPath}`);
    definition.instructionFiles.forEach((file) => console.log(`   Skill: ${file.path}`));
}))
    .addCommand(new Command('openclaw')
    .description('Integrate with OpenClaw')
    .option('--dry-run', 'Preview changes')
    .action((options) => {
    const definition = getSetupDefinition('openclaw');
    if (options.dryRun) {
        printSetupPreview(definition);
        return;
    }
    installSetup(definition);
    console.log(`✅ Nexus Prime installed for OpenClaw`);
    console.log(`   MCP: ${definition.configPath}`);
    definition.instructionFiles.forEach((file) => console.log(`   Instruction: ${file.path}`));
}))
    .addCommand(new Command('hermes')
    .description('Integrate with Hermes')
    .option('--dry-run', 'Preview changes')
    .action((options) => {
    const definition = getSetupDefinition('hermes');
    if (options.dryRun) {
        printSetupPreview(definition);
        return;
    }
    installSetup(definition);
    console.log(`✅ Nexus Prime installed for Hermes`);
    console.log(`   MCP: ${definition.configPath}`);
    definition.instructionFiles.forEach((file) => console.log(`   Skill: ${file.path}`));
}))
    .addCommand(new Command('nanoclaw')
    .description('Integrate with NanoClaw')
    .option('--dry-run', 'Preview changes')
    .action((options) => {
    const definition = getSetupDefinition('nanoclaw');
    if (options.dryRun) {
        printSetupPreview(definition);
        return;
    }
    installSetup(definition);
    console.log(`✅ Nexus Prime installed for NanoClaw`);
    console.log(`   MCP: ${definition.configPath}`);
    definition.instructionFiles.forEach((file) => console.log(`   Skill: ${file.path}`));
}))
    .addCommand(new Command('picoclaw')
    .description('Integrate with PicoClaw')
    .option('--dry-run', 'Preview changes')
    .action((options) => {
    const definition = getSetupDefinition('picoclaw');
    if (options.dryRun) {
        printSetupPreview(definition);
        return;
    }
    installSetup(definition);
    console.log(`✅ Nexus Prime installed for PicoClaw`);
    console.log(`   MCP: ${definition.configPath}`);
    definition.instructionFiles.forEach((file) => console.log(`   Skill: ${file.path}`));
}))
    .addCommand(new Command('all')
    .description('Install Nexus Prime for all supported clients in the current workspace')
    .option('--dry-run', 'Preview changes')
    .action((options) => {
    const definitions = SETUP_CLIENTS.map((clientId) => getSetupDefinition(clientId));
    if (options.dryRun) {
        definitions.forEach((definition) => printSetupPreview(definition));
        writeClaudeCodeHooks(join(homedir(), '.claude', 'settings.json'), true);
        return;
    }
    definitions.forEach((definition) => installSetup(definition));
    writeClaudeCodeHooks(join(homedir(), '.claude', 'settings.json'), false);
    console.log('✅ Nexus Prime installed for all supported clients');
    definitions.forEach((definition) => {
        console.log(`   ${definition.label}`);
        if (definition.configPath)
            console.log(`     MCP: ${definition.configPath}`);
        definition.instructionFiles.forEach((file) => console.log(`     Instruction: ${file.path}`));
    });
}))
    .addCommand(new Command('auto')
    .description('Auto-detect installed IDEs, configure MCP, start daemon, and open dashboard')
    .option('--dry-run', 'Preview changes without writing files')
    .option('--no-browser', 'Skip auto-opening the browser')
    .action(async (options) => {
    const newUser = isNewUser();
    const marker = readSetupMarker();
    // Animated boot sequence
    if (process.stdout.isTTY && !process.env.CI) {
        await runInstallBootSequence(packageJson.version);
    }
    // Returning user: show summary and skip lengthy prompts
    if (!newUser && marker) {
        printReturningUserBanner(marker);
    }
    // New user: interactive license prompt
    let licenseKey = null;
    if (newUser && process.stdout.isTTY && !process.env.CI && !options.dryRun) {
        try {
            const mgr = getSharedLicenseManager();
            const lic = mgr.getStatus();
            licenseKey = await promptLicenseKey(lic.tier);
        }
        catch { /* best-effort */ }
    }
    await cliSetup({
        dryRun: options.dryRun ?? false,
        verbose: true,
        isNewUser: newUser,
        licenseKey: licenseKey ?? undefined,
        openDashboard: options.browser !== false,
    });
}))
    .addCommand(new Command('status')
    .description('Check integration status')
    .action(() => {
    console.log('📋 Integration Status:');
    SETUP_CLIENTS.forEach((clientId) => {
        const definition = getSetupDefinition(clientId);
        const status = statusForDefinition(definition);
        const icon = status.state === 'installed' ? '✅' : status.state === 'drifted' ? '🟡' : '❌';
        const hookSummary = status.memoryHookReady ? ' · memory hooks ready' : '';
        console.log(`  - ${definition.label}: ${icon} ${status.summary}${hookSummary}`);
    });
}))
    .addCommand(new Command('diagnose')
    .description('Run a full diagnostic check across all clients without writing anything')
    .action(() => {
    console.log('🔍 Nexus Prime Setup Diagnostics\n');
    const manifest = collectBootstrapManifest({ packageRoot: PACKAGE_ROOT, workspaceRoot: getWorkspaceRoot() });
    const pad = (s, n) => s.padEnd(n);
    console.log(`${pad('Client', 16)} ${pad('State', 12)} ${pad('Home', 8)} ${pad('Workspace', 12)} ${pad('MemHook', 9)} ${pad('Config Path', 10)}`);
    console.log('─'.repeat(80));
    for (const client of manifest.clients) {
        const stateIcon = client.state === 'installed' ? '✅' : client.state === 'drifted' ? '🟡' : '❌';
        const homeIcon = client.homeReady ? '✅' : '❌';
        const wsIcon = client.workspaceReady ? '✅' : '❌';
        const hookIcon = client.memoryHookReady ? '✅' : '❌';
        console.log(`${pad(client.label, 16)} ${stateIcon} ${pad(client.state, 9)} ${homeIcon} ${pad('', 5)} ${wsIcon} ${pad('', 9)} ${hookIcon} ${pad('', 6)} ${client.configPath || '(none)'}`);
    }
    console.log('\n📂 Path Validation:');
    for (const client of manifest.clients) {
        if (client.configPath) {
            const check = validateTargetPath(client.configPath);
            const icon = check.valid ? '✅' : '❌';
            console.log(`  ${icon} ${client.label} config: ${client.configPath}${check.valid ? '' : ` — ${check.reason}`}`);
        }
        for (const instrPath of client.instructionFiles) {
            const check = validateTargetPath(instrPath);
            const icon = check.valid ? '✅' : '❌';
            console.log(`  ${icon} ${client.label} instruction: ${instrPath}${check.valid ? '' : ` — ${check.reason}`}`);
        }
    }
    console.log(`\n📊 Summary: ${manifest.clients.filter(c => c.state === 'installed').length}/${manifest.clients.length} clients fully installed`);
    console.log(`   Workspace: ${manifest.workspaceRoot}`);
    console.log(`   Generated: ${new Date(manifest.generatedAt).toISOString()}`);
}));
program
    .command('cleanup')
    .description('Remove temp files, stale sessions, and configs for non-detected clients')
    .option('--dry-run', 'Preview what would be removed')
    .action((options) => {
    const dryRun = !!options.dryRun;
    const cwd = getWorkspaceRoot();
    let totalCleaned = 0;
    console.log(dryRun ? '🔍 Cleanup preview (dry run):\n' : '🧹 Running cleanup...\n');
    // 1. Remove tmp-control-plane-* directories
    try {
        const entries = fs.readdirSync(cwd);
        const tmpDirs = entries.filter(e => e.startsWith('tmp-control-plane-'));
        for (const dir of tmpDirs) {
            const fullPath = path.join(cwd, dir);
            try {
                if (fs.statSync(fullPath).isDirectory()) {
                    console.log(`  ${dryRun ? 'Would remove' : 'Removing'}: ${dir}/`);
                    if (!dryRun)
                        fs.rmSync(fullPath, { recursive: true, force: true });
                    totalCleaned++;
                }
            }
            catch { /* ignore */ }
        }
    }
    catch { /* ignore */ }
    // 2. Clean stale sessions
    try {
        const cleaned = SessionDNAManager.cleanStale();
        if (cleaned > 0) {
            console.log(`  ${dryRun ? 'Would clean' : 'Cleaned'}: ${cleaned} stale session(s)`);
            totalCleaned += cleaned;
        }
    }
    catch { /* ignore */ }
    // 3. Remove empty .agent/ subdirectories
    const agentDir = path.join(cwd, '.agent');
    if (fs.existsSync(agentDir)) {
        try {
            const subdirs = fs.readdirSync(agentDir);
            for (const sub of subdirs) {
                const subPath = path.join(agentDir, sub);
                try {
                    if (fs.statSync(subPath).isDirectory()) {
                        const contents = fs.readdirSync(subPath);
                        if (contents.length === 0) {
                            console.log(`  ${dryRun ? 'Would remove' : 'Removing'}: .agent/${sub}/ (empty)`);
                            if (!dryRun)
                                fs.rmdirSync(subPath);
                            totalCleaned++;
                        }
                    }
                }
                catch { /* ignore */ }
            }
        }
        catch { /* ignore */ }
    }
    // 4. Compact memory vault
    try {
        const vaultDir = path.join(resolveNexusStateDir(), 'memory-vault', 'items');
        if (fs.existsSync(vaultDir)) {
            const items = fs.readdirSync(vaultDir).filter(f => f.endsWith('.json'));
            if (items.length > 10) {
                console.log(`  ${dryRun ? 'Would compact' : 'Compacting'}: ${items.length} vault item files`);
                if (!dryRun) {
                    const consolidated = [];
                    for (const item of items) {
                        try {
                            consolidated.push(JSON.parse(fs.readFileSync(path.join(vaultDir, item), 'utf8')));
                            fs.unlinkSync(path.join(vaultDir, item));
                        }
                        catch { /* skip corrupted */ }
                    }
                    const snapshotPath = path.join(resolveNexusStateDir(), 'memory-vault', `vault-snapshot-${Date.now()}.json`);
                    fs.writeFileSync(snapshotPath, JSON.stringify(consolidated, null, 2));
                    console.log(`  Consolidated to: ${snapshotPath}`);
                }
                totalCleaned++;
            }
        }
    }
    catch { /* ignore */ }
    console.log(`\n✅ ${dryRun ? 'Would clean' : 'Cleaned'} ${totalCleaned} item(s)`);
});
program
    .command('doctor')
    .description('Diagnose system health and report issues with recommendations')
    .action(async () => {
    const activeNexus = await withDashboardSuppressed(() => ensureNexusRunning());
    try {
        const diagnosis = activeNexus.diagnoseRuntime();
        const manifest = diagnosis.bootstrapManifest ?? collectBootstrapManifest({ packageRoot: PACKAGE_ROOT, workspaceRoot: getWorkspaceRoot() });
        const installed = manifest.clients.filter(c => c.state === 'installed');
        const drifted = manifest.clients.filter(c => c.state === 'drifted');
        console.log('🏥 Nexus Prime Health Check\n');
        console.log(`Status: ${diagnosis.ok ? 'nominal' : diagnosis.envelope.status}`);
        console.log(`Workspace: ${diagnosis.envelope.workspace.workspaceRoot}`);
        console.log(`Repo Root: ${diagnosis.envelope.workspace.repoRoot}`);
        console.log(`State Root: ${diagnosis.envelope.workspace.stateRoot}`);
        console.log(`Synapse: ${diagnosis.envelope.engines.synapse.mode} · requested=${diagnosis.envelope.engines.synapse.requestedStorageRoot || 'n/a'} · active=${diagnosis.envelope.engines.synapse.storageRoot || 'n/a'}`);
        console.log(`Architects: ${diagnosis.envelope.engines.architects.mode} · requested=${diagnosis.envelope.engines.architects.requestedStorageRoot || 'n/a'} · active=${diagnosis.envelope.engines.architects.storageRoot || 'n/a'}`);
        console.log(`Clients: ${installed.length} installed, ${drifted.length} drifted`);
        if (diagnosis.envelope.engines.synapse.quarantinePath) {
            console.log(`Synapse Quarantine: ${diagnosis.envelope.engines.synapse.quarantinePath}`);
        }
        if (diagnosis.envelope.engines.architects.quarantinePath) {
            console.log(`Architects Quarantine: ${diagnosis.envelope.engines.architects.quarantinePath}`);
        }
        if (diagnosis.issues.length > 0) {
            console.log('\n⚠️  Issues:');
            diagnosis.issues.forEach((issue) => console.log(`  • ${issue}`));
        }
        else {
            console.log('\n🎉 No issues detected!');
        }
        if (drifted.length > 0) {
            console.log('\nSuggested Repair:');
            console.log(`  nexus-prime autofix`);
            console.log(`  or nexus-prime setup <client> for: ${drifted.map((client) => client.label).join(', ')}`);
        }
    }
    finally {
        await activeNexus.stop();
        nexus = null;
    }
});
program
    .command('autofix')
    .description('Apply safe runtime self-healing for bootstrap drift and noisy memory state')
    .action(async () => {
    const activeNexus = await withDashboardSuppressed(() => ensureNexusRunning());
    try {
        const result = activeNexus.autofixRuntime();
        console.log('🛠️  Autofix complete\n');
        console.log(`Clients tracked: ${result.bootstrapManifest.clients.length}`);
        console.log(`Memory expired: ${result.memoryMaintenance?.expired || 0}`);
        console.log(`Memory quarantined: ${result.memoryMaintenance?.quarantined || 0}`);
        console.log(`Runtime status: ${result.diagnosis.envelope.status}`);
        if (result.diagnosis.issues.length) {
            console.log('\nRemaining Issues:');
            result.diagnosis.issues.forEach((issue) => console.log(`  • ${issue}`));
        }
    }
    finally {
        await activeNexus.stop();
        nexus = null;
    }
});
program
    .command('proof')
    .description('Inspect Nexus Prime provenance, signatures, and opt-in proof telemetry')
    .addCommand(new Command('verify')
    .description('Verify Nexus Prime PR presence, generated commit trailers, artifact signatures, and telemetry redaction')
    .option('--repo-root <path>', 'Repo root to verify (default: cwd)')
    .option('--pr-body <path>', 'Generated pull request body markdown to verify')
    .option('--commit-message <path>', 'Generated commit message file to verify')
    .option('--artifact <path...>', 'Generated artifact/document files to verify')
    .option('--strict', 'Treat warnings as failures')
    .option('--json', 'Output raw JSON')
    .action(async (options) => {
    const summary = await verifyNexusProof({
        repoRoot: options.repoRoot ? path.resolve(options.repoRoot) : getWorkspaceRoot(),
        prBodyPath: options.prBody ? path.resolve(options.prBody) : undefined,
        commitMessagePath: options.commitMessage ? path.resolve(options.commitMessage) : undefined,
        artifactPaths: (options.artifact ?? []).map((artifactPath) => path.resolve(artifactPath)),
    });
    if (options.json) {
        console.log(JSON.stringify(summary, null, 2));
    }
    else {
        console.log(formatNexusProofReport(summary));
    }
    if (summary.failed > 0 || (options.strict && summary.warnings > 0)) {
        process.exitCode = 1;
    }
}));
program
    .command('memory-hygiene')
    .description('Inspect or apply memory hygiene to reduce duplicate and low-signal memories')
    .option('--mode <mode>', 'report or apply', 'report')
    .option('--apply', 'Apply maintenance before reporting')
    .option('--limit <limit>', 'Sample size for audit', '80')
    .option('--batch-size <batchSize>', 'Maximum hygiene rows to touch in one pass', '250')
    .option('--states <states>', 'Comma-separated states to include (active,quarantined,scrap,expired)')
    .action(async (options) => {
    const activeNexus = await withDashboardSuppressed(() => ensureNexusRunning());
    try {
        const limit = Math.max(1, Number(options.limit || '80'));
        const batchSize = Math.max(1, Math.min(Number(options.batchSize || '250'), 250));
        const mode = options.apply ? 'apply' : (options.mode === 'apply' ? 'apply' : 'report');
        const states = (options.states || '')
            .split(',')
            .map((value) => value.trim())
            .filter(Boolean);
        const result = activeNexus.runMemoryHygiene({
            mode,
            batchSize,
            states: states.length > 0 ? states : undefined,
            auditLimit: limit,
        });
        console.log('🧠 Memory Hygiene\n');
        console.log(`Mode: ${result.mode}`);
        console.log(`Schema: ${result.schemaVersion}`);
        console.log(`Scanned: ${result.audit?.scanned || 0}`);
        console.log(`Quarantine backlog: ${result.health?.quarantineBacklog || 0}`);
        console.log(`Purge eligible: ${result.health?.purgeEligible || 0}`);
        console.log(`Promoted: ${result.health?.promoted || 0}`);
        console.log(`Shared: ${result.health?.shared || 0}`);
        if (result.maintenance) {
            console.log(`Active trimmed: ${result.maintenance.activeTrimmed || 0}`);
            console.log(`Quarantined expired: ${result.maintenance.quarantinedExpired || 0}`);
            console.log(`Scrap prepared: ${result.maintenance.scrapExpired || 0}`);
            console.log(`Purged: ${result.maintenance.purged || 0}`);
        }
    }
    finally {
        await activeNexus.stop();
        nexus = null;
    }
});
program
    .command('license')
    .description('Manage your Nexus Prime license')
    .addCommand(new Command('activate')
    .description('Activate a license key')
    .argument('<key>', 'License key from the Nexus account page or license team')
    .action((key) => {
    const mgr = getSharedLicenseManager();
    const status = mgr.activate(key);
    if (status.valid) {
        console.log(`\u2713 License activated: ${status.tier.toUpperCase()} plan`);
        if (status.expiresAt) {
            console.log(`  Expires: ${new Date(status.expiresAt).toISOString().slice(0, 10)}`);
        }
        console.log(formatPCUStatus(snapshotPCU()));
    }
    else {
        console.error(`\u2717 License invalid: ${status.degradedReason ?? 'unknown'}`);
        console.error('  Request a valid key at https://nexus-prime.cfd/account');
        console.error('  Or email adarsh@nexus-prime.cfd — licenses are shared within 24 hours.');
        process.exit(1);
    }
}))
    .addCommand(new Command('status')
    .description('Show current license, plan limits, and usage')
    .option('--json', 'Output raw JSON')
    .action((opts) => {
    const pcu = snapshotPCU();
    if (opts.json) {
        console.log(JSON.stringify(pcu, null, 2));
    }
    else {
        console.log(formatPCUStatus(pcu));
        const authInfo = readAuthInfo();
        if (authInfo) {
            console.log(`  Logged in as: ${authInfo.email}`);
        }
        else {
            console.log('  Not logged in. Run: nexus-prime license login');
        }
    }
}))
    .addCommand(new Command('deactivate')
    .description('Remove license key and revert to Free plan')
    .action(() => {
    getSharedLicenseManager().deactivate();
    console.log('\u2713 License removed. Reverted to Free plan.');
    console.log('  Request a new key at https://nexus-prime.cfd/account');
    console.log('  Or email adarsh@nexus-prime.cfd — licenses are shared within 24 hours.');
}))
    .addCommand(new Command('login')
    .description('Login to nexus-prime.cfd for license sync')
    .argument('[email]', 'Email address')
    .argument('[password]', 'Password')
    .action(async (email, password) => {
    if (!email || !password) {
        // Interactive mode — read from stdin
        const readline = await import('readline');
        const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
        const ask = (q) => new Promise(resolve => rl.question(q, resolve));
        if (!email)
            email = await ask('Email: ');
        if (!password)
            password = await ask('Password: ');
        rl.close();
    }
    try {
        const result = await loginFromCLI(email, password);
        console.log(`\u2713 Logged in as ${result.email}`);
        // Auto-sync license after login
        try {
            const status = await syncLicense();
            console.log(`\u2713 License synced: ${status.tier.toUpperCase()} plan`);
            console.log(formatPCUStatus(snapshotPCU()));
        }
        catch {
            console.log('  License sync skipped (no license found yet).');
            console.log('  Request a license at https://nexus-prime.cfd/account');
            console.log('  Or email adarsh@nexus-prime.cfd — licenses are shared within 24 hours.');
        }
    }
    catch (err) {
        console.error(`\u2717 Login failed: ${err instanceof Error ? err.message : String(err)}`);
        process.exit(1);
    }
}))
    .addCommand(new Command('logout')
    .description('Clear stored login credentials')
    .action(() => {
    logout();
    console.log('\u2713 Logged out. Auth tokens cleared.');
}))
    .addCommand(new Command('sync')
    .description('Fetch latest license from nexus-prime.cfd')
    .action(async () => {
    if (!isLoggedIn()) {
        console.error('\u2717 Not logged in. Run: nexus-prime license login');
        process.exit(1);
    }
    try {
        const status = await syncLicense();
        console.log(`\u2713 License updated: ${status.tier.toUpperCase()} plan`);
        console.log(formatPCUStatus(snapshotPCU()));
    }
    catch (err) {
        console.error(`\u2717 Sync failed: ${err instanceof Error ? err.message : String(err)}`);
        process.exit(1);
    }
}))
    .addCommand(new Command('upgrade')
    .description('Request a plan upgrade')
    .argument('[plan]', 'Target plan: pro, team, or enterprise')
    .action(async (plan) => {
    if (!plan || !['pro', 'team', 'enterprise'].includes(plan)) {
        console.log('Available plans:');
        console.log('  pro        — 10 projects, 10K memories, 5 operatives, Darwin solo');
        console.log('  team       — Unlimited projects, 100K memories, unlimited operatives, Synapse');
        console.log('  enterprise — Everything unlimited, Architects, fleet Darwin');
        console.log('');
        console.log('Usage: nexus-prime license upgrade <plan>');
        console.log('  Or visit: https://nexus-prime.cfd/account');
        return;
    }
    if (!isLoggedIn()) {
        console.log('Opening upgrade page in browser...');
        const { exec } = await import('child_process');
        exec(`open https://nexus-prime.cfd/account`);
        return;
    }
    try {
        const result = await requestUpgrade(plan);
        console.log(`\u2713 Upgrade request submitted (${result.status})`);
        console.log('  The Nexus Prime team will review it and share licenses within 24 hours.');
        console.log('  Once approved, run: nexus-prime license sync');
    }
    catch (err) {
        console.error(`\u2717 Request failed: ${err instanceof Error ? err.message : String(err)}`);
        console.log('  Visit https://nexus-prime.cfd/account to request an upgrade.');
        console.log('  Or email adarsh@nexus-prime.cfd with your account email and target plan.');
        process.exit(1);
    }
}));
program
    .command('uninstall')
    .description('Reverse every change Nexus Prime made: stop processes, remove registrations, optionally purge state')
    .option('--all', 'Stop all Nexus daemons and unregister all known client configs (default)')
    .option('--dry-run', 'Preview all removals without touching anything')
    .option('--purge', 'Also delete persistent state (memory, workforce DBs, logs, caches, worktrees)')
    .option('--purge-all', 'Alias for --purge')
    .option('--yes', 'Skip confirmation when using --purge')
    .option('--workspace-root <path>', 'Workspace root to scan for IDE registrations (default: cwd)')
    .action(async (opts) => {
    const report = await runUninstall({
        dryRun: opts.dryRun ?? false,
        all: opts.all ?? true,
        purge: opts.purge ?? opts.purgeAll ?? false,
        yes: opts.yes ?? false,
        workspaceRoot: opts.workspaceRoot,
    });
    if (!report.ok)
        process.exit(1);
});
program
    .command('cleanup')
    .description('Bound transient storage growth (worktrees, runs, caches)')
    .option('--dry-run', 'Preview what would be removed (default when --fix is absent)')
    .option('--fix', 'Actually apply the sweep. Without --fix, runs in dry-run mode.')
    .option('--repo-root <path>', 'Git repo root (default: cwd)')
    .action(async (opts) => {
    await runCleanup({
        dryRun: opts.dryRun ?? !opts.fix,
        fix: opts.fix ?? false,
        repoRoot: opts.repoRoot,
    });
});
program
    .command('doctor')
    .description('Diagnose Nexus state and storage')
    .addCommand(new Command('storage')
    .description('Report disk usage by scope and flag budget violations')
    .action(() => {
    const report = runDoctorStorage();
    if (report.suggestCleanup)
        process.exit(2);
}));
program
    .command('reset')
    .description('Reset Nexus Prime daemon state (--hard wipes all data, --soft stops daemon only)')
    .option('--hard', 'Full wipe: kill daemon, delete all db/run state for the workspace')
    .option('--soft', 'Soft reset: kill daemon and remove lockfiles, preserve memory/db data')
    .option('--workspace <key>', 'Scope reset to a specific workspace state key')
    .option('--wipe-memories', 'Also delete memory.db (only meaningful with --hard)')
    .option('--unregister', 'Reverse IDE MCP config written by "nexus-prime mcp"')
    .option('--yes', 'Skip confirmation prompt (CI-friendly)')
    .action(async (opts) => {
    const summary = await runReset({
        hard: opts.hard ?? false,
        soft: opts.soft ?? false,
        workspace: opts.workspace,
        wipeMemories: opts.wipeMemories ?? false,
        unregister: opts.unregister ?? false,
        yes: opts.yes ?? false,
    });
    if (!summary.ok)
        process.exit(1);
});
program
    .command('orchestrate')
    .alias('do')
    .description('Send a goal to the control plane and stream live progress in the terminal')
    .argument('<goal>', 'Natural language goal for the agent')
    .option('--port <port>', 'Dashboard port (default: 3377 or $NEXUS_DASHBOARD_PORT)')
    .option('--timeout <ms>', 'Max wait time in milliseconds (default: 120000)')
    .action(async (goal, opts) => {
    const { runOrchestrateStream } = await import('./cli/orchestrate-stream.js');
    await runOrchestrateStream(goal, {
        port: opts.port ? Number(opts.port) : undefined,
        timeoutMs: opts.timeout ? Number(opts.timeout) : undefined,
    });
});
program
    .command('fix-claude-hooks')
    .description('Strip stale Nexus hook entries from ~/.claude/settings.json (use after downgrading from a newer version)')
    .option('--dry-run', 'Show what would change without writing')
    .option('--workspace', 'Also clean ./.claude/settings.json in the current workspace')
    .action(async (opts) => {
    const fs = await import('fs');
    const path = await import('path');
    const os = await import('os');
    const { NEXUS_HOOK_COMMAND_MARKER } = await import('./install/claude-code-hooks.js');
    const targets = [path.join(os.homedir(), '.claude', 'settings.json')];
    if (opts.workspace)
        targets.push(path.join(process.cwd(), '.claude', 'settings.json'));
    let totalRemoved = 0;
    for (const target of targets) {
        if (!fs.existsSync(target)) {
            console.log(`  skip: ${target} (not found)`);
            continue;
        }
        let parsed;
        try {
            parsed = JSON.parse(fs.readFileSync(target, 'utf8'));
        }
        catch (err) {
            console.error(`  error: ${target} (invalid JSON: ${err instanceof Error ? err.message : String(err)})`);
            continue;
        }
        const hooks = parsed?.hooks;
        if (!hooks || typeof hooks !== 'object') {
            console.log(`  ok: ${target} (no hooks block)`);
            continue;
        }
        let removedHere = 0;
        for (const event of Object.keys(hooks)) {
            if (!Array.isArray(hooks[event]))
                continue;
            const before = hooks[event];
            const after = before.filter((entry) => {
                const entryHooks = entry?.hooks;
                if (!Array.isArray(entryHooks))
                    return true;
                const hasNexus = entryHooks.some((h) => typeof h?.command === 'string' && h.command.trimStart().startsWith(NEXUS_HOOK_COMMAND_MARKER));
                if (hasNexus)
                    removedHere += 1;
                return !hasNexus;
            });
            if (after.length === 0) {
                delete hooks[event];
            }
            else {
                hooks[event] = after;
            }
        }
        if (Object.keys(hooks).length === 0)
            delete parsed.hooks;
        totalRemoved += removedHere;
        if (removedHere === 0) {
            console.log(`  ok: ${target} (no Nexus entries)`);
            continue;
        }
        if (opts.dryRun) {
            console.log(`  dry-run: ${target} would remove ${removedHere} Nexus hook entry/entries`);
            continue;
        }
        fs.writeFileSync(target, JSON.stringify(parsed, null, 2) + '\n', 'utf8');
        console.log(`  fixed: ${target} (removed ${removedHere} entry/entries)`);
    }
    console.log(opts.dryRun ? `\nDry-run total: ${totalRemoved} entry/entries.` : `\nDone. Removed ${totalRemoved} stale Nexus hook entry/entries.`);
});
program
    .command('watch')
    .description('Tail live SSE events from the running daemon in a colored terminal feed')
    .option('--port <port>', 'Dashboard port (default: 3377 or $NEXUS_DASHBOARD_PORT)')
    .option('--all', 'Show all event types (default: mcp, tokens, planner, license, install)')
    .option('--filter <regex>', 'Custom event type filter (regex string)')
    .action(async (opts) => {
    const { runWatch } = await import('./cli/watch.js');
    await runWatch({
        port: opts.port ? Number(opts.port) : undefined,
        all: opts.all,
        filter: opts.filter,
    });
});
// Default: running `nexus-prime` with no subcommand runs `setup auto`
if (process.argv.length === 2) {
    process.argv.push('setup', 'auto');
}
// Graceful fallback for unknown `nexus-prime hook <subcommand>` invocations.
// When users downgrade from a version that wrote hook entries to
// ~/.claude/settings.json, the older binary may not have the referenced
// subcommand. Exiting non-zero would fail every Claude Code session start.
// Drain piped stdin (Claude pipes JSON into hooks) and exit 0 silently.
const KNOWN_HOOK_SUBCOMMANDS = new Set([
    'bootstrap', 'memory', 'mindkit', 'ghost-pass', 'session-dna',
    'generate', 'deploy', 'undeploy', 'list', 'help', '--help', '-h',
]);
if (process.argv[2] === 'hook' && process.argv[3] && !KNOWN_HOOK_SUBCOMMANDS.has(process.argv[3])) {
    if (!process.stdin.isTTY) {
        process.stdin.resume();
        process.stdin.on('data', () => { });
        process.stdin.on('end', () => process.exit(0));
        setTimeout(() => process.exit(0), 200).unref();
    }
    else {
        process.exit(0);
    }
}
else {
    program.parse();
}
