import * as plugins from '../../plugins.js'; import type { CliArguments, CommandAction, IpcCommandOptions } from '../types.js'; import { handleDaemonError } from '../helpers/errors.js'; import { unknownError } from '../helpers/formatting.js'; import { runIpcCommand } from '../utils/ipc.js'; import { ensureDaemonOrHint } from './daemon-check.js'; /** * Add an IPC-based CLI command with: * - optional daemon preflight * - standard error handling * - automatic disconnect via runIpcCommand unless keepAlive is true */ export function registerIpcCommand( smartcli: plugins.smartcli.Smartcli, name: string, action: CommandAction, opts: IpcCommandOptions = {} ) { const { actionLabel = name, keepAlive = false, requireDaemon = true } = opts; smartcli.addCommand(name).subscribe({ next: async (argv: CliArguments) => { // Early preflight for better UX const ok = await ensureDaemonOrHint(requireDaemon, actionLabel); if (!ok) { process.exit(1); return; } // Evaluate keepAlive - can be boolean or function const shouldKeepAlive = typeof keepAlive === 'function' ? keepAlive(argv) : keepAlive; if (shouldKeepAlive) { // Let action manage its own connection/cleanup lifecycle try { await action(argv); } catch (error) { handleDaemonError(error, actionLabel); } } else { // Auto-disconnect pattern for one-shot IPC commands await runIpcCommand(async () => { try { await action(argv); } catch (error) { handleDaemonError(error, actionLabel); } }); } }, error: (err) => { // Fallback error path (should be rare with try/catch in next) console.error(`Unexpected error in command "${name}":`, unknownError(err)); process.exit(1); }, complete: () => {}, }); } /** * Register local commands that don't require IPC/daemon connection * Used for daemon lifecycle, service management, and other local operations */ export function registerLocalCommand( smartcli: plugins.smartcli.Smartcli, name: string, action: (argv: CliArguments) => Promise, opts: { actionLabel?: string } = {} ) { const { actionLabel = name } = opts; smartcli.addCommand(name).subscribe({ next: async (argv: CliArguments) => { try { await action(argv); } catch (error: any) { console.error(`Error ${actionLabel}:`, error?.message || String(error)); process.exit(1); } }, error: (err) => { console.error(`Unexpected error in command "${name}":`, unknownError(err)); process.exit(1); }, complete: () => {}, }); }