Skip to main content
Glama

Curupira

by drzln
command-registry.ts6.08 kB
/** * @fileoverview Command registry for managing command definitions */ import { createLogger } from '@curupira/shared' import type { CommandDefinition, BaseCommand } from '../types.js' import { CommandParser } from './command-parser.js' // Import command implementations import { InitCommand } from '../commands/init.js' import { ValidateCommand } from '../commands/validate.js' import { StartCommand } from '../commands/start.js' const logger = createLogger({ level: 'info', name: 'command-registry' }) /** * Central registry for all CLI commands */ export class CommandRegistry { private parser: CommandParser private definitions: Map<string, CommandDefinition> = new Map() constructor() { this.parser = new CommandParser() this.registerBuiltInCommands() } /** * Get the command parser instance */ getParser(): CommandParser { return this.parser } /** * Register a command definition */ registerCommand(definition: CommandDefinition): void { logger.debug({ command: definition.name }, 'Registering command definition') this.definitions.set(definition.name, definition) this.parser.registerCommand(definition) } /** * Get a command definition by name */ getCommand(name: string): CommandDefinition | undefined { return this.definitions.get(name) } /** * Get all registered command definitions */ getAllCommands(): CommandDefinition[] { return Array.from(this.definitions.values()) } /** * Register all built-in commands */ private registerBuiltInCommands(): void { logger.info('Registering built-in commands') // Init command this.registerCommand({ name: 'init', description: 'Initialize Curupira in a React project', options: [ { name: 'force', short: 'f', description: 'Overwrite existing configuration', type: 'boolean', default: false } ], examples: [ 'curupira init # Create curupira.yml', 'curupira init --force # Overwrite existing config' ], handler: new InitCommand() }) // Validate command this.registerCommand({ name: 'validate', description: 'Validate curupira.yml configuration', options: [ { name: 'fix', short: 'f', description: 'Auto-fix common issues', type: 'boolean', default: false } ], examples: [ 'curupira validate # Validate configuration', 'curupira validate --fix # Validate and attempt to fix issues' ], handler: new ValidateCommand() }) // Start command this.registerCommand({ name: 'start', description: 'Start Curupira MCP server', options: [ { name: 'port', short: 'p', description: 'Server port', type: 'number' }, { name: 'host', short: 'h', description: 'Server host', type: 'string' } ], examples: [ 'curupira start # Start MCP server', 'curupira start -p 3000 # Start on specific port', 'curupira start --host 0.0.0.0 # Start on all interfaces' ], handler: new StartCommand() }) logger.info({ count: this.definitions.size }, 'Registered built-in commands') } /** * Create command definition from handler */ static createDefinition( name: string, description: string, handler: BaseCommand, options?: Partial<CommandDefinition> ): CommandDefinition { return { name, description, handler, ...options } } /** * Validate all registered commands */ validateRegistry(): { valid: boolean; errors: string[] } { const errors: string[] = [] for (const [name, definition] of this.definitions) { // Check handler exists if (!definition.handler) { errors.push(`Command '${name}' missing handler`) continue } // Check handler implements BaseCommand interface if (typeof definition.handler.execute !== 'function') { errors.push(`Command '${name}' handler missing execute method`) } if (!definition.handler.name) { errors.push(`Command '${name}' handler missing name property`) } if (!definition.handler.description) { errors.push(`Command '${name}' handler missing description property`) } // Validate options if (definition.options) { for (const option of definition.options) { if (!option.name || !option.description || !option.type) { errors.push(`Command '${name}' has invalid option definition`) } } } // Validate flags if (definition.flags) { for (const flag of definition.flags) { if (!flag.name || !flag.description) { errors.push(`Command '${name}' has invalid flag definition`) } } } // Check for name conflicts with aliases if (definition.aliases) { for (const alias of definition.aliases) { if (this.definitions.has(alias)) { errors.push(`Command '${name}' alias '${alias}' conflicts with existing command`) } } } } return { valid: errors.length === 0, errors } } /** * Get command statistics */ getStats(): { totalCommands: number totalAliases: number totalOptions: number totalFlags: number } { let totalAliases = 0 let totalOptions = 0 let totalFlags = 0 for (const definition of this.definitions.values()) { totalAliases += definition.aliases?.length || 0 totalOptions += definition.options?.length || 0 totalFlags += definition.flags?.length || 0 } return { totalCommands: this.definitions.size, totalAliases, totalOptions, totalFlags } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/drzln/curupira'

If you have feedback or need assistance with the MCP directory API, please join our Discord server