Files
BMAD-METHOD/tools/cli.js
2025-06-08 17:34:38 -05:00

215 lines
7.7 KiB
JavaScript
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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 <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 <id>', '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 <id>', '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();
}