import type { Command } from 'commander'; import { getDaemonPid, readMeta, startDaemon, stopDaemon, waitForHealth, } from './gateway/daemon.js'; interface GatewayParentOpts { host: string; port: string; token?: string; } function resolveOpts(raw: GatewayParentOpts): { host: string; port: number; token?: string } { const meta = readMeta(); return { host: raw.host ?? meta?.host ?? 'localhost', port: parseInt(raw.port, 10) || meta?.port || 14242, token: raw.token ?? meta?.adminToken, }; } export function registerGatewayCommand(program: Command): void { const gw = program .command('gateway') .description('Manage the Mosaic gateway daemon') .helpOption('--help', 'Display help') .option('-h, --host ', 'Gateway host', 'localhost') .option('-p, --port ', 'Gateway port', '14242') .option('-t, --token ', 'Admin API token') .action(() => { gw.outputHelp(); }); // ─── install ──────────────────────────────────────────────────────────── gw.command('install') .description('Install and configure the gateway daemon') .option('--skip-install', 'Skip npm package installation (use local build)') .action(async (cmdOpts: { skipInstall?: boolean }) => { const opts = resolveOpts(gw.opts() as GatewayParentOpts); const { runInstall } = await import('./gateway/install.js'); await runInstall({ ...opts, skipInstall: cmdOpts.skipInstall }); }); // ─── start ────────────────────────────────────────────────────────────── gw.command('start') .description('Start the gateway daemon') .action(async () => { const opts = resolveOpts(gw.opts() as GatewayParentOpts); try { const pid = startDaemon(); console.log(`Gateway started (PID ${pid.toString()})`); console.log('Waiting for health...'); const healthy = await waitForHealth(opts.host, opts.port); if (healthy) { console.log(`Gateway ready at http://${opts.host}:${opts.port.toString()}`); } else { console.warn('Gateway started but health check timed out. Check logs.'); } } catch (err) { console.error(err instanceof Error ? err.message : String(err)); process.exit(1); } }); // ─── stop ─────────────────────────────────────────────────────────────── gw.command('stop') .description('Stop the gateway daemon') .action(async () => { try { await stopDaemon(); console.log('Gateway stopped.'); } catch (err) { console.error(err instanceof Error ? err.message : String(err)); process.exit(1); } }); // ─── restart ──────────────────────────────────────────────────────────── gw.command('restart') .description('Restart the gateway daemon') .action(async () => { const opts = resolveOpts(gw.opts() as GatewayParentOpts); const pid = getDaemonPid(); if (pid !== null) { console.log('Stopping gateway...'); await stopDaemon(); } console.log('Starting gateway...'); try { const newPid = startDaemon(); console.log(`Gateway started (PID ${newPid.toString()})`); const healthy = await waitForHealth(opts.host, opts.port); if (healthy) { console.log(`Gateway ready at http://${opts.host}:${opts.port.toString()}`); } else { console.warn('Gateway started but health check timed out. Check logs.'); } } catch (err) { console.error(err instanceof Error ? err.message : String(err)); process.exit(1); } }); // ─── status ───────────────────────────────────────────────────────────── gw.command('status') .description('Show gateway daemon status and health') .action(async () => { const opts = resolveOpts(gw.opts() as GatewayParentOpts); const { runStatus } = await import('./gateway/status.js'); await runStatus(opts); }); // ─── config ───────────────────────────────────────────────────────────── gw.command('config') .description('View or modify gateway configuration') .option('--set ', 'Set a configuration value') .option('--unset ', 'Remove a configuration key') .option('--edit', 'Open config in $EDITOR') .action(async (cmdOpts: { set?: string; unset?: string; edit?: boolean }) => { const { runConfig } = await import('./gateway/config.js'); await runConfig(cmdOpts); }); // ─── logs ─────────────────────────────────────────────────────────────── gw.command('logs') .description('View gateway daemon logs') .option('-f, --follow', 'Follow log output') .option('-n, --lines ', 'Number of lines to show', '50') .action(async (cmdOpts: { follow?: boolean; lines?: string }) => { const { runLogs } = await import('./gateway/logs.js'); runLogs({ follow: cmdOpts.follow, lines: parseInt(cmdOpts.lines ?? '50', 10) }); }); // ─── uninstall ────────────────────────────────────────────────────────── gw.command('uninstall') .description('Uninstall the gateway daemon and optionally remove data') .action(async () => { const { runUninstall } = await import('./gateway/uninstall.js'); await runUninstall(); }); }