#!/usr/bin/env node /** * BMAD v4 Build CLI * Command line interface for building agents and bundles */ const { program } = require('commander'); const WebBuilder = require('./builders/web-builder'); const DependencyResolver = require('./lib/dependency-resolver'); // Initialize resolver const resolver = new DependencyResolver(); program .name('bmad-build') .description('BMAD v4 Build System') .version('4.0.0'); // Build all web bundles and agents program .command('build') .alias('build:web') .description('Build all web bundles and standalone agents') .option('--sample-update', 'Also output to web-bundles directory') .action(async (options) => { try { const builder = new WebBuilder(); if (options.sampleUpdate) { builder.enableSampleUpdate(); } const results = await builder.buildAll(); if (results.errors.length > 0) { console.log('\nāš ļø Build completed with errors:'); results.errors.forEach(error => { console.log(` ${error.type}: ${error.name} - ${error.error}`); }); process.exit(1); } else { console.log('\nšŸŽ‰ All builds completed successfully!'); if (options.sampleUpdate) { console.log(' šŸ“ Also updated web-bundles directory'); } } } catch (error) { console.error('āŒ Build failed:', error.message); process.exit(1); } }); // Build specific bundle program .command('build:bundle') .description('Build a specific bundle') .requiredOption('-n, --name ', 'Bundle name') .action(async (options) => { try { const builder = new WebBuilder(); const configs = builder.loadBundleConfigs(); const config = configs.find(c => c.name.toLowerCase().includes(options.name.toLowerCase())); if (!config) { console.error(`āŒ Bundle not found: ${options.name}`); process.exit(1); } const result = await builder.buildBundle(config); console.log(`āœ… Built bundle: ${result.name}`); console.log(` Files: ${result.outputs.length}`); console.log(` Size: ${result.statistics.totalSize} characters`); } catch (error) { console.error('āŒ Build failed:', error.message); process.exit(1); } }); // Build standalone agent program .command('build:agent') .description('Build a standalone agent') .requiredOption('-a, --agent ', 'Agent ID') .action(async (options) => { try { const builder = new WebBuilder(); const result = await builder.buildStandaloneAgent(options.agent); console.log(`āœ… Built agent: ${result.name}`); console.log(` File: ${result.outputs[0]}`); console.log(` Size: ${result.statistics.totalSize} characters`); } catch (error) { console.error('āŒ Build failed:', error.message); process.exit(1); } }); // List available agents program .command('list:agents') .description('List all available agents') .action(() => { try { const agents = resolver.getAvailableAgents(); console.log('šŸ“‹ Available agents:'); agents.forEach(agentId => { try { const config = resolver.loadAgentConfig(agentId); const webCompatible = config.environments?.web?.available !== false; const ideOnly = config.environments?.ide?.ide_only === true; console.log(` ${agentId}: ${config.name}`); console.log(` ${config.description}`); console.log(` Environments: ${webCompatible ? 'web' : ''}${webCompatible && !ideOnly ? ', ' : ''}${!ideOnly ? 'ide' : 'ide-only'}`); console.log(''); } catch (error) { console.log(` ${agentId}: Error loading config`); } }); } catch (error) { console.error('āŒ Failed to list agents:', error.message); process.exit(1); } }); // Analyze dependencies program .command('analyze:deps') .description('Analyze agent dependencies') .option('-a, --agent ', 'Specific agent ID') .option('-g, --graph', 'Generate dependency graph') .action((options) => { try { if (options.agent) { const deps = resolver.resolveAgentDependencies(options.agent, 'web'); console.log(`šŸ“Š Dependencies for ${deps.config.name}:`); Object.entries(deps.resources).forEach(([type, resources]) => { if (resources.length > 0) { console.log(` ${type}: ${resources.join(', ')}`); } }); } else if (options.graph) { const graph = resolver.generateDependencyGraph(); console.log('šŸ“ˆ Dependency Graph:'); console.log(` Nodes: ${graph.nodes.length}`); console.log(` Edges: ${graph.edges.length}`); console.log('\n Agents:'); graph.nodes.filter(n => n.type === 'agent').forEach(n => { console.log(` ${n.id}: ${n.label}`); }); } else { const agents = resolver.getAvailableAgents(); console.log('šŸ“Š All Agent Dependencies:'); agents.forEach(agentId => { try { const deps = resolver.resolveAgentDependencies(agentId, 'web'); const totalDeps = Object.values(deps.resources).reduce((sum, arr) => sum + arr.length, 0); console.log(` ${agentId}: ${totalDeps} total dependencies`); } catch (error) { console.log(` ${agentId}: Error resolving dependencies`); } }); } } catch (error) { console.error('āŒ Analysis failed:', error.message); process.exit(1); } }); // Validate configuration program .command('validate') .description('Validate all configurations') .action(() => { try { const agents = resolver.getAvailableAgents(); let errors = 0; console.log('šŸ” Validating configurations...'); agents.forEach(agentId => { try { const deps = resolver.resolveAgentDependencies(agentId, 'web'); console.log(` āœ… ${agentId}: Valid`); } catch (error) { console.log(` āŒ ${agentId}: ${error.message}`); errors++; } }); if (errors > 0) { console.log(`\nāŒ Validation failed: ${errors} errors found`); process.exit(1); } else { console.log('\nāœ… All configurations valid!'); } } catch (error) { console.error('āŒ Validation failed:', error.message); process.exit(1); } }); // Handle unknown commands program.on('command:*', () => { console.error('Invalid command: %s\nSee --help for a list of available commands.', program.args.join(' ')); process.exit(1); }); // Parse command line arguments program.parse(); // Show help if no command provided if (!process.argv.slice(2).length) { program.outputHelp(); }