import type { Command } from './types.js'; import type { CommandRunner, CommandRunnerContext as RunnerContext } from './command-runner.js'; import { parseCommand } from './command-parse.js'; import { applyCommandSchema } from './command-apply.js'; export type CommandRegistry = Map>; export function createCommandRegistry(): CommandRegistry { return new Map(); } export function registerCommand( registry: CommandRegistry, runner: CommandRunner ): void { registry.set(runner.schema.name, runner as CommandRunner); } export function unregisterCommand( registry: CommandRegistry, name: string ): void { registry.delete(name); } export function hasCommand( registry: CommandRegistry, name: string ): boolean { return registry.has(name); } export function getCommand( registry: CommandRegistry, name: string ): CommandRunner | undefined { return registry.get(name); } async function executeWithRunnerContext( registry: CommandRegistry, context: TContext, runner: CommandRunner, command: Command ): Promise<{ success: true; result: unknown } | { success: false; error: string }> { const runnerCtx: RunnerContext = { context, run: (input: string) => runCommand(registry, context, input), runParsed: (cmd: Command) => runCommandParsed(registry, context, cmd), }; try { const result = await runner.run.call(runnerCtx, command); return { success: true, result }; } catch (e) { const error = e as Error; return { success: false, error: error.message }; } } export async function runCommand( registry: CommandRegistry, context: TContext, input: string ): Promise<{ success: true; result: unknown } | { success: false; error: string }> { const command = parseCommand(input); return await runCommandParsed(registry, context, command); } export async function runCommandParsed( registry: CommandRegistry, context: TContext, command: Command ): Promise<{ success: true; result: unknown } | { success: false; error: string }> { const runner = registry.get(command.name); if (!runner) { return { success: false, error: `Unknown command: ${command.name}` }; } const validationResult = applyCommandSchema(command, runner.schema); if (!validationResult.valid) { return { success: false, error: validationResult.errors.join('; ') }; } return await executeWithRunnerContext(registry, context, runner, validationResult.command); } export type CommandRunnerContext = RunnerContext & { registry: CommandRegistry; }; export function createCommandRunnerContext( registry: CommandRegistry, context: TContext ): CommandRunnerContext { return { registry, context, run: (input: string) => runCommand(registry, context, input), runParsed: (command: Command) => runCommandParsed(registry, context, command), }; }