import type { CommandDef, CommandManifest } from '@mosaic/types'; // Local-only commands (work even when gateway is disconnected) const LOCAL_COMMANDS: CommandDef[] = [ { name: 'help', description: 'Show available commands', aliases: ['h'], args: undefined, execution: 'local', available: true, scope: 'core', }, { name: 'stop', description: 'Cancel current streaming response', aliases: [], args: undefined, execution: 'local', available: true, scope: 'core', }, { name: 'cost', description: 'Show token usage and cost for current session', aliases: [], args: undefined, execution: 'local', available: true, scope: 'core', }, { name: 'status', description: 'Show connection and session status', aliases: ['s'], args: undefined, execution: 'local', available: true, scope: 'core', }, { name: 'clear', description: 'Clear the current conversation display', aliases: [], args: undefined, execution: 'local', available: true, scope: 'core', }, ]; const ALIASES: Record = { n: 'new', m: 'model', t: 'thinking', a: 'agent', s: 'status', h: 'help', pref: 'preferences', }; export class CommandRegistry { private gatewayManifest: CommandManifest | null = null; updateManifest(manifest: CommandManifest): void { this.gatewayManifest = manifest; } resolveAlias(command: string): string { return ALIASES[command] ?? command; } find(command: string): CommandDef | null { const resolved = this.resolveAlias(command); // Search local first, then gateway manifest const local = LOCAL_COMMANDS.find((c) => c.name === resolved || c.aliases.includes(resolved)); if (local) return local; if (this.gatewayManifest) { return ( this.gatewayManifest.commands.find( (c) => c.name === resolved || c.aliases.includes(resolved), ) ?? null ); } return null; } getAll(): CommandDef[] { const gateway = this.gatewayManifest?.commands ?? []; return [...LOCAL_COMMANDS, ...gateway]; } getLocalCommands(): CommandDef[] { return LOCAL_COMMANDS; } } export const commandRegistry = new CommandRegistry();