diff --git a/tools/cli/installers/lib/ide/_base-ide.js b/tools/cli/installers/lib/ide/_base-ide.js index 936629045..fb392bd82 100644 --- a/tools/cli/installers/lib/ide/_base-ide.js +++ b/tools/cli/installers/lib/ide/_base-ide.js @@ -15,7 +15,7 @@ class BaseIdeSetup { this.configDir = null; // Override in subclasses (e.g., '.windsurf/workflows/wds') this.configFile = null; // Override in subclasses when detection is file-based this.detectionPaths = []; // Additional paths that indicate the IDE is configured - this.wdsFolderName = '_wds'; // Default, can be overridden + this.wdsFolderName = '_bmad/wds'; // Default, can be overridden } /** diff --git a/tools/cli/installers/lib/ide/manager.js b/tools/cli/installers/lib/ide/manager.js index 2ef2c2c9f..2b068ab36 100644 --- a/tools/cli/installers/lib/ide/manager.js +++ b/tools/cli/installers/lib/ide/manager.js @@ -10,7 +10,7 @@ class IdeManager { constructor() { this.handlers = new Map(); this.loadHandlers(); - this.wdsFolderName = '_wds'; // Default, can be overridden + this.wdsFolderName = '_bmad/wds'; // Default, can be overridden } /** diff --git a/tools/cli/lib/compiler.js b/tools/cli/lib/compiler.js index a0209f22b..e42471e1f 100644 --- a/tools/cli/lib/compiler.js +++ b/tools/cli/lib/compiler.js @@ -346,7 +346,7 @@ function rewritePaths(content, wdsFolder) { // --- Main Compilation --- function compileAgentFile(yamlPath, options = {}) { - const wdsFolder = options.wdsFolder || '_wds'; + const wdsFolder = options.wdsFolder || '_bmad/wds'; const rawContent = fs.readFileSync(yamlPath, 'utf8'); // Rewrite paths before parsing diff --git a/tools/cli/lib/installer.js b/tools/cli/lib/installer.js index ab853f48c..8be038448 100644 --- a/tools/cli/lib/installer.js +++ b/tools/cli/lib/installer.js @@ -26,8 +26,28 @@ class Installer { async install(config) { const { projectDir, wdsFolder, root_folder } = config; const wdsDir = path.join(projectDir, wdsFolder); + const detection = config._detection || { type: 'fresh' }; - // Check if already installed + // Handle legacy _wds/ → _bmad/wds/ migration + if (detection.type === 'legacy' && wdsFolder !== '_wds') { + const legacyDir = path.join(projectDir, '_wds'); + const legacyConfigPath = path.join(legacyDir, 'config.yaml'); + + // Save config from legacy location + if (await fs.pathExists(legacyConfigPath)) { + let savedConfig = await fs.readFile(legacyConfigPath, 'utf8'); + // Update wds_folder in saved config to new path + savedConfig = savedConfig.replace(/wds_folder:.*/, `wds_folder: ${wdsFolder}`); + config._savedConfigYaml = savedConfig; + } + + const migrateSpinner = ora(`Migrating _wds/ → ${wdsFolder}/...`).start(); + await fs.ensureDir(path.dirname(wdsDir)); + await fs.remove(legacyDir); + migrateSpinner.succeed(`Legacy _wds/ removed — installing fresh at ${wdsFolder}/`); + } + + // Check if already installed at target path if (await fs.pathExists(wdsDir)) { console.log(chalk.yellow(`\n ${wdsFolder}/ already exists.`)); const { action } = await inquirer.prompt([ @@ -68,6 +88,9 @@ class Installer { } } + // Ensure parent directory exists (for _bmad/wds/) + await fs.ensureDir(path.dirname(wdsDir)); + console.log(''); // Step 1: Copy source files diff --git a/tools/cli/lib/ui.js b/tools/cli/lib/ui.js index 028925ee5..c7ca0294f 100644 --- a/tools/cli/lib/ui.js +++ b/tools/cli/lib/ui.js @@ -6,6 +6,10 @@ const chalk = require('chalk'); const figlet = require('figlet'); const inquirer = require('inquirer').default || require('inquirer'); const path = require('node:path'); +const fs = require('fs-extra'); + +const WDS_FOLDER = '_bmad/wds'; +const LEGACY_WDS_FOLDER = '_wds'; class UI { /** @@ -22,6 +26,26 @@ class UI { console.log(chalk.dim(' Strategic design methodology for AI-powered workflows\n')); } + /** + * Detect existing WDS installation and determine folder path + */ + async detectInstallation(projectDir) { + const hasBmadWds = await fs.pathExists(path.join(projectDir, WDS_FOLDER)); + const hasLegacyWds = await fs.pathExists(path.join(projectDir, LEGACY_WDS_FOLDER)); + const hasBmadDir = await fs.pathExists(path.join(projectDir, '_bmad')); + + if (hasBmadWds) { + return { type: 'bmad', folder: WDS_FOLDER }; + } + if (hasLegacyWds) { + return { type: 'legacy', folder: LEGACY_WDS_FOLDER }; + } + if (hasBmadDir) { + return { type: 'bmad-ready', folder: WDS_FOLDER }; + } + return { type: 'fresh', folder: WDS_FOLDER }; + } + /** * Run the full prompt flow and return config */ @@ -30,9 +54,35 @@ class UI { const projectDir = process.cwd(); const defaultProjectName = path.basename(projectDir); + const detection = await this.detectInstallation(projectDir); console.log(chalk.white(` Target: ${chalk.cyan(projectDir)}`)); - console.log(chalk.dim(` Agents and workflows will be installed in ${chalk.white('_wds/')}\n`)); + + // Handle legacy _wds/ detection + let wdsFolder = detection.folder; + if (detection.type === 'legacy') { + console.log(chalk.yellow(`\n Found legacy installation at ${chalk.white(LEGACY_WDS_FOLDER + '/')}`)); + console.log(chalk.dim(` BMAD standard path is ${chalk.white(WDS_FOLDER + '/')}\n`)); + + const { migrationChoice } = await inquirer.prompt([ + { + type: 'list', + name: 'migrationChoice', + message: 'How would you like to proceed?', + choices: [ + { name: `Migrate to ${WDS_FOLDER}/ (recommended)`, value: 'migrate' }, + { name: `Keep at ${LEGACY_WDS_FOLDER}/ (legacy)`, value: 'keep' }, + ], + }, + ]); + + if (migrationChoice === 'keep') { + wdsFolder = LEGACY_WDS_FOLDER; + } + // 'migrate' keeps the default WDS_FOLDER — installer.js handles the actual move + } else { + console.log(chalk.dim(` Agents and workflows will be installed in ${chalk.white(wdsFolder + '/')}\n`)); + } // 5-question installer const answers = await inquirer.prompt([ @@ -102,7 +152,8 @@ class UI { return { projectDir, ...answers, - wdsFolder: '_wds', + wdsFolder, + _detection: detection, cancelled: false, }; }