#!/usr/bin/env node
/**
 * ShieldCortex - Brain-like Memory System for Claude Code
 *
 * This server provides persistent, intelligent memory for Claude Code,
 * solving the context compaction and session persistence problems.
 *
 * Usage:
 *   npx shieldcortex                         # Start MCP server (default)
 *   npx shieldcortex --mode mcp              # Start MCP server
 *   npx shieldcortex --mode api              # Start visualization API server
 *   npx shieldcortex --mode both             # Start both servers
 *   npx shieldcortex --dashboard             # Start API + Dashboard (admin panel)
 *   npx shieldcortex --db /path/to.db        # Custom database path
 *   npx shieldcortex status                   # Show database and system status
 *   npx shieldcortex setup                    # Configure Claude for proactive memory use
 *   npx shieldcortex install                  # Alias for setup
 *   npx shieldcortex hook pre-compact         # Run pre-compact hook (for settings.json)
 *   npx shieldcortex hook session-start       # Run session-start hook (for settings.json)
 *   npx shieldcortex hook session-end         # Run session-end hook (for settings.json)
 *   npx shieldcortex service install         # Auto-start dashboard on login
 *   npx shieldcortex service uninstall       # Remove auto-start
 *   npx shieldcortex service status          # Check service status
 *   npx shieldcortex openclaw install        # Install OpenClaw hook
 *   npx shieldcortex openclaw uninstall      # Remove OpenClaw hook
 *   npx shieldcortex openclaw status         # Check OpenClaw hook status
 *   npx shieldcortex migrate                  # Migrate from Claude Cortex
 *   npx shieldcortex setup uninstall         # Remove hooks + CLAUDE.md block (requires confirmation)
 *   npx shieldcortex uninstall               # Full uninstall (requires confirmation)
 *   npx shieldcortex uninstall --confirm     # Full uninstall (non-interactive)
 *   npx shieldcortex uninstall --keep-logs   # Full uninstall but keep log files
 */
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { spawn } from 'child_process';
import { fileURLToPath } from 'url';
import path from 'path';
import { createServer } from './server.js';
import { startVisualizationServer } from './api/visualization-server.js';
import { handleServiceCommand } from './service/install.js';
import { setupClaudeMd } from './setup/claude-md.js';
import { handleHookCommand } from './setup/hooks.js';
import { handleOpenClawCommand } from './setup/openclaw.js';
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const pkg = require('../package.json');
// Get the directory of this file for relative paths
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Parse command line arguments
function parseArgs() {
    const args = process.argv.slice(2);
    const result = { mode: 'mcp' };
    for (let i = 0; i < args.length; i++) {
        if (args[i] === '--db' && args[i + 1]) {
            result.dbPath = args[i + 1];
            i++;
        }
        else if (args[i] === '--dashboard') {
            result.mode = 'dashboard';
        }
        else if (args[i] === '--mode' && args[i + 1]) {
            const mode = args[i + 1].toLowerCase();
            if (mode === 'mcp' || mode === 'api' || mode === 'both' || mode === 'dashboard') {
                result.mode = mode;
            }
            i++;
        }
    }
    return result;
}
/**
 * Start MCP server for Claude Code integration
 */
async function startMcpServer(dbPath) {
    // Create the MCP server
    const server = createServer(dbPath);
    // Connect via stdio transport
    const transport = new StdioServerTransport();
    await server.connect(transport);
    // Handle graceful shutdown
    process.on('SIGINT', async () => {
        await server.close();
        process.exit(0);
    });
    process.on('SIGTERM', async () => {
        await server.close();
        process.exit(0);
    });
}
/**
 * Start the Next.js dashboard as a child process
 */
function startDashboard() {
    // Dashboard paths - check standalone first (npm package), then fall back to dev
    // Note: Next.js standalone output puts files in a subdirectory named after the project
    const standaloneServer = path.resolve(__dirname, '..', 'dashboard', '.next', 'standalone', 'dashboard', 'server.js');
    const dashboardDir = path.resolve(__dirname, '..', 'dashboard');
    // Check if standalone server exists (bundled in npm package)
    const fs = require('fs');
    const useStandalone = fs.existsSync(standaloneServer);
    console.log(`
╔══════════════════════════════════════════════════════════════╗
║             🧠 ShieldCortex Dashboard                        ║
╠══════════════════════════════════════════════════════════════╣
║  Starting Next.js dashboard...                               ║
║  Dashboard: http://localhost:3030                            ║
║  API:       http://localhost:3001                            ║
╚══════════════════════════════════════════════════════════════╝
  `);
    let dashboard;
    if (useStandalone) {
        // Use standalone server (npm package distribution)
        const standaloneCwd = path.resolve(__dirname, '..', 'dashboard', '.next', 'standalone', 'dashboard');
        dashboard = spawn(process.execPath, ['server.js'], {
            cwd: standaloneCwd,
            stdio: ['ignore', 'pipe', 'pipe'],
            env: { ...process.env, PORT: '3030', HOSTNAME: '0.0.0.0' },
        });
    }
    else {
        // Fall back to npm run start (local development)
        dashboard = spawn('npm', ['run', 'start'], {
            cwd: dashboardDir,
            stdio: ['ignore', 'pipe', 'pipe'],
            shell: true,
        });
    }
    // Pipe dashboard output with prefix
    dashboard.stdout?.on('data', (data) => {
        const lines = data.toString().split('\n').filter((l) => l.trim());
        for (const line of lines) {
            console.log(`[dashboard] ${line}`);
        }
    });
    dashboard.stderr?.on('data', (data) => {
        const lines = data.toString().split('\n').filter((l) => l.trim());
        for (const line of lines) {
            console.error(`[dashboard] ${line}`);
        }
    });
    dashboard.on('error', (error) => {
        console.error('[dashboard] Failed to start:', error.message);
        if (!useStandalone) {
            console.error('[dashboard] Make sure to run "npm run build" in the dashboard directory first.');
        }
    });
    dashboard.on('exit', (code, signal) => {
        if (signal) {
            console.log(`[dashboard] Killed by signal ${signal}`);
        }
        else if (code !== 0) {
            console.error(`[dashboard] Exited with code ${code}`);
        }
    });
    return dashboard;
}
/**
 * Main entry point
 */
async function main() {
    // Handle --version / -v
    if (process.argv[2] === '--version' || process.argv[2] === '-v') {
        console.log(pkg.version);
        return;
    }
    // Handle "doctor" subcommand
    if (process.argv[2] === 'doctor') {
        const { handleDoctorCommand } = await import('./setup/doctor.js');
        await handleDoctorCommand();
        return;
    }
    // Handle "setup" subcommand (alias: "install")
    if (process.argv[2] === 'setup' || process.argv[2] === 'install') {
        if (process.argv[3] === 'uninstall') {
            const { uninstallSetup } = await import('./setup/uninstall.js');
            await uninstallSetup();
            return;
        }
        const stopHook = process.argv.includes('--with-stop-hook');
        await setupClaudeMd({ stopHook });
        return;
    }
    // Handle "migrate" subcommand
    if (process.argv[2] === 'migrate') {
        const { handleMigrateCommand } = await import('./setup/migrate.js');
        await handleMigrateCommand();
        return;
    }
    // Handle "uninstall" subcommand
    if (process.argv[2] === 'uninstall') {
        const { uninstallAll } = await import('./setup/uninstall.js');
        await uninstallAll({ keepLogs: process.argv.includes('--keep-logs') });
        return;
    }
    // Handle "hook" subcommand
    if (process.argv[2] === 'hook') {
        await handleHookCommand(process.argv[3] || '');
        return;
    }
    // Handle "openclaw" subcommand (backward compat: "clawdbot" also accepted)
    if (process.argv[2] === 'openclaw' || process.argv[2] === 'clawdbot') {
        await handleOpenClawCommand(process.argv[3] || '');
        return;
    }
    // Handle "service" subcommand before normal mode parsing
    if (process.argv[2] === 'service') {
        await handleServiceCommand(process.argv[3] || '');
        return;
    }
    // Handle "status" subcommand
    if (process.argv[2] === 'status') {
        const { handleStatusCommand } = await import('./setup/status.js');
        await handleStatusCommand();
        return;
    }
    // Handle "graph" subcommand
    if (process.argv[2] === 'graph') {
        const action = process.argv[3];
        if (action === 'backfill') {
            const { initDatabase } = await import('./database/init.js');
            const os = await import('os');
            const dbPath = process.env.CLAUDE_MEMORY_DB || path.join(os.homedir(), '.shieldcortex', 'memories.db');
            initDatabase(dbPath);
            const { backfillGraph } = await import('./graph/backfill.js');
            console.log('Backfilling knowledge graph from existing memories...');
            const result = backfillGraph();
            console.log(`Done! Extracted ${result.entities} new entities, ${result.triples} new triples from ${result.memoriesProcessed} memories.`);
        }
        else {
            console.error('Unknown graph command. Available: backfill');
            process.exit(1);
        }
        return;
    }
    const { dbPath, mode } = parseArgs();
    let dashboardProcess = null;
    if (mode === 'api') {
        // API mode only - for dashboard visualization
        console.log('Starting ShieldCortex in API mode...');
        startVisualizationServer(dbPath);
    }
    else if (mode === 'dashboard') {
        // Dashboard mode - API + Next.js dashboard
        console.log('Starting ShieldCortex with Dashboard...');
        startVisualizationServer(dbPath);
        dashboardProcess = startDashboard();
        // Graceful shutdown for dashboard mode
        const shutdown = (signal) => {
            console.log(`\nReceived ${signal}, shutting down...`);
            if (dashboardProcess) {
                dashboardProcess.kill('SIGTERM');
            }
            process.exit(0);
        };
        process.on('SIGINT', () => shutdown('SIGINT'));
        process.on('SIGTERM', () => shutdown('SIGTERM'));
    }
    else if (mode === 'both') {
        // Both modes - API in background, MCP in foreground
        console.log('Starting ShieldCortex in both modes...');
        startVisualizationServer(dbPath);
        await startMcpServer(dbPath);
    }
    else {
        // MCP mode (default) - for Claude Code integration
        await startMcpServer(dbPath);
    }
}
// Run
main().catch((error) => {
    // Log to stderr to avoid corrupting MCP protocol
    console.error('Failed to start shieldcortex server:', error);
    process.exit(1);
});
//# sourceMappingURL=index.js.map