UNPKG

@cloudkinetix/bmad-enhanced

Version:

Cloud-Kinetix enhanced fork of BMAD-METHOD - Breakthrough Method of Agile AI-driven Development with robust versioning and unified validation.

244 lines (207 loc) 7.46 kB
#!/usr/bin/env node /** * Cloud Kinetix Enhancer - Thin Layer on top of BMAD * * Minimal wrapper that adds CK-specific features without duplicating upstream functionality. * Uses a hook-based architecture to enhance BMAD commands. */ const path = require('path'); const fs = require('fs-extra'); const { spawn } = require('child_process'); class CKEnhancer { constructor() { this.hooks = { pre: {}, post: {} }; // Register default hooks this.registerDefaultHooks(); } /** * Register default CK enhancement hooks */ registerDefaultHooks() { // Pre-install: Create backup this.addHook('pre', 'install', async (options) => { if (options.backup !== false && !options.ckFeatures === false) { const BMADBackupManager = require('./bmad-backup-manager'); const backupManager = new BMADBackupManager(options.directory || process.cwd()); const result = await backupManager.createBackups(); if (result.success) { console.log(`✅ Backup created: ${result.message}`); } else { console.warn(`⚠️ Backup failed: ${result.message}`); } } }); // Post-install: Add CK features this.addHook('post', 'install', async (options, installedIDEs) => { if (options.ckFeatures !== false) { await this.installCKFeatures(options, installedIDEs); } }); // Pre-update: Create backup this.addHook('pre', 'update', async (options) => { if (options.backup !== false) { const BMADBackupManager = require('./bmad-backup-manager'); const backupManager = new BMADBackupManager(options.directory || process.cwd()); const result = await backupManager.createBackups(); if (result.success) { console.log(`✅ Pre-update backup created: ${result.message}`); } } }); } /** * Add a hook for command enhancement */ addHook(type, command, handler) { if (!this.hooks[type][command]) { this.hooks[type][command] = []; } this.hooks[type][command].push(handler); } /** * Run pre-hooks for a command */ async runPreHooks(command, options) { const hooks = this.hooks.pre[command] || []; for (const hook of hooks) { await hook(options); } } /** * Run post-hooks for a command */ async runPostHooks(command, options, result) { const hooks = this.hooks.post[command] || []; for (const hook of hooks) { await hook(options, result); } } /** * Execute upstream BMAD command */ async runUpstreamCommand(command, options) { const args = [command]; // Build arguments based on command if (command === 'install') { if (options.full) args.push('--full'); if (options.expansionOnly) args.push('--expansion-only'); if (options.directory) args.push('--directory', path.resolve(options.directory)); // Filter out CK-specific expansion packs for upstream if (options.expansionPacks && options.expansionPacks.length > 0) { const upstreamPacks = options.expansionPacks.filter(pack => !pack.startsWith('ck-')); if (upstreamPacks.length > 0) { args.push('--expansion-packs', ...upstreamPacks); } } // Use all IDEs - upstream now supports all IDEs including Trae if (options.ides && options.ides.length > 0) { const upstreamIDEs = options.ides; if (upstreamIDEs.length > 0) { args.push('--ide', ...upstreamIDEs); } } } else if (command === 'update') { if (options.force) args.push('--force'); if (options.dryRun) args.push('--dry-run'); } // Execute upstream command return new Promise((resolve, reject) => { console.log(`🚀 Running upstream BMAD ${command}...`); const child = spawn('npx', ['--yes', 'bmad-method@latest', ...args], { cwd: options.directory || process.cwd(), stdio: 'inherit' }); child.on('close', (code) => { if (code === 0) { resolve({ success: true, ides: options.ides }); } else { reject(new Error(`BMAD ${command} failed with exit code ${code}`)); } }); child.on('error', reject); }); } /** * Install CK-specific features */ async installCKFeatures(options, installedIDEs) { const ckPacks = (options.expansionPacks || []).filter(pack => pack.startsWith('ck-')); if (ckPacks.length === 0 && !options.full) { return; // No CK features to install } console.log('⭐ Installing Cloud Kinetix enterprise features...'); // Get expansion packs directory const targetDir = path.resolve(options.directory || process.cwd()); const expansionPacksSource = path.join(__dirname, '../../expansion-packs'); // Install each CK expansion pack for (const packName of ckPacks) { const sourceDir = path.join(expansionPacksSource, packName); const targetPath = path.join(targetDir, `.bmad-${packName}`); if (await fs.pathExists(sourceDir)) { console.log(`📦 Installing ${packName}...`); await fs.copy(sourceDir, targetPath, { overwrite: true }); } else { console.warn(`⚠️ CK expansion pack not found: ${packName}`); } } // IMPORTANT: We do NOT setup IDE configurations for CK agents here // because the upstream BMAD installer already handles CK expansion packs // when we pass them via --expansion-packs. The upstream installer creates // the proper organized structure: // - .claude/commands/ck/jira/agents/ // - .claude/commands/ck/ai-agent/agents/ // etc. // // Setting up IDE configurations again here would: // 1. Create duplicate files in flat structure (.claude/commands/jira.md) // 2. Conflict with the organized structure created by upstream // 3. Cause confusion with multiple command files for the same agent console.log('✅ Cloud Kinetix features installed successfully!'); } /** * Main enhancement method - wraps upstream commands */ async enhance(command, options = {}) { try { // Run pre-hooks await this.runPreHooks(command, options); // Execute upstream command const result = await this.runUpstreamCommand(command, options); // Run post-hooks await this.runPostHooks(command, options, result); return result; } catch (error) { console.error(`❌ Enhancement failed: ${error.message}`); throw error; } } /** * Check if a command should be enhanced or passed through directly */ shouldEnhance(command) { // Only enhance install and update commands return ['install', 'update'].includes(command); } /** * Direct pass-through to upstream for non-enhanced commands */ async passThrough(command, args = []) { return new Promise((resolve, reject) => { const child = spawn('npx', ['--yes', 'bmad-method@latest', command, ...args], { stdio: 'inherit' }); child.on('close', (code) => { if (code === 0) { resolve({ success: true }); } else { reject(new Error(`BMAD ${command} failed with exit code ${code}`)); } }); child.on('error', reject); }); } } module.exports = CKEnhancer;