bmad-method 6.2.2 → 6.2.3-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +78 -0
- package/package.json +8 -8
- package/src/core-skills/bmad-distillator/resources/distillate-format-reference.md +1 -1
- package/src/core-skills/bmad-init/scripts/bmad_init.py +35 -4
- package/src/core-skills/bmad-init/scripts/tests/test_bmad_init.py +64 -0
- package/tools/{cli → installer}/bmad-cli.js +3 -1
- package/tools/{cli/lib → installer}/cli-utils.js +3 -4
- package/tools/{cli → installer}/commands/install.js +3 -3
- package/tools/{cli → installer}/commands/status.js +4 -4
- package/tools/{cli → installer}/commands/uninstall.js +5 -5
- package/tools/installer/core/config.js +52 -0
- package/tools/{cli/installers/lib → installer}/core/custom-module-cache.js +1 -1
- package/tools/installer/core/existing-install.js +127 -0
- package/tools/installer/core/install-paths.js +129 -0
- package/tools/installer/core/installer.js +1790 -0
- package/tools/{cli/installers/lib → installer}/core/manifest-generator.js +3 -3
- package/tools/{cli/installers/lib → installer}/core/manifest.js +2 -2
- package/tools/{cli/installers/lib/custom/handler.js → installer/custom-handler.js} +1 -1
- package/tools/{cli/installers/lib → installer}/ide/_config-driven.js +30 -397
- package/tools/{cli/installers/lib → installer}/ide/manager.js +1 -53
- package/tools/installer/ide/platform-codes.js +37 -0
- package/tools/installer/ide/platform-codes.yaml +190 -0
- package/tools/{cli/installers/lib → installer}/ide/shared/module-injections.js +1 -1
- package/tools/{cli/installers/lib → installer}/message-loader.js +2 -2
- package/tools/installer/modules/custom-modules.js +197 -0
- package/tools/installer/modules/external-manager.js +323 -0
- package/tools/{cli/installers/lib/core/config-collector.js → installer/modules/official-modules.js} +714 -43
- package/tools/{cli/lib → installer}/ui.js +65 -299
- package/tools/javascript-conventions.md +5 -0
- package/tools/bmad-npx-wrapper.js +0 -38
- package/tools/cli/installers/lib/core/dependency-resolver.js +0 -743
- package/tools/cli/installers/lib/core/detector.js +0 -223
- package/tools/cli/installers/lib/core/ide-config-manager.js +0 -157
- package/tools/cli/installers/lib/core/installer.js +0 -3002
- package/tools/cli/installers/lib/ide/_base-ide.js +0 -657
- package/tools/cli/installers/lib/ide/platform-codes.js +0 -100
- package/tools/cli/installers/lib/ide/platform-codes.yaml +0 -341
- package/tools/cli/installers/lib/modules/external-manager.js +0 -136
- package/tools/cli/installers/lib/modules/manager.js +0 -928
- package/tools/cli/lib/config.js +0 -213
- package/tools/cli/lib/platform-codes.js +0 -116
- package/tools/lib/xml-utils.js +0 -13
- /package/tools/{cli → installer}/README.md +0 -0
- /package/tools/{cli → installer}/external-official-modules.yaml +0 -0
- /package/tools/{cli/lib → installer}/file-ops.js +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/shared/agent-command-generator.js +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/shared/bmad-artifacts.js +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/shared/path-utils.js +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/shared/skill-manifest.js +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/agent-command-template.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/antigravity.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/default-agent.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/default-task.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/default-tool.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/default-workflow.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/gemini-agent.toml +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/gemini-task.toml +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/gemini-tool.toml +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/gemini-workflow-yaml.toml +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/gemini-workflow.toml +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/kiro-agent.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/kiro-task.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/kiro-tool.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/kiro-workflow.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/opencode-agent.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/opencode-task.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/opencode-tool.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/opencode-workflow-yaml.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/opencode-workflow.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/rovodev.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/trae.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/combined/windsurf-workflow.md +0 -0
- /package/tools/{cli/installers/lib → installer}/ide/templates/split/.gitkeep +0 -0
- /package/tools/{cli/installers → installer}/install-messages.yaml +0 -0
- /package/tools/{cli/lib → installer}/project-root.js +0 -0
- /package/tools/{cli/lib → installer}/prompts.js +0 -0
- /package/tools/{cli/lib → installer}/yaml-format.js +0 -0
|
@@ -2,8 +2,8 @@ const path = require('node:path');
|
|
|
2
2
|
const os = require('node:os');
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const { CLIUtils } = require('./cli-utils');
|
|
5
|
-
const { CustomHandler } = require('
|
|
6
|
-
const { ExternalModuleManager } = require('
|
|
5
|
+
const { CustomHandler } = require('./custom-handler');
|
|
6
|
+
const { ExternalModuleManager } = require('./modules/external-manager');
|
|
7
7
|
const prompts = require('./prompts');
|
|
8
8
|
|
|
9
9
|
// Separator class for visual grouping in select/multiselect prompts
|
|
@@ -32,7 +32,7 @@ class UI {
|
|
|
32
32
|
await CLIUtils.displayLogo();
|
|
33
33
|
|
|
34
34
|
// Display version-specific start message from install-messages.yaml
|
|
35
|
-
const { MessageLoader } = require('
|
|
35
|
+
const { MessageLoader } = require('./message-loader');
|
|
36
36
|
const messageLoader = new MessageLoader();
|
|
37
37
|
await messageLoader.displayStartMessage();
|
|
38
38
|
|
|
@@ -51,125 +51,11 @@ class UI {
|
|
|
51
51
|
confirmedDirectory = await this.getConfirmedDirectory();
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
const { Detector } = require('../installers/lib/core/detector');
|
|
56
|
-
const { Installer } = require('../installers/lib/core/installer');
|
|
57
|
-
const detector = new Detector();
|
|
54
|
+
const { Installer } = require('./core/installer');
|
|
58
55
|
const installer = new Installer();
|
|
59
|
-
const
|
|
60
|
-
if (legacyV4.hasLegacyV4) {
|
|
61
|
-
await installer.handleLegacyV4Migration(confirmedDirectory, legacyV4);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Check for legacy folders and prompt for rename before showing any menus
|
|
65
|
-
let hasLegacyCfg = false;
|
|
66
|
-
let hasLegacyBmadFolder = false;
|
|
67
|
-
let bmadDir = null;
|
|
68
|
-
let legacyBmadPath = null;
|
|
69
|
-
|
|
70
|
-
// First check for legacy .bmad folder (instead of _bmad)
|
|
71
|
-
// Only check if directory exists
|
|
72
|
-
if (await fs.pathExists(confirmedDirectory)) {
|
|
73
|
-
const entries = await fs.readdir(confirmedDirectory, { withFileTypes: true });
|
|
74
|
-
for (const entry of entries) {
|
|
75
|
-
if (entry.isDirectory() && (entry.name === '.bmad' || entry.name === 'bmad')) {
|
|
76
|
-
hasLegacyBmadFolder = true;
|
|
77
|
-
legacyBmadPath = path.join(confirmedDirectory, entry.name);
|
|
78
|
-
bmadDir = legacyBmadPath;
|
|
79
|
-
|
|
80
|
-
// Check if it has _cfg folder
|
|
81
|
-
const cfgPath = path.join(legacyBmadPath, '_cfg');
|
|
82
|
-
if (await fs.pathExists(cfgPath)) {
|
|
83
|
-
hasLegacyCfg = true;
|
|
84
|
-
}
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// If no .bmad or bmad found, check for current installations _bmad
|
|
91
|
-
if (!hasLegacyBmadFolder) {
|
|
92
|
-
const bmadResult = await installer.findBmadDir(confirmedDirectory);
|
|
93
|
-
bmadDir = bmadResult.bmadDir;
|
|
94
|
-
hasLegacyCfg = bmadResult.hasLegacyCfg;
|
|
95
|
-
}
|
|
56
|
+
const { bmadDir } = await installer.findBmadDir(confirmedDirectory);
|
|
96
57
|
|
|
97
|
-
//
|
|
98
|
-
// Show version warning instead of offering conversion
|
|
99
|
-
if (hasLegacyBmadFolder || hasLegacyCfg) {
|
|
100
|
-
await prompts.log.warn('LEGACY INSTALLATION DETECTED');
|
|
101
|
-
await prompts.note(
|
|
102
|
-
'Found a ".bmad"/"bmad" folder, or a legacy "_cfg" folder under the bmad folder -\n' +
|
|
103
|
-
'this is from an old BMAD version that is out of date for automatic upgrade,\n' +
|
|
104
|
-
'manual intervention required.\n\n' +
|
|
105
|
-
'You have a legacy version installed (v4 or alpha).\n' +
|
|
106
|
-
'Legacy installations may have compatibility issues.\n\n' +
|
|
107
|
-
'For the best experience, we strongly recommend:\n' +
|
|
108
|
-
' 1. Delete your current BMAD installation folder (.bmad or bmad)\n' +
|
|
109
|
-
' 2. Run a fresh installation\n\n' +
|
|
110
|
-
'If you do not want to start fresh, you can attempt to proceed beyond this\n' +
|
|
111
|
-
'point IF you have ensured the bmad folder is named _bmad, and under it there\n' +
|
|
112
|
-
'is a _config folder. If you have a folder under your bmad folder named _cfg,\n' +
|
|
113
|
-
'you would need to rename it _config, and then restart the installer.\n\n' +
|
|
114
|
-
'Benefits of a fresh install:\n' +
|
|
115
|
-
' \u2022 Cleaner configuration without legacy artifacts\n' +
|
|
116
|
-
' \u2022 All new features properly configured\n' +
|
|
117
|
-
' \u2022 Fewer potential conflicts\n\n' +
|
|
118
|
-
'If you have already produced output from an earlier alpha version, you can\n' +
|
|
119
|
-
'still retain those artifacts. After installation, ensure you configured during\n' +
|
|
120
|
-
'install the proper file locations for artifacts depending on the module you\n' +
|
|
121
|
-
'are using, or move the files to the proper locations.',
|
|
122
|
-
'Legacy Installation Detected',
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
const proceed = await prompts.select({
|
|
126
|
-
message: 'How would you like to proceed?',
|
|
127
|
-
choices: [
|
|
128
|
-
{
|
|
129
|
-
name: 'Cancel and do a fresh install (recommended)',
|
|
130
|
-
value: 'cancel',
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: 'Proceed anyway (will attempt update, potentially may fail or have unstable behavior)',
|
|
134
|
-
value: 'proceed',
|
|
135
|
-
},
|
|
136
|
-
],
|
|
137
|
-
default: 'cancel',
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
if (proceed === 'cancel') {
|
|
141
|
-
await prompts.note('1. Delete the existing bmad folder in your project\n' + "2. Run 'bmad install' again", 'To do a fresh install');
|
|
142
|
-
process.exit(0);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const s = await prompts.spinner();
|
|
147
|
-
s.start('Updating folder structure...');
|
|
148
|
-
try {
|
|
149
|
-
// Handle .bmad folder
|
|
150
|
-
if (hasLegacyBmadFolder) {
|
|
151
|
-
const newBmadPath = path.join(confirmedDirectory, '_bmad');
|
|
152
|
-
await fs.move(legacyBmadPath, newBmadPath);
|
|
153
|
-
bmadDir = newBmadPath;
|
|
154
|
-
s.stop(`Renamed "${path.basename(legacyBmadPath)}" to "_bmad"`);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Handle _cfg folder (either from .bmad or standalone)
|
|
158
|
-
const cfgPath = path.join(bmadDir, '_cfg');
|
|
159
|
-
if (await fs.pathExists(cfgPath)) {
|
|
160
|
-
s.start('Renaming configuration folder...');
|
|
161
|
-
const newCfgPath = path.join(bmadDir, '_config');
|
|
162
|
-
await fs.move(cfgPath, newCfgPath);
|
|
163
|
-
s.stop('Renamed "_cfg" to "_config"');
|
|
164
|
-
}
|
|
165
|
-
} catch (error) {
|
|
166
|
-
s.stop('Failed to update folder structure');
|
|
167
|
-
await prompts.log.error(`Error: ${error.message}`);
|
|
168
|
-
process.exit(1);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Check if there's an existing BMAD installation (after any folder renames)
|
|
58
|
+
// Check if there's an existing BMAD installation
|
|
173
59
|
const hasExistingInstall = await fs.pathExists(bmadDir);
|
|
174
60
|
|
|
175
61
|
let customContentConfig = { hasCustomContent: false };
|
|
@@ -184,18 +70,9 @@ class UI {
|
|
|
184
70
|
if (hasExistingInstall) {
|
|
185
71
|
// Get version information
|
|
186
72
|
const { existingInstall, bmadDir } = await this.getExistingInstallation(confirmedDirectory);
|
|
187
|
-
const packageJsonPath = path.join(__dirname, '
|
|
73
|
+
const packageJsonPath = path.join(__dirname, '../../package.json');
|
|
188
74
|
const currentVersion = require(packageJsonPath).version;
|
|
189
|
-
const installedVersion = existingInstall.version || 'unknown';
|
|
190
|
-
|
|
191
|
-
// Check if version is pre beta
|
|
192
|
-
const shouldProceed = await this.showLegacyVersionWarning(installedVersion, currentVersion, path.basename(bmadDir), options);
|
|
193
|
-
|
|
194
|
-
// If user chose to cancel, exit the installer
|
|
195
|
-
if (!shouldProceed) {
|
|
196
|
-
process.exit(0);
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
75
|
+
const installedVersion = existingInstall.installed ? existingInstall.version || 'unknown' : 'unknown';
|
|
199
76
|
|
|
200
77
|
// Build menu choices dynamically
|
|
201
78
|
const choices = [];
|
|
@@ -402,7 +279,7 @@ class UI {
|
|
|
402
279
|
customModuleResult = await this.handleCustomModulesInModifyFlow(confirmedDirectory, selectedModules);
|
|
403
280
|
} else {
|
|
404
281
|
// Preserve existing custom modules if user doesn't want to modify them
|
|
405
|
-
const { Installer } = require('
|
|
282
|
+
const { Installer } = require('./core/installer');
|
|
406
283
|
const installer = new Installer();
|
|
407
284
|
const { bmadDir } = await installer.findBmadDir(confirmedDirectory);
|
|
408
285
|
|
|
@@ -423,22 +300,24 @@ class UI {
|
|
|
423
300
|
selectedModules.push(...customModuleResult.selectedCustomModules);
|
|
424
301
|
}
|
|
425
302
|
|
|
426
|
-
//
|
|
427
|
-
|
|
303
|
+
// Ensure core is in the modules list
|
|
304
|
+
if (!selectedModules.includes('core')) {
|
|
305
|
+
selectedModules.unshift('core');
|
|
306
|
+
}
|
|
428
307
|
|
|
429
308
|
// Get tool selection
|
|
430
309
|
const toolSelection = await this.promptToolSelection(confirmedDirectory, options);
|
|
431
310
|
|
|
432
|
-
const
|
|
311
|
+
const moduleConfigs = await this.collectModuleConfigs(confirmedDirectory, selectedModules, options);
|
|
433
312
|
|
|
434
313
|
return {
|
|
435
314
|
actionType: 'update',
|
|
436
315
|
directory: confirmedDirectory,
|
|
437
|
-
installCore: true,
|
|
438
316
|
modules: selectedModules,
|
|
439
317
|
ides: toolSelection.ides,
|
|
440
318
|
skipIde: toolSelection.skipIde,
|
|
441
|
-
coreConfig:
|
|
319
|
+
coreConfig: moduleConfigs.core || {},
|
|
320
|
+
moduleConfigs: moduleConfigs,
|
|
442
321
|
customContent: customModuleResult.customContentConfig,
|
|
443
322
|
skipPrompts: options.yes || false,
|
|
444
323
|
};
|
|
@@ -543,18 +422,21 @@ class UI {
|
|
|
543
422
|
selectedModules.push(...customContentConfig.selectedModuleIds);
|
|
544
423
|
}
|
|
545
424
|
|
|
546
|
-
|
|
425
|
+
// Ensure core is in the modules list
|
|
426
|
+
if (!selectedModules.includes('core')) {
|
|
427
|
+
selectedModules.unshift('core');
|
|
428
|
+
}
|
|
547
429
|
let toolSelection = await this.promptToolSelection(confirmedDirectory, options);
|
|
548
|
-
const
|
|
430
|
+
const moduleConfigs = await this.collectModuleConfigs(confirmedDirectory, selectedModules, options);
|
|
549
431
|
|
|
550
432
|
return {
|
|
551
433
|
actionType: 'install',
|
|
552
434
|
directory: confirmedDirectory,
|
|
553
|
-
installCore: true,
|
|
554
435
|
modules: selectedModules,
|
|
555
436
|
ides: toolSelection.ides,
|
|
556
437
|
skipIde: toolSelection.skipIde,
|
|
557
|
-
coreConfig:
|
|
438
|
+
coreConfig: moduleConfigs.core || {},
|
|
439
|
+
moduleConfigs: moduleConfigs,
|
|
558
440
|
customContent: customContentConfig,
|
|
559
441
|
skipPrompts: options.yes || false,
|
|
560
442
|
};
|
|
@@ -570,18 +452,15 @@ class UI {
|
|
|
570
452
|
* @returns {Object} Tool configuration
|
|
571
453
|
*/
|
|
572
454
|
async promptToolSelection(projectDir, options = {}) {
|
|
573
|
-
|
|
574
|
-
const {
|
|
575
|
-
const { Installer } = require('../installers/lib/core/installer');
|
|
576
|
-
const detector = new Detector();
|
|
455
|
+
const { ExistingInstall } = require('./core/existing-install');
|
|
456
|
+
const { Installer } = require('./core/installer');
|
|
577
457
|
const installer = new Installer();
|
|
578
|
-
const
|
|
579
|
-
const
|
|
580
|
-
const
|
|
581
|
-
const configuredIdes = existingInstall.ides || [];
|
|
458
|
+
const { bmadDir } = await installer.findBmadDir(projectDir || process.cwd());
|
|
459
|
+
const existingInstall = await ExistingInstall.detect(bmadDir);
|
|
460
|
+
const configuredIdes = existingInstall.ides;
|
|
582
461
|
|
|
583
462
|
// Get IDE manager to fetch available IDEs dynamically
|
|
584
|
-
const { IdeManager } = require('
|
|
463
|
+
const { IdeManager } = require('./ide/manager');
|
|
585
464
|
const ideManager = new IdeManager();
|
|
586
465
|
await ideManager.ensureInitialized(); // IMPORTANT: Must initialize before getting IDEs
|
|
587
466
|
|
|
@@ -811,29 +690,29 @@ class UI {
|
|
|
811
690
|
* @returns {Object} Object with existingInstall, installedModuleIds, and bmadDir
|
|
812
691
|
*/
|
|
813
692
|
async getExistingInstallation(directory) {
|
|
814
|
-
const {
|
|
815
|
-
const { Installer } = require('
|
|
816
|
-
const detector = new Detector();
|
|
693
|
+
const { ExistingInstall } = require('./core/existing-install');
|
|
694
|
+
const { Installer } = require('./core/installer');
|
|
817
695
|
const installer = new Installer();
|
|
818
|
-
const
|
|
819
|
-
const
|
|
820
|
-
const
|
|
821
|
-
const installedModuleIds = new Set(existingInstall.modules.map((mod) => mod.id));
|
|
696
|
+
const { bmadDir } = await installer.findBmadDir(directory);
|
|
697
|
+
const existingInstall = await ExistingInstall.detect(bmadDir);
|
|
698
|
+
const installedModuleIds = new Set(existingInstall.moduleIds);
|
|
822
699
|
|
|
823
700
|
return { existingInstall, installedModuleIds, bmadDir };
|
|
824
701
|
}
|
|
825
702
|
|
|
826
703
|
/**
|
|
827
|
-
* Collect core
|
|
704
|
+
* Collect all module configurations (core + selected modules).
|
|
705
|
+
* All interactive prompting happens here in the UI layer.
|
|
828
706
|
* @param {string} directory - Installation directory
|
|
707
|
+
* @param {string[]} modules - Modules to configure (including 'core')
|
|
829
708
|
* @param {Object} options - Command-line options
|
|
830
|
-
* @returns {Object}
|
|
709
|
+
* @returns {Object} Collected module configurations keyed by module name
|
|
831
710
|
*/
|
|
832
|
-
async
|
|
833
|
-
const {
|
|
834
|
-
const configCollector = new
|
|
711
|
+
async collectModuleConfigs(directory, modules, options = {}) {
|
|
712
|
+
const { OfficialModules } = require('./modules/official-modules');
|
|
713
|
+
const configCollector = new OfficialModules();
|
|
835
714
|
|
|
836
|
-
//
|
|
715
|
+
// Seed core config from CLI options if provided
|
|
837
716
|
if (options.userName || options.communicationLanguage || options.documentOutputLanguage || options.outputFolder) {
|
|
838
717
|
const coreConfig = {};
|
|
839
718
|
if (options.userName) {
|
|
@@ -855,8 +734,6 @@ class UI {
|
|
|
855
734
|
|
|
856
735
|
// Load existing config to merge with provided options
|
|
857
736
|
await configCollector.loadExistingConfig(directory);
|
|
858
|
-
|
|
859
|
-
// Merge provided options with existing config (or defaults)
|
|
860
737
|
const existingConfig = configCollector.collectedConfig.core || {};
|
|
861
738
|
configCollector.collectedConfig.core = { ...existingConfig, ...coreConfig };
|
|
862
739
|
|
|
@@ -872,7 +749,6 @@ class UI {
|
|
|
872
749
|
await configCollector.loadExistingConfig(directory);
|
|
873
750
|
const existingConfig = configCollector.collectedConfig.core || {};
|
|
874
751
|
|
|
875
|
-
// If no existing config, use defaults
|
|
876
752
|
if (Object.keys(existingConfig).length === 0) {
|
|
877
753
|
let safeUsername;
|
|
878
754
|
try {
|
|
@@ -889,16 +765,14 @@ class UI {
|
|
|
889
765
|
};
|
|
890
766
|
await prompts.log.info('Using default configuration (--yes flag)');
|
|
891
767
|
}
|
|
892
|
-
} else {
|
|
893
|
-
// Load existing configs first if they exist
|
|
894
|
-
await configCollector.loadExistingConfig(directory);
|
|
895
|
-
// Now collect with existing values as defaults (false = don't skip loading, true = skip completion message)
|
|
896
|
-
await configCollector.collectModuleConfig('core', directory, false, true);
|
|
897
768
|
}
|
|
898
769
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
770
|
+
// Collect all module configs — core is skipped if already seeded above
|
|
771
|
+
await configCollector.collectAllConfigurations(modules, directory, {
|
|
772
|
+
skipPrompts: options.yes || false,
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
return configCollector.collectedConfig;
|
|
902
776
|
}
|
|
903
777
|
|
|
904
778
|
/**
|
|
@@ -935,9 +809,9 @@ class UI {
|
|
|
935
809
|
}
|
|
936
810
|
|
|
937
811
|
// Add official modules
|
|
938
|
-
const {
|
|
939
|
-
const
|
|
940
|
-
const { modules: availableModules, customModules: customModulesFromCache } = await
|
|
812
|
+
const { OfficialModules } = require('./modules/official-modules');
|
|
813
|
+
const officialModules = new OfficialModules();
|
|
814
|
+
const { modules: availableModules, customModules: customModulesFromCache } = await officialModules.listAvailable();
|
|
941
815
|
|
|
942
816
|
// First, add all items to appropriate sections
|
|
943
817
|
const allCustomModules = [];
|
|
@@ -992,9 +866,9 @@ class UI {
|
|
|
992
866
|
* @returns {Array} Selected module codes (excluding core)
|
|
993
867
|
*/
|
|
994
868
|
async selectAllModules(installedModuleIds = new Set()) {
|
|
995
|
-
const {
|
|
996
|
-
const
|
|
997
|
-
const { modules: localModules } = await
|
|
869
|
+
const { OfficialModules } = require('./modules/official-modules');
|
|
870
|
+
const officialModulesSource = new OfficialModules();
|
|
871
|
+
const { modules: localModules } = await officialModulesSource.listAvailable();
|
|
998
872
|
|
|
999
873
|
// Get external modules
|
|
1000
874
|
const externalManager = new ExternalModuleManager();
|
|
@@ -1069,7 +943,7 @@ class UI {
|
|
|
1069
943
|
maxItems: allOptions.length,
|
|
1070
944
|
});
|
|
1071
945
|
|
|
1072
|
-
const result = selected ? selected
|
|
946
|
+
const result = selected ? [...selected] : [];
|
|
1073
947
|
|
|
1074
948
|
// Display selected modules as bulleted list
|
|
1075
949
|
if (result.length > 0) {
|
|
@@ -1089,9 +963,9 @@ class UI {
|
|
|
1089
963
|
* @returns {Array} Default module codes
|
|
1090
964
|
*/
|
|
1091
965
|
async getDefaultModules(installedModuleIds = new Set()) {
|
|
1092
|
-
const {
|
|
1093
|
-
const
|
|
1094
|
-
const { modules: localModules } = await
|
|
966
|
+
const { OfficialModules } = require('./modules/official-modules');
|
|
967
|
+
const officialModules = new OfficialModules();
|
|
968
|
+
const { modules: localModules } = await officialModules.listAvailable();
|
|
1095
969
|
|
|
1096
970
|
const defaultModules = [];
|
|
1097
971
|
|
|
@@ -1149,7 +1023,7 @@ class UI {
|
|
|
1149
1023
|
const files = await fs.readdir(directory);
|
|
1150
1024
|
if (files.length > 0) {
|
|
1151
1025
|
// Check for any bmad installation (any folder with _config/manifest.yaml)
|
|
1152
|
-
const { Installer } = require('
|
|
1026
|
+
const { Installer } = require('./core/installer');
|
|
1153
1027
|
const installer = new Installer();
|
|
1154
1028
|
const bmadResult = await installer.findBmadDir(directory);
|
|
1155
1029
|
const hasBmadInstall =
|
|
@@ -1385,50 +1259,18 @@ class UI {
|
|
|
1385
1259
|
return path.resolve(expanded);
|
|
1386
1260
|
}
|
|
1387
1261
|
|
|
1388
|
-
/**
|
|
1389
|
-
* Load existing configurations to use as defaults
|
|
1390
|
-
* @param {string} directory - Installation directory
|
|
1391
|
-
* @returns {Object} Existing configurations
|
|
1392
|
-
*/
|
|
1393
|
-
async loadExistingConfigurations(directory) {
|
|
1394
|
-
const configs = {
|
|
1395
|
-
hasCustomContent: false,
|
|
1396
|
-
coreConfig: {},
|
|
1397
|
-
ideConfig: { ides: [], skipIde: false },
|
|
1398
|
-
};
|
|
1399
|
-
|
|
1400
|
-
try {
|
|
1401
|
-
// Load core config
|
|
1402
|
-
configs.coreConfig = await this.collectCoreConfig(directory);
|
|
1403
|
-
|
|
1404
|
-
// Load IDE configuration
|
|
1405
|
-
const configuredIdes = await this.getConfiguredIdes(directory);
|
|
1406
|
-
if (configuredIdes.length > 0) {
|
|
1407
|
-
configs.ideConfig.ides = configuredIdes;
|
|
1408
|
-
configs.ideConfig.skipIde = false;
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
return configs;
|
|
1412
|
-
} catch {
|
|
1413
|
-
// If loading fails, return empty configs
|
|
1414
|
-
await prompts.log.warn('Could not load existing configurations');
|
|
1415
|
-
return configs;
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
1262
|
/**
|
|
1420
1263
|
* Get configured IDEs from existing installation
|
|
1421
1264
|
* @param {string} directory - Installation directory
|
|
1422
1265
|
* @returns {Array} List of configured IDEs
|
|
1423
1266
|
*/
|
|
1424
1267
|
async getConfiguredIdes(directory) {
|
|
1425
|
-
const {
|
|
1426
|
-
const { Installer } = require('
|
|
1427
|
-
const detector = new Detector();
|
|
1268
|
+
const { ExistingInstall } = require('./core/existing-install');
|
|
1269
|
+
const { Installer } = require('./core/installer');
|
|
1428
1270
|
const installer = new Installer();
|
|
1429
|
-
const
|
|
1430
|
-
const existingInstall = await
|
|
1431
|
-
return existingInstall.ides
|
|
1271
|
+
const { bmadDir } = await installer.findBmadDir(directory);
|
|
1272
|
+
const existingInstall = await ExistingInstall.detect(bmadDir);
|
|
1273
|
+
return existingInstall.ides;
|
|
1432
1274
|
}
|
|
1433
1275
|
|
|
1434
1276
|
/**
|
|
@@ -1573,7 +1415,7 @@ class UI {
|
|
|
1573
1415
|
const { existingInstall } = await this.getExistingInstallation(directory);
|
|
1574
1416
|
|
|
1575
1417
|
// Check if there are any custom modules in cache
|
|
1576
|
-
const { Installer } = require('
|
|
1418
|
+
const { Installer } = require('./core/installer');
|
|
1577
1419
|
const installer = new Installer();
|
|
1578
1420
|
const { bmadDir } = await installer.findBmadDir(directory);
|
|
1579
1421
|
|
|
@@ -1707,82 +1549,6 @@ class UI {
|
|
|
1707
1549
|
return result;
|
|
1708
1550
|
}
|
|
1709
1551
|
|
|
1710
|
-
/**
|
|
1711
|
-
* Check if installed version is a legacy version that needs fresh install
|
|
1712
|
-
* @param {string} installedVersion - The installed version
|
|
1713
|
-
* @returns {boolean} True if legacy (v4 or any alpha)
|
|
1714
|
-
*/
|
|
1715
|
-
isLegacyVersion(installedVersion) {
|
|
1716
|
-
if (!installedVersion || installedVersion === 'unknown') {
|
|
1717
|
-
return true; // Treat unknown as legacy for safety
|
|
1718
|
-
}
|
|
1719
|
-
// Check if version string contains -alpha or -Alpha (any v6 alpha)
|
|
1720
|
-
return /-alpha\./i.test(installedVersion);
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
|
-
/**
|
|
1724
|
-
* Show warning for legacy version (v4 or alpha) and ask if user wants to proceed
|
|
1725
|
-
* @param {string} installedVersion - The installed version
|
|
1726
|
-
* @param {string} currentVersion - The current version
|
|
1727
|
-
* @param {string} bmadFolderName - Name of the BMAD folder
|
|
1728
|
-
* @returns {Promise<boolean>} True if user wants to proceed, false if they cancel
|
|
1729
|
-
*/
|
|
1730
|
-
async showLegacyVersionWarning(installedVersion, currentVersion, bmadFolderName, options = {}) {
|
|
1731
|
-
if (!this.isLegacyVersion(installedVersion)) {
|
|
1732
|
-
return true; // Not legacy, proceed
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
|
-
let warningContent;
|
|
1736
|
-
if (installedVersion === 'unknown') {
|
|
1737
|
-
warningContent = 'Unable to detect your installed BMAD version.\n' + 'This appears to be a legacy or unsupported installation.';
|
|
1738
|
-
} else {
|
|
1739
|
-
warningContent =
|
|
1740
|
-
`You are updating from ${installedVersion} to ${currentVersion}.\n` + 'You have a legacy version installed (v4 or alpha).';
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
warningContent +=
|
|
1744
|
-
'\n\nFor the best experience, we recommend:\n' +
|
|
1745
|
-
' 1. Delete your current BMAD installation folder\n' +
|
|
1746
|
-
` (the "${bmadFolderName}/" folder in your project)\n` +
|
|
1747
|
-
' 2. Run a fresh installation\n\n' +
|
|
1748
|
-
'Benefits of a fresh install:\n' +
|
|
1749
|
-
' \u2022 Cleaner configuration without legacy artifacts\n' +
|
|
1750
|
-
' \u2022 All new features properly configured\n' +
|
|
1751
|
-
' \u2022 Fewer potential conflicts';
|
|
1752
|
-
|
|
1753
|
-
await prompts.log.warn('VERSION WARNING');
|
|
1754
|
-
await prompts.note(warningContent, 'Version Warning');
|
|
1755
|
-
|
|
1756
|
-
if (options.yes) {
|
|
1757
|
-
await prompts.log.warn('Non-interactive mode (--yes): auto-proceeding with legacy update');
|
|
1758
|
-
return true;
|
|
1759
|
-
}
|
|
1760
|
-
|
|
1761
|
-
const proceed = await prompts.select({
|
|
1762
|
-
message: 'How would you like to proceed?',
|
|
1763
|
-
choices: [
|
|
1764
|
-
{
|
|
1765
|
-
name: 'Proceed with update anyway (may have issues)',
|
|
1766
|
-
value: 'proceed',
|
|
1767
|
-
},
|
|
1768
|
-
{
|
|
1769
|
-
name: 'Cancel (recommended - do a fresh install instead)',
|
|
1770
|
-
value: 'cancel',
|
|
1771
|
-
},
|
|
1772
|
-
],
|
|
1773
|
-
default: 'cancel',
|
|
1774
|
-
});
|
|
1775
|
-
|
|
1776
|
-
if (proceed === 'cancel') {
|
|
1777
|
-
await prompts.note(
|
|
1778
|
-
`1. Delete the "${bmadFolderName}/" folder in your project\n` + "2. Run 'bmad install' again",
|
|
1779
|
-
'To do a fresh install',
|
|
1780
|
-
);
|
|
1781
|
-
}
|
|
1782
|
-
|
|
1783
|
-
return proceed === 'proceed';
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
1552
|
/**
|
|
1787
1553
|
* Display module versions with update availability
|
|
1788
1554
|
* @param {Array} modules - Array of module info objects with version info
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* BMad Method CLI - Direct execution wrapper for npx
|
|
5
|
-
* This file ensures proper execution when run via npx from GitHub or npm registry
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { execFileSync } = require('node:child_process');
|
|
9
|
-
const path = require('node:path');
|
|
10
|
-
const fs = require('node:fs');
|
|
11
|
-
|
|
12
|
-
// Check if we're running in an npx temporary directory
|
|
13
|
-
const isNpxExecution = __dirname.includes('_npx') || __dirname.includes('.npm');
|
|
14
|
-
|
|
15
|
-
if (isNpxExecution) {
|
|
16
|
-
// Running via npx - spawn child process to preserve user's working directory
|
|
17
|
-
const args = process.argv.slice(2);
|
|
18
|
-
const bmadCliPath = path.join(__dirname, 'cli', 'bmad-cli.js');
|
|
19
|
-
|
|
20
|
-
if (!fs.existsSync(bmadCliPath)) {
|
|
21
|
-
console.error('Error: Could not find bmad-cli.js at', bmadCliPath);
|
|
22
|
-
console.error('Current directory:', __dirname);
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
// Execute CLI from user's working directory (process.cwd()), not npm cache
|
|
28
|
-
execFileSync('node', [bmadCliPath, ...args], {
|
|
29
|
-
stdio: 'inherit',
|
|
30
|
-
cwd: process.cwd(), // This preserves the user's working directory
|
|
31
|
-
});
|
|
32
|
-
} catch (error) {
|
|
33
|
-
process.exit(error.status || 1);
|
|
34
|
-
}
|
|
35
|
-
} else {
|
|
36
|
-
// Local execution - use require
|
|
37
|
-
require('./cli/bmad-cli.js');
|
|
38
|
-
}
|