diff --git a/package.json b/package.json index 511f7fae..e8583be3 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ }, "scripts": { "bmad:install": "node tools/cli/bmad-cli.js install", - "bmad:status": "node tools/cli/bmad-cli.js status", "bundle": "node tools/cli/bundlers/bundle-web.js all", "flatten": "node tools/flattener/main.js", "format:check": "prettier --check \"**/*.{js,cjs,mjs,json,md,yaml}\"", diff --git a/tools/cli/commands/build.js b/tools/cli/commands/build.js deleted file mode 100644 index 50c12b83..00000000 --- a/tools/cli/commands/build.js +++ /dev/null @@ -1,283 +0,0 @@ -const chalk = require('chalk'); -const path = require('node:path'); -const fs = require('fs-extra'); -const { YamlXmlBuilder } = require('../lib/agent/yaml-xml-builder'); -const { getProjectRoot } = require('../lib/project-root'); - -const builder = new YamlXmlBuilder(); - -/** - * Find .claude directory by searching up from current directory - */ -async function findClaudeDir(startDir) { - let currentDir = startDir; - const root = path.parse(currentDir).root; - - while (currentDir !== root) { - const claudeDir = path.join(currentDir, '.claude'); - if (await fs.pathExists(claudeDir)) { - return claudeDir; - } - currentDir = path.dirname(currentDir); - } - - return null; -} - -module.exports = { - command: 'build [agent]', - description: 'Build agent XML files from YAML sources', - options: [ - ['-a, --all', 'Build all agents'], - ['-d, --directory ', 'Project directory', '.'], - ], - action: async (agentName, options) => { - try { - let projectDir = path.resolve(options.directory); - - // Auto-detect .claude directory (search up from current dir) - const claudeDir = await findClaudeDir(projectDir); - if (!claudeDir) { - console.log(chalk.yellow('\n⚠️ No .claude directory found')); - console.log(chalk.dim('Run this command from your project directory or')); - console.log(chalk.dim('use --directory flag to specify location')); - console.log(chalk.dim('\nExample: npx bmad-method build pm --directory /path/to/project')); - process.exit(1); - } - - // Use the directory containing .claude - projectDir = path.dirname(claudeDir); - console.log(chalk.dim(`Using project: ${projectDir}\n`)); - - console.log(chalk.cyan('🔨 Building Agent Files\n')); - - if (options.all) { - // Build all agents - await buildAllAgents(projectDir); - } else if (agentName) { - // Build specific agent - await buildAgent(projectDir, agentName); - } else { - // No agent specified, list available agents - console.log(chalk.yellow('No agent specified. Use --all to build all agents or specify an agent name.')); - console.log(chalk.dim('\nAvailable agents:')); - await listAvailableAgents(projectDir); - } - - process.exit(0); - } catch (error) { - console.error(chalk.red('\nError:'), error.message); - if (process.env.DEBUG) { - console.error(error.stack); - } - process.exit(1); - } - }, -}; - -/** - * Build a specific agent - */ -async function buildAgent(projectDir, agentName) { - // First check standalone agents in bmad/agents/{agentname}/ - const standaloneAgentDir = path.join(projectDir, '_bmad', 'agents', agentName); - let standaloneYamlPath = path.join(standaloneAgentDir, `${agentName}.agent.yaml`); - - // If exact match doesn't exist, look for any .agent.yaml file in the directory - if (!(await fs.pathExists(standaloneYamlPath)) && (await fs.pathExists(standaloneAgentDir))) { - const files = await fs.readdir(standaloneAgentDir); - const agentFile = files.find((f) => f.endsWith('.agent.yaml')); - if (agentFile) { - standaloneYamlPath = path.join(standaloneAgentDir, agentFile); - } - } - - if (await fs.pathExists(standaloneYamlPath)) { - const yamlFileName = path.basename(standaloneYamlPath, '.agent.yaml'); - const outputPath = path.join(standaloneAgentDir, `${yamlFileName}.md`); - - // Build the standalone agent - console.log(chalk.cyan(` Building standalone agent ${agentName}...`)); - - const customizePath = path.join(projectDir, '_bmad', '_config', 'agents', `${agentName}.customize.yaml`); - const customizeExists = await fs.pathExists(customizePath); - - await builder.buildAgent(standaloneYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true }); - - console.log(chalk.green(` ✓ ${agentName} built successfully (standalone)`)); - return; - } - - // Find the agent YAML file in .claude/commands/bmad/ - const bmadCommandsDir = path.join(projectDir, '.claude', 'commands', '_bmad'); - - // Search all module directories for the agent - const modules = await fs.readdir(bmadCommandsDir); - let found = false; - - for (const module of modules) { - const agentYamlPath = path.join(bmadCommandsDir, module, 'agents', `${agentName}.agent.yaml`); - const outputPath = path.join(bmadCommandsDir, module, 'agents', `${agentName}.md`); - - if (await fs.pathExists(agentYamlPath)) { - found = true; - - // Build the agent - console.log(chalk.cyan(` Building ${agentName}...`)); - - const customizePath = path.join(projectDir, '.claude', '_config', 'agents', `${agentName}.customize.yaml`); - const customizeExists = await fs.pathExists(customizePath); - - await builder.buildAgent(agentYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true }); - - console.log(chalk.green(` ✓ ${agentName} built successfully`)); - return; - } - } - - if (!found) { - console.log(chalk.yellow(` ⚠️ Agent '${agentName}' not found`)); - console.log(chalk.dim(' Available agents:')); - await listAvailableAgents(projectDir); - } -} - -/** - * Build all agents - */ -async function buildAllAgents(projectDir) { - let builtCount = 0; - - // First, build standalone agents in bmad/agents/ - const standaloneAgentsDir = path.join(projectDir, '_bmad', 'agents'); - if (await fs.pathExists(standaloneAgentsDir)) { - console.log(chalk.cyan('\nBuilding standalone agents...')); - const agentDirs = await fs.readdir(standaloneAgentsDir); - - for (const agentDirName of agentDirs) { - const agentDir = path.join(standaloneAgentsDir, agentDirName); - - // Skip if not a directory - const stat = await fs.stat(agentDir); - if (!stat.isDirectory()) { - continue; - } - - // Find any .agent.yaml file in the directory - const files = await fs.readdir(agentDir); - const agentFile = files.find((f) => f.endsWith('.agent.yaml')); - - if (!agentFile) { - continue; - } - - const agentYamlPath = path.join(agentDir, agentFile); - const agentName = path.basename(agentFile, '.agent.yaml'); - const outputPath = path.join(agentDir, `${agentName}.md`); - - console.log(chalk.cyan(` Building standalone agent ${agentName}...`)); - - const customizePath = path.join(projectDir, '_bmad', '_config', 'agents', `${agentName}.customize.yaml`); - const customizeExists = await fs.pathExists(customizePath); - - await builder.buildAgent(agentYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true }); - - console.log(chalk.green(` ✓ ${agentName} (standalone)`)); - builtCount++; - } - } - - // Then, build module agents in .claude/commands/bmad/ - const bmadCommandsDir = path.join(projectDir, '.claude', 'commands', 'bmad'); - if (await fs.pathExists(bmadCommandsDir)) { - console.log(chalk.cyan('\nBuilding module agents...')); - const modules = await fs.readdir(bmadCommandsDir); - - for (const module of modules) { - const agentsDir = path.join(bmadCommandsDir, module, 'agents'); - - if (!(await fs.pathExists(agentsDir))) { - continue; - } - - const files = await fs.readdir(agentsDir); - - for (const file of files) { - if (!file.endsWith('.agent.yaml')) { - continue; - } - - const agentName = file.replace('.agent.yaml', ''); - const agentYamlPath = path.join(agentsDir, file); - const outputPath = path.join(agentsDir, `${agentName}.md`); - - console.log(chalk.cyan(` Building ${agentName}...`)); - - const customizePath = path.join(projectDir, '.claude', '_config', 'agents', `${agentName}.customize.yaml`); - const customizeExists = await fs.pathExists(customizePath); - - await builder.buildAgent(agentYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true }); - - console.log(chalk.green(` ✓ ${agentName} (${module})`)); - builtCount++; - } - } - } - - console.log(chalk.green(`\n✓ Built ${builtCount} agent(s)`)); -} - -/** - * List available agents - */ -async function listAvailableAgents(projectDir) { - // List standalone agents first - const standaloneAgentsDir = path.join(projectDir, 'bmad', 'agents'); - if (await fs.pathExists(standaloneAgentsDir)) { - console.log(chalk.dim(' Standalone agents:')); - const agentDirs = await fs.readdir(standaloneAgentsDir); - - for (const agentDirName of agentDirs) { - const agentDir = path.join(standaloneAgentsDir, agentDirName); - - // Skip if not a directory - const stat = await fs.stat(agentDir); - if (!stat.isDirectory()) { - continue; - } - - // Find any .agent.yaml file in the directory - const files = await fs.readdir(agentDir); - const agentFile = files.find((f) => f.endsWith('.agent.yaml')); - - if (agentFile) { - const agentName = path.basename(agentFile, '.agent.yaml'); - console.log(chalk.dim(` - ${agentName} (in ${agentDirName}/)`)); - } - } - } - - // List module agents - const bmadCommandsDir = path.join(projectDir, '.claude', 'commands', 'bmad'); - if (await fs.pathExists(bmadCommandsDir)) { - console.log(chalk.dim(' Module agents:')); - const modules = await fs.readdir(bmadCommandsDir); - - for (const module of modules) { - const agentsDir = path.join(bmadCommandsDir, module, 'agents'); - - if (!(await fs.pathExists(agentsDir))) { - continue; - } - - const files = await fs.readdir(agentsDir); - - for (const file of files) { - if (file.endsWith('.agent.yaml')) { - const agentName = file.replace('.agent.yaml', ''); - console.log(chalk.dim(` - ${agentName} (${module})`)); - } - } - } - } -} diff --git a/tools/cli/commands/list.js b/tools/cli/commands/list.js deleted file mode 100644 index de2bd465..00000000 --- a/tools/cli/commands/list.js +++ /dev/null @@ -1,40 +0,0 @@ -const chalk = require('chalk'); -const { Installer } = require('../installers/lib/core/installer'); - -const installer = new Installer(); - -module.exports = { - command: 'list', - description: 'List available modules', - options: [], - action: async () => { - try { - const result = await installer.getAvailableModules(); - const { modules, customModules } = result; - - console.log(chalk.cyan('\n📦 Available BMAD Modules:\n')); - - for (const module of modules) { - console.log(chalk.bold(` ${module.id}`)); - console.log(chalk.dim(` ${module.description}`)); - console.log(chalk.dim(` Version: ${module.version}`)); - console.log(); - } - - if (customModules && customModules.length > 0) { - console.log(chalk.cyan('\n🔧 Custom Modules:\n')); - for (const module of customModules) { - console.log(chalk.bold(` ${module.id}`)); - console.log(chalk.dim(` ${module.description}`)); - console.log(chalk.dim(` Version: ${module.version}`)); - console.log(); - } - } - - process.exit(0); - } catch (error) { - console.error(chalk.red('Error:'), error.message); - process.exit(1); - } - }, -}; diff --git a/tools/cli/commands/status.js b/tools/cli/commands/status.js deleted file mode 100644 index 34ce22d0..00000000 --- a/tools/cli/commands/status.js +++ /dev/null @@ -1,47 +0,0 @@ -const chalk = require('chalk'); -const { Installer } = require('../installers/lib/core/installer'); - -const installer = new Installer(); - -module.exports = { - command: 'status', - description: 'Show installation status', - options: [['-d, --directory ', 'Installation directory', '.']], - action: async (options) => { - try { - const status = await installer.getStatus(options.directory); - - if (!status.installed) { - console.log(chalk.yellow('\n⚠️ No BMAD installation found in:'), options.directory); - console.log(chalk.dim('Run "bmad install" to set up BMAD Method')); - process.exit(0); - } - - console.log(chalk.cyan('\n📊 BMAD Installation Status\n')); - console.log(chalk.bold('Location:'), status.path); - console.log(chalk.bold('Version:'), status.version); - console.log(chalk.bold('Core:'), status.hasCore ? chalk.green('✓ Installed') : chalk.red('✗ Not installed')); - - if (status.modules.length > 0) { - console.log(chalk.bold('\nModules:')); - for (const mod of status.modules) { - console.log(` ${chalk.green('✓')} ${mod.id} (v${mod.version})`); - } - } else { - console.log(chalk.bold('\nModules:'), chalk.dim('None installed')); - } - - if (status.ides.length > 0) { - console.log(chalk.bold('\nConfigured IDEs:')); - for (const ide of status.ides) { - console.log(` ${chalk.green('✓')} ${ide}`); - } - } - - process.exit(0); - } catch (error) { - console.error(chalk.red('Error:'), error.message); - process.exit(1); - } - }, -}; diff --git a/tools/cli/commands/uninstall.js b/tools/cli/commands/uninstall.js deleted file mode 100644 index 1834ae47..00000000 --- a/tools/cli/commands/uninstall.js +++ /dev/null @@ -1,44 +0,0 @@ -const chalk = require('chalk'); -const path = require('node:path'); -const { Installer } = require('../installers/lib/core/installer'); -const { UI } = require('../lib/ui'); - -const installer = new Installer(); -const ui = new UI(); - -module.exports = { - command: 'uninstall', - description: 'Remove BMAD installation', - options: [ - ['-d, --directory ', 'Installation directory', '.'], - ['--force', 'Skip confirmation prompt'], - ], - action: async (options) => { - try { - const bmadPath = path.join(options.directory, 'bmad'); - - if (!options.force) { - const { confirm } = await ui.prompt([ - { - type: 'confirm', - name: 'confirm', - message: `Are you sure you want to remove BMAD from ${bmadPath}?`, - default: false, - }, - ]); - - if (!confirm) { - console.log('Uninstall cancelled.'); - process.exit(0); - } - } - - await installer.uninstall(options.directory); - console.log(chalk.green('\n✨ BMAD Method has been uninstalled.')); - process.exit(0); - } catch (error) { - console.error(chalk.red('Uninstall failed:'), error.message); - process.exit(1); - } - }, -}; diff --git a/tools/cli/commands/update.js b/tools/cli/commands/update.js deleted file mode 100644 index 19ae5646..00000000 --- a/tools/cli/commands/update.js +++ /dev/null @@ -1,28 +0,0 @@ -const chalk = require('chalk'); -const { Installer } = require('../installers/lib/core/installer'); - -const installer = new Installer(); - -module.exports = { - command: 'update', - description: 'Update existing BMAD installation', - options: [ - ['-d, --directory ', 'Installation directory', '.'], - ['--force', 'Force update, overwriting modified files'], - ['--dry-run', 'Show what would be updated without making changes'], - ], - action: async (options) => { - try { - await installer.update({ - directory: options.directory, - force: options.force, - dryRun: options.dryRun, - }); - console.log(chalk.green('\n✨ Update complete!')); - process.exit(0); - } catch (error) { - console.error(chalk.red('Update failed:'), error.message); - process.exit(1); - } - }, -};