UNPKG

aiwg

Version:

Cognitive architecture for AI-augmented software development with structured memory, ensemble validation, and closed-loop correction. FAIR-aligned artifacts, 84% cost reduction via human-in-the-loop, standards adopted by 100+ organizations.

192 lines (171 loc) 5.76 kB
/** * Help Generator * * Dynamically generates CLI help text from the extension registry. * Replaces hardcoded displayHelp() with registry-driven approach. * * @implements @.aiwg/architecture/decisions/ADR-001-unified-extension-system.md * @tests @test/unit/cli/help-generator.test.ts * @version 1.0.0 */ import type { ExtensionRegistry } from '../extensions/registry.js'; import type { Extension } from '../extensions/types.js'; import type { CommandCategory } from './handlers/types.js'; /** * Category display order and titles * * Determines the order in which command categories appear in help output. */ const CATEGORY_ORDER: { category: CommandCategory; title: string }[] = [ { category: 'framework', title: 'Framework Management' }, { category: 'project', title: 'Project Setup' }, { category: 'workspace', title: 'Workspace Management' }, { category: 'mcp', title: 'MCP Server' }, { category: 'toolsmith', title: 'Toolsmith (Runtime Discovery)' }, { category: 'catalog', title: 'Model Catalog' }, { category: 'utility', title: 'Utilities' }, { category: 'plugin', title: 'Plugin Packaging' }, { category: 'scaffolding', title: 'Scaffolding' }, { category: 'channel', title: 'Channel Management' }, { category: 'maintenance', title: 'Maintenance' }, { category: 'ralph', title: 'Ralph Loop (Iterative Execution)' }, ]; /** * Command name column width for alignment */ const COMMAND_COL_WIDTH = 24; /** * Generate help text from registry * * Dynamically builds CLI help text by querying the extension registry for * command extensions, grouping them by category, and formatting them for display. * * @param registry - Extension registry to query * @returns Formatted help text * * @example * ```typescript * import { getRegistry } from '../extensions/registry.js'; * import { generateHelp } from './help-generator.js'; * * const registry = getRegistry(); * const helpText = generateHelp(registry); * console.log(helpText); * ``` */ export function generateHelp(registry: ExtensionRegistry): string { const lines: string[] = []; // Header lines.push('AIWG CLI'); lines.push(''); lines.push('Usage: aiwg <command> [options]'); lines.push(''); // Get commands by category const commands = registry.getByType('command'); const byCategory = groupByCategory(commands); // Generate sections in order for (const { category, title } of CATEGORY_ORDER) { const categoryCommands = byCategory.get(category); if (!categoryCommands || categoryCommands.length === 0) continue; lines.push(`${title}:`); for (const cmd of categoryCommands) { const name = formatCommandName(cmd); const desc = cmd.description; lines.push(` ${name.padEnd(COMMAND_COL_WIDTH)} ${desc}`); } lines.push(''); } // Platform options lines.push('Platform Options (--provider):'); lines.push(' claude Claude Code (default)'); lines.push(' copilot GitHub Copilot'); lines.push(' factory Factory AI'); lines.push(' codex / openai OpenAI Codex'); lines.push(' cursor Cursor IDE'); lines.push(' opencode OpenCode'); lines.push(' warp Warp Terminal'); lines.push(' windsurf Windsurf'); lines.push(''); // Examples lines.push('Examples:'); lines.push(' aiwg use sdlc Install SDLC framework'); lines.push(' aiwg -new Create new project'); lines.push(' aiwg doctor Check installation health'); lines.push(''); return lines.join('\n'); } /** * Group commands by category * * Takes a flat list of command extensions and organizes them into a Map * keyed by category, with values being arrays of extensions. * * @param commands - Array of command extensions * @returns Map of category to command extensions * * @example * ```typescript * const commands = registry.getByType('command'); * const grouped = groupByCategory(commands); * * const frameworkCommands = grouped.get('framework'); * console.log(`${frameworkCommands?.length} framework commands`); * ``` */ function groupByCategory(commands: Extension[]): Map<string, Extension[]> { const map = new Map<string, Extension[]>(); for (const cmd of commands) { const category = cmd.category || 'utility'; let list = map.get(category); if (!list) { list = []; map.set(category, list); } list.push(cmd); } // Sort commands within each category by ID // Use Array.from to convert values() iterator to array Array.from(map.values()).forEach((list) => { list.sort((a, b) => a.id.localeCompare(b.id)); }); return map; } /** * Format command name with primary alias * * Returns a formatted command name string that includes the primary alias * (if present) for display in help text. * * Format: * - No aliases: "command-name" * - With aliases: "command-name, -alias" * * @param cmd - Command extension * @returns Formatted command name string * * @example * ```typescript * // Command with no aliases * const name1 = formatCommandName(useCmd); * // Returns: "use" * * // Command with aliases * const name2 = formatCommandName(newCmd); * // Returns: "new, -new" * * // Command with multiple aliases * const name3 = formatCommandName(helpCmd); * // Returns: "help, -h" * ``` */ function formatCommandName(cmd: Extension): string { // Get aliases from metadata const metadata = cmd.metadata as any; const aliases = metadata?.aliases || []; // If no aliases, just return ID if (aliases.length === 0) { return cmd.id; } // Show command name with first alias return `${cmd.id}, ${aliases[0]}`; }