UNPKG

@morodomi/ait3

Version:

AIT³ Development Platform - AI + Ticket + Test + Tool driven development methodology

127 lines (126 loc) 5 kB
import { Command } from 'commander'; import { join, dirname } from 'path'; import { mkdir, writeFile, access } from 'fs/promises'; import { STYLES } from '../../common/styles.js'; import { ait3Template } from '../../assets/commands/ait3.js'; import { geminiTemplate } from '../../assets/commands/gemini.js'; import { orchestratorTemplate } from '../../assets/commands/orchestrator.js'; import { ait3InitTemplate } from '../../assets/commands/ait3-init.js'; import { codeReviewTemplate } from '../../assets/commands/code-review.js'; // Command name to template mapping const commandTemplates = { ait3: ait3Template, gemini: geminiTemplate, orchestrator: orchestratorTemplate, 'ait3-init': ait3InitTemplate, 'code-review': codeReviewTemplate }; export async function installCommand(args) { const { name = 'all', force = false } = args; // Determine which files to install let filesToInstall = []; if (name === 'all' || !name) { // Install all command guides filesToInstall = Object.keys(commandTemplates).map(cmd => [cmd, cmd]); } else if (name in commandTemplates) { // Install specific command guide filesToInstall = [[name, name]]; } else { // Invalid command name return { success: false, message: `${STYLES.danger('ERROR: Unknown command')}: ${name}\n${STYLES.info('Available commands')}: ${Object.keys(commandTemplates).join(', ')}` }; } const messages = []; let installedCount = 0; let skippedCount = 0; let hasExistingFile = false; // Show intent if (!name || name === 'all') { messages.push(`${STYLES.info('PACKAGE: Installing all command guides')}...`); } // Process each file for (const [cmdName, _fileName] of filesToInstall) { const targetPath = join('.claude', 'commands', cmdName); const targetDir = dirname(targetPath); try { // Create directory if needed try { await access(targetDir); } catch { await mkdir(targetDir, { recursive: true }); messages.push(`${STYLES.success('SUCCESS:')} Created directory: ${STYLES.info(targetDir)}`); } // Check if file exists let shouldWrite = true; try { await access(targetPath); hasExistingFile = true; if (!force) { shouldWrite = false; messages.push(`${STYLES.warning('⚠')} Skipped: ${STYLES.info(targetPath)} already exists (use --force to overwrite)`); skippedCount++; } else { messages.push(`${STYLES.warning('⚠')} Overwriting existing file: ${STYLES.info(targetPath)}`); } } catch { // File doesn't exist, good to proceed } if (shouldWrite) { // Get template content const templateContent = commandTemplates[cmdName]; if (!templateContent) { throw new Error(`Template not found for command: ${cmdName}`); } // Write file await writeFile(targetPath, templateContent, 'utf-8'); messages.push(`${STYLES.success('SUCCESS:')} Installed: ${STYLES.info(targetPath)}`); installedCount++; } } catch (error) { return { success: false, message: `${STYLES.danger('ERROR: Failed to create')}: ${targetPath}\n${error instanceof Error ? error.message : 'Unknown error'}` }; } } // Check if we were trying to install a single specific file that already exists if (name && name !== 'all' && filesToInstall.length === 1 && hasExistingFile && !force && installedCount === 0) { return { success: false, message: messages.join('\n') }; } // Summary messages.push(''); messages.push(`${STYLES.success('SUCCESS: Installation complete')}: ${installedCount} file(s) installed${skippedCount > 0 ? `, ${skippedCount} skipped` : ''}`); return { success: true, message: messages.join('\n') }; } export const commandCommand = new Command('command') .description('Install Claude command guides') .argument('[name]', 'Command name to install (default: all)', 'all') .option('-f, --force', 'Overwrite existing files', false) .action(async (name, options) => { const args = { name, force: options.force }; try { const result = await installCommand(args); console.log(result.message); if (!result.success) { process.exit(1); } } catch (error) { console.error(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`); process.exit(1); } });