fix: BMAD install creates .bmad-core/.bmad-core/ directory structure + updates (#223)
* chore: fix installation directory handling to use .bmad-core as default path - Remove redundant ./ prefix from default directory - Update all default paths from ./.bmad-core to .bmad-core - Add logic to handle direct .bmad-core path selection - Treat parent as project root when .bmad-core specified - Simplify directory state detection for existing files - Remove unknown_existing state type from installer logic * chore: refactor installer to use modern JS patterns and improve code clarity ## CHANGES - Replace require with node:path import - Add block scoping to switch cases - Remove unused options parameter from update - Use optional chaining for ideConfig check - Replace forEach with for...of loops - Use template literals for string concatenation - Add early return to avoid else block - Update spell check dictionary entries * chore: update dependencies to latest major versions ## CHANGES - Update @kayvan/markdown-tree-parser to v1.5.0 - Update chalk to v5.4.1 for ESM support - Update commander to v14.0.0 with Node 20 requirement - Update fs-extra to v11.3.0 - Update glob to v11.0.3 with new API - Update inquirer to v12.6.3 with modular design - Update ora to v8.2.0 with improved features
This commit is contained in:
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -27,6 +27,7 @@
|
|||||||
"Luxon",
|
"Luxon",
|
||||||
"MERN",
|
"MERN",
|
||||||
"mgmt",
|
"mgmt",
|
||||||
|
"nodir",
|
||||||
"Nuxt",
|
"Nuxt",
|
||||||
"overcommitting",
|
"overcommitting",
|
||||||
"pasteable",
|
"pasteable",
|
||||||
@@ -58,6 +59,8 @@
|
|||||||
"Turborepo",
|
"Turborepo",
|
||||||
"Underserved",
|
"Underserved",
|
||||||
"unredacted",
|
"unredacted",
|
||||||
|
"upgrader",
|
||||||
|
"upgraders",
|
||||||
"VARCHAR",
|
"VARCHAR",
|
||||||
"venv",
|
"venv",
|
||||||
"vercel",
|
"vercel",
|
||||||
|
|||||||
1265
package-lock.json
generated
1265
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@@ -23,14 +23,14 @@
|
|||||||
"prepare": "husky"
|
"prepare": "husky"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kayvan/markdown-tree-parser": "^1.4.2",
|
"@kayvan/markdown-tree-parser": "^1.5.0",
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^5.4.1",
|
||||||
"commander": "^9.4.1",
|
"commander": "^14.0.0",
|
||||||
"fs-extra": "^11.1.0",
|
"fs-extra": "^11.3.0",
|
||||||
"glob": "^8.0.3",
|
"glob": "^11.0.3",
|
||||||
"inquirer": "^8.2.5",
|
"inquirer": "^12.6.3",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"ora": "^5.4.1"
|
"ora": "^8.2.0"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"agile",
|
"agile",
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ program
|
|||||||
.description('Install BMAD Method agents and tools')
|
.description('Install BMAD Method agents and tools')
|
||||||
.option('-f, --full', 'Install complete .bmad-core folder')
|
.option('-f, --full', 'Install complete .bmad-core folder')
|
||||||
.option('-a, --agent <agent>', 'Install specific agent with dependencies')
|
.option('-a, --agent <agent>', 'Install specific agent with dependencies')
|
||||||
.option('-d, --directory <path>', 'Installation directory (default: ./bmad-core)')
|
.option('-d, --directory <path>', 'Installation directory (default: .bmad-core)')
|
||||||
.option('-i, --ide <ide>', 'Configure for specific IDE (cursor, claude-code, windsurf, roo)')
|
.option('-i, --ide <ide>', 'Configure for specific IDE (cursor, claude-code, windsurf, roo)')
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
try {
|
try {
|
||||||
@@ -50,7 +50,7 @@ program
|
|||||||
const config = {
|
const config = {
|
||||||
installType: options.full ? 'full' : 'single-agent',
|
installType: options.full ? 'full' : 'single-agent',
|
||||||
agent: options.agent,
|
agent: options.agent,
|
||||||
directory: options.directory || './.bmad-core',
|
directory: options.directory || '.bmad-core',
|
||||||
ide: options.ide
|
ide: options.ide
|
||||||
};
|
};
|
||||||
await installer.install(config);
|
await installer.install(config);
|
||||||
@@ -66,9 +66,9 @@ program
|
|||||||
.description('Update existing BMAD installation')
|
.description('Update existing BMAD installation')
|
||||||
.option('--force', 'Force update, overwriting modified files')
|
.option('--force', 'Force update, overwriting modified files')
|
||||||
.option('--dry-run', 'Show what would be updated without making changes')
|
.option('--dry-run', 'Show what would be updated without making changes')
|
||||||
.action(async (options) => {
|
.action(async () => {
|
||||||
try {
|
try {
|
||||||
await installer.update(options);
|
await installer.update();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(chalk.red('Update failed:'), error.message);
|
console.error(chalk.red('Update failed:'), error.message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
@@ -110,7 +110,7 @@ async function promptInstallation() {
|
|||||||
type: 'input',
|
type: 'input',
|
||||||
name: 'directory',
|
name: 'directory',
|
||||||
message: 'Where would you like to install BMAD?',
|
message: 'Where would you like to install BMAD?',
|
||||||
default: './.bmad-core'
|
default: '.bmad-core'
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
answers.directory = directory;
|
answers.directory = directory;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const path = require("path");
|
const path = require("node:path");
|
||||||
const chalk = require("chalk");
|
const chalk = require("chalk");
|
||||||
const ora = require("ora");
|
const ora = require("ora");
|
||||||
const inquirer = require("inquirer");
|
const inquirer = require("inquirer");
|
||||||
@@ -12,7 +12,11 @@ class Installer {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Resolve installation directory
|
// Resolve installation directory
|
||||||
const installDir = path.resolve(config.directory);
|
let installDir = path.resolve(config.directory);
|
||||||
|
if (path.basename(installDir) === '.bmad-core') {
|
||||||
|
// If user points directly to .bmad-core, treat its parent as the project root
|
||||||
|
installDir = path.dirname(installDir);
|
||||||
|
}
|
||||||
|
|
||||||
// Detect current state
|
// Detect current state
|
||||||
const state = await this.detectInstallationState(installDir);
|
const state = await this.detectInstallationState(installDir);
|
||||||
@@ -103,9 +107,9 @@ class Installer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
state.type = "unknown_existing";
|
// Directory has other files, but no BMAD installation.
|
||||||
|
// Treat as clean install but record that it isn't empty.
|
||||||
state.hasOtherFiles = true;
|
state.hasOtherFiles = true;
|
||||||
return state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return state; // clean install
|
return state; // clean install
|
||||||
@@ -253,11 +257,12 @@ class Installer {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "upgrade":
|
case "upgrade": {
|
||||||
console.log(chalk.cyan("\n📦 Starting v3 to v4 upgrade process..."));
|
console.log(chalk.cyan("\n📦 Starting v3 to v4 upgrade process..."));
|
||||||
const V3ToV4Upgrader = require("../../upgraders/v3-to-v4-upgrader");
|
const V3ToV4Upgrader = require("../../upgraders/v3-to-v4-upgrader");
|
||||||
const upgrader = new V3ToV4Upgrader();
|
const upgrader = new V3ToV4Upgrader();
|
||||||
return await upgrader.upgrade({ projectPath: installDir });
|
return await upgrader.upgrade({ projectPath: installDir });
|
||||||
|
}
|
||||||
case "alongside":
|
case "alongside":
|
||||||
return await this.performFreshInstall(config, installDir, spinner);
|
return await this.performFreshInstall(config, installDir, spinner);
|
||||||
case "cancel":
|
case "cancel":
|
||||||
@@ -295,7 +300,7 @@ class Installer {
|
|||||||
switch (action) {
|
switch (action) {
|
||||||
case "force":
|
case "force":
|
||||||
return await this.performFreshInstall(config, installDir, spinner);
|
return await this.performFreshInstall(config, installDir, spinner);
|
||||||
case "different":
|
case "different": {
|
||||||
const { newDir } = await inquirer.prompt([
|
const { newDir } = await inquirer.prompt([
|
||||||
{
|
{
|
||||||
type: "input",
|
type: "input",
|
||||||
@@ -306,6 +311,7 @@ class Installer {
|
|||||||
]);
|
]);
|
||||||
config.directory = newDir;
|
config.directory = newDir;
|
||||||
return await this.install(config);
|
return await this.install(config);
|
||||||
|
}
|
||||||
case "cancel":
|
case "cancel":
|
||||||
console.log("Installation cancelled.");
|
console.log("Installation cancelled.");
|
||||||
return;
|
return;
|
||||||
@@ -326,7 +332,9 @@ class Installer {
|
|||||||
if (modifiedFiles.length > 0) {
|
if (modifiedFiles.length > 0) {
|
||||||
spinner.warn("Found modified files");
|
spinner.warn("Found modified files");
|
||||||
console.log(chalk.yellow("\nThe following files have been modified:"));
|
console.log(chalk.yellow("\nThe following files have been modified:"));
|
||||||
modifiedFiles.forEach((file) => console.log(` - ${file}`));
|
for (const file of modifiedFiles) {
|
||||||
|
console.log(` - ${file}`);
|
||||||
|
}
|
||||||
|
|
||||||
const { action } = await inquirer.prompt([
|
const { action } = await inquirer.prompt([
|
||||||
{
|
{
|
||||||
@@ -391,9 +399,9 @@ class Installer {
|
|||||||
|
|
||||||
if (config.ide) {
|
if (config.ide) {
|
||||||
const ideConfig = configLoader.getIdeConfiguration(config.ide);
|
const ideConfig = configLoader.getIdeConfiguration(config.ide);
|
||||||
if (ideConfig && ideConfig.instructions) {
|
if (ideConfig?.instructions) {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.bold("To use BMAD agents in " + ideConfig.name + ":")
|
chalk.bold(`To use BMAD agents in ${ideConfig.name}:`)
|
||||||
);
|
);
|
||||||
console.log(ideConfig.instructions);
|
console.log(ideConfig.instructions);
|
||||||
}
|
}
|
||||||
@@ -418,7 +426,7 @@ class Installer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Legacy method for backward compatibility
|
// Legacy method for backward compatibility
|
||||||
async update(options) {
|
async update() {
|
||||||
console.log(chalk.yellow('The "update" command is deprecated.'));
|
console.log(chalk.yellow('The "update" command is deprecated.'));
|
||||||
console.log(
|
console.log(
|
||||||
'Please use "install" instead - it will detect and offer to update existing installations.'
|
'Please use "install" instead - it will detect and offer to update existing installations.'
|
||||||
@@ -432,9 +440,8 @@ class Installer {
|
|||||||
ide: null,
|
ide: null,
|
||||||
};
|
};
|
||||||
return await this.install(config);
|
return await this.install(config);
|
||||||
} else {
|
|
||||||
console.log(chalk.red("No BMAD installation found."));
|
|
||||||
}
|
}
|
||||||
|
console.log(chalk.red("No BMAD installation found."));
|
||||||
}
|
}
|
||||||
|
|
||||||
async listAgents() {
|
async listAgents() {
|
||||||
@@ -442,9 +449,9 @@ class Installer {
|
|||||||
|
|
||||||
console.log(chalk.bold("\nAvailable BMAD Agents:\n"));
|
console.log(chalk.bold("\nAvailable BMAD Agents:\n"));
|
||||||
|
|
||||||
agents.forEach((agent) => {
|
for (const agent of agents) {
|
||||||
console.log(chalk.cyan(` ${agent.id.padEnd(20)}`), agent.description);
|
console.log(chalk.cyan(` ${agent.id.padEnd(20)}`), agent.description);
|
||||||
});
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
chalk.dim("\nInstall with: npx bmad-method install --agent=<id>\n")
|
chalk.dim("\nInstall with: npx bmad-method install --agent=<id>\n")
|
||||||
|
|||||||
868
tools/installer/package-lock.json
generated
868
tools/installer/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bmad-method",
|
"name": "bmad-method",
|
||||||
"version": "4.0.0",
|
"version": "4.0.1",
|
||||||
"description": "BMAD Method installer - AI-powered Agile development framework",
|
"description": "BMAD Method installer - AI-powered Agile development framework",
|
||||||
"main": "lib/installer.js",
|
"main": "lib/installer.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -22,12 +22,12 @@
|
|||||||
"author": "BMAD Team",
|
"author": "BMAD Team",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^5.4.1",
|
||||||
"commander": "^9.4.1",
|
"commander": "^14.0.0",
|
||||||
"fs-extra": "^11.1.0",
|
"fs-extra": "^11.3.0",
|
||||||
"inquirer": "^8.2.5",
|
"inquirer": "^12.6.3",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"ora": "^5.4.1"
|
"ora": "^8.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user