/ src / commands / daemon.ts
daemon.ts
 1  /**
 2   * CLI commands for daemon lifecycle:
 3   *   opencli daemon status — show daemon state
 4   *   opencli daemon stop   — graceful shutdown
 5   */
 6  
 7  import { styleText } from 'node:util';
 8  import { fetchDaemonStatus, requestDaemonShutdown } from '../browser/daemon-client.js';
 9  import { formatDuration } from '../download/progress.js';
10  import { log } from '../logger.js';
11  
12  export async function daemonStatus(): Promise<void> {
13    const status = await fetchDaemonStatus();
14    if (!status) {
15      console.log(`Daemon: ${styleText('dim', 'not running')}`);
16      return;
17    }
18  
19    const extensionLabel = !status.extensionConnected
20      ? styleText('yellow', 'disconnected')
21      : status.extensionVersion
22        ? `${styleText('green', 'connected')} ${styleText('dim', `(v${status.extensionVersion})`)}`
23        : `${styleText('yellow', 'connected')} ${styleText('dim', '(version unknown)')}`;
24  
25    console.log(`Daemon: ${styleText('green', 'running')} (PID ${status.pid})`);
26    console.log(`Uptime: ${formatDuration(Math.round(status.uptime * 1000))}`);
27    console.log(`Extension: ${extensionLabel}`);
28    console.log(`Memory: ${status.memoryMB} MB`);
29    console.log(`Port: ${status.port}`);
30  }
31  
32  export async function daemonStop(): Promise<void> {
33    const status = await fetchDaemonStatus();
34    if (!status) {
35      log.info('Daemon is not running.');
36      return;
37    }
38  
39    const ok = await requestDaemonShutdown();
40    if (ok) {
41      log.success('Daemon stopped.');
42    } else {
43      log.error('Failed to stop daemon.');
44      process.exitCode = 1;
45    }
46  }