Compare commits

...

8 Commits

Author SHA1 Message Date
Phil 7e99c36f76
Merge 6caca55e43 into 1c13305f9f 2026-01-30 12:10:32 -06:00
Murat K Ozcan 1c13305f9f
Merge pull request #1476 from jheyworth/fix/installer-peer-deps-comprehensive
fix: resolve npm install peer dependency issues
2026-01-30 12:05:34 -06:00
jheyworth 6198add5bd fix: resolve npm install peer dependency issues
Comprehensive fix for installer failures related to Astro/Starlight peer dependencies:

1. Update @astrojs/starlight from 0.37.0 to 0.37.5 (latest stable)
2. Add .npmrc with legacy-peer-deps to prevent peer dependency warnings
3. Update module installer to use --legacy-peer-deps flag for external modules

This resolves issues where:
- npm shows peer dependency warnings that users interpret as failures
- External module installations fail due to strict peer dependency checking
- Different npm versions handle peer dependencies inconsistently

Technical note: Starlight 0.37.x requires astro@^5.5.0, which is compatible
with astro@5.16.0 (^5.5.0 means >=5.5.0 <6.0.0). The issue was npm's warning
display, not actual incompatibility.

Fixes: Installation errors reported in v6.0.0-Beta.2

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-30 15:37:42 +00:00
Phil 6caca55e43
Merge branch 'main' into dir-install-flag 2026-01-26 10:12:47 -05:00
Brian 2c3285f47e
Merge branch 'main' into dir-install-flag 2026-01-25 14:11:01 -06:00
Brian c46453259f
Merge branch 'main' into dir-install-flag 2026-01-24 19:46:50 -06:00
Phil 83ed3a978d
Merge branch 'main' into dir-install-flag 2026-01-23 13:09:19 -05:00
Phil Mahncke 3dd05b0584 feat: enhance install command with directory option and update prompt logic
Added a new CLI option for specifying the target project directory, allowing users to skip the interactive prompt. Updated the installation prompt method to accept options and handle directory validation accordingly.
2026-01-22 22:31:13 -05:00
6 changed files with 682 additions and 667 deletions

6
.npmrc
View File

@ -1 +1,5 @@
registry=https://registry.npmjs.org # Prevent peer dependency warnings during installation
legacy-peer-deps=true
# Improve install performance
prefer-offline=true

1309
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -88,7 +88,7 @@
}, },
"devDependencies": { "devDependencies": {
"@astrojs/sitemap": "^3.6.0", "@astrojs/sitemap": "^3.6.0",
"@astrojs/starlight": "^0.37.0", "@astrojs/starlight": "^0.37.5",
"@eslint/js": "^9.33.0", "@eslint/js": "^9.33.0",
"archiver": "^7.0.1", "archiver": "^7.0.1",
"astro": "^5.16.0", "astro": "^5.16.0",

View File

@ -9,7 +9,10 @@ const ui = new UI();
module.exports = { module.exports = {
command: 'install', command: 'install',
description: 'Install BMAD Core agents and tools', description: 'Install BMAD Core agents and tools',
options: [['-d, --debug', 'Enable debug output for manifest generation']], options: [
['-d, --debug', 'Enable debug output for manifest generation'],
['-D, --directory <path>', 'Target project directory (skips interactive prompt)'],
],
action: async (options) => { action: async (options) => {
try { try {
// Set debug flag as environment variable for all components // Set debug flag as environment variable for all components
@ -18,7 +21,7 @@ module.exports = {
console.log(chalk.cyan('Debug mode enabled\n')); console.log(chalk.cyan('Debug mode enabled\n'));
} }
const config = await ui.promptInstall(); const config = await ui.promptInstall(options);
// Handle cancel // Handle cancel
if (config.actionType === 'cancel') { if (config.actionType === 'cancel') {

View File

@ -416,7 +416,7 @@ class ModuleManager {
if (needsDependencyInstall || wasNewClone || nodeModulesMissing) { if (needsDependencyInstall || wasNewClone || nodeModulesMissing) {
const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start(); const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
try { try {
execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress', { execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress --legacy-peer-deps', {
cwd: moduleCacheDir, cwd: moduleCacheDir,
stdio: 'pipe', stdio: 'pipe',
timeout: 120_000, // 2 minute timeout timeout: 120_000, // 2 minute timeout
@ -441,7 +441,7 @@ class ModuleManager {
if (packageJsonNewer) { if (packageJsonNewer) {
const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start(); const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
try { try {
execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress', { execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress --legacy-peer-deps', {
cwd: moduleCacheDir, cwd: moduleCacheDir,
stdio: 'pipe', stdio: 'pipe',
timeout: 120_000, // 2 minute timeout timeout: 120_000, // 2 minute timeout

View File

@ -26,9 +26,10 @@ const choiceUtils = { Separator };
class UI { class UI {
/** /**
* Prompt for installation configuration * Prompt for installation configuration
* @param {Object} options - CLI options object (may contain directory property)
* @returns {Object} Installation configuration * @returns {Object} Installation configuration
*/ */
async promptInstall() { async promptInstall(options = {}) {
CLIUtils.displayLogo(); CLIUtils.displayLogo();
// Display version-specific start message from install-messages.yaml // Display version-specific start message from install-messages.yaml
@ -36,7 +37,7 @@ class UI {
const messageLoader = new MessageLoader(); const messageLoader = new MessageLoader();
messageLoader.displayStartMessage(); messageLoader.displayStartMessage();
const confirmedDirectory = await this.getConfirmedDirectory(); const confirmedDirectory = await this.getConfirmedDirectory(options);
// Preflight: Check for legacy BMAD v4 footprints immediately after getting directory // Preflight: Check for legacy BMAD v4 footprints immediately after getting directory
const { Detector } = require('../installers/lib/core/detector'); const { Detector } = require('../installers/lib/core/detector');
@ -506,9 +507,23 @@ class UI {
/** /**
* Get confirmed directory from user * Get confirmed directory from user
* @param {Object} options - CLI options object (may contain directory property)
* @returns {string} Confirmed directory path * @returns {string} Confirmed directory path
*/ */
async getConfirmedDirectory() { async getConfirmedDirectory(options = {}) {
// If directory provided via CLI, validate and return it
if (options.directory) {
const expandedPath = this.expandUserPath(options.directory);
const validationError = this.validateDirectorySync(expandedPath);
if (validationError) {
throw new Error(`Invalid directory: ${validationError}`);
}
await this.displayDirectoryInfo(expandedPath);
// Skip confirmation for CLI-provided directories
return expandedPath;
}
// Existing interactive prompt logic
let confirmedDirectory = null; let confirmedDirectory = null;
while (!confirmedDirectory) { while (!confirmedDirectory) {
const directoryAnswer = await this.promptForDirectory(); const directoryAnswer = await this.promptForDirectory();