bmad-method 6.3.1-next.8 → 6.4.0
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/package.json +3 -2
- package/src/bmm-skills/1-analysis/bmad-agent-analyst/SKILL.md +51 -36
- package/src/bmm-skills/1-analysis/bmad-agent-analyst/customize.toml +90 -0
- package/src/bmm-skills/1-analysis/bmad-agent-tech-writer/SKILL.md +50 -33
- package/src/bmm-skills/1-analysis/bmad-agent-tech-writer/customize.toml +81 -0
- package/src/bmm-skills/1-analysis/bmad-document-project/SKILL.md +57 -1
- package/src/bmm-skills/1-analysis/bmad-document-project/customize.toml +41 -0
- package/src/bmm-skills/1-analysis/bmad-document-project/workflows/deep-dive-instructions.md +1 -0
- package/src/bmm-skills/1-analysis/bmad-document-project/workflows/full-scan-instructions.md +1 -0
- package/src/bmm-skills/1-analysis/bmad-prfaq/SKILL.md +48 -9
- package/src/bmm-skills/1-analysis/bmad-prfaq/customize.toml +41 -0
- package/src/bmm-skills/1-analysis/bmad-prfaq/references/verdict.md +4 -0
- package/src/bmm-skills/1-analysis/bmad-product-brief/SKILL.md +44 -9
- package/src/bmm-skills/1-analysis/bmad-product-brief/customize.toml +47 -0
- package/src/bmm-skills/1-analysis/bmad-product-brief/prompts/contextual-discovery.md +8 -7
- package/src/bmm-skills/1-analysis/bmad-product-brief/prompts/draft-and-review.md +6 -5
- package/src/bmm-skills/1-analysis/bmad-product-brief/prompts/finalize.md +4 -1
- package/src/bmm-skills/1-analysis/bmad-product-brief/prompts/guided-elicitation.md +3 -2
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/SKILL.md +91 -1
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/customize.toml +41 -0
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/domain-steps/step-06-research-synthesis.md +6 -0
- package/src/bmm-skills/1-analysis/research/bmad-market-research/SKILL.md +91 -1
- package/src/bmm-skills/1-analysis/research/bmad-market-research/customize.toml +41 -0
- package/src/bmm-skills/1-analysis/research/bmad-market-research/steps/step-06-research-completion.md +6 -0
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/SKILL.md +91 -1
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/customize.toml +41 -0
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/technical-steps/step-06-research-synthesis.md +6 -0
- package/src/bmm-skills/2-plan-workflows/bmad-agent-pm/SKILL.md +50 -35
- package/src/bmm-skills/2-plan-workflows/bmad-agent-pm/customize.toml +85 -0
- package/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/SKILL.md +50 -31
- package/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/customize.toml +60 -0
- package/src/bmm-skills/2-plan-workflows/bmad-create-prd/SKILL.md +99 -1
- package/src/bmm-skills/2-plan-workflows/bmad-create-prd/customize.toml +41 -0
- package/src/bmm-skills/2-plan-workflows/bmad-create-prd/steps-c/step-12-complete.md +6 -0
- package/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/SKILL.md +70 -1
- package/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/customize.toml +41 -0
- package/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/steps/step-14-complete.md +6 -0
- package/src/bmm-skills/2-plan-workflows/bmad-edit-prd/SKILL.md +97 -1
- package/src/bmm-skills/2-plan-workflows/bmad-edit-prd/customize.toml +42 -0
- package/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-04-complete.md +2 -0
- package/src/bmm-skills/2-plan-workflows/bmad-validate-prd/SKILL.md +99 -1
- package/src/bmm-skills/2-plan-workflows/bmad-validate-prd/customize.toml +42 -0
- package/src/bmm-skills/2-plan-workflows/bmad-validate-prd/steps-v/step-v-13-report-complete.md +1 -0
- package/src/bmm-skills/3-solutioning/bmad-agent-architect/SKILL.md +50 -30
- package/src/bmm-skills/3-solutioning/bmad-agent-architect/customize.toml +65 -0
- package/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/SKILL.md +86 -1
- package/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/customize.toml +41 -0
- package/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-06-final-assessment.md +6 -0
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/SKILL.md +69 -1
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/customize.toml +41 -0
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-08-complete.md +6 -0
- package/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/SKILL.md +88 -1
- package/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/customize.toml +41 -0
- package/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/steps/step-04-final-validation.md +6 -0
- package/src/bmm-skills/3-solutioning/bmad-generate-project-context/SKILL.md +76 -1
- package/src/bmm-skills/3-solutioning/bmad-generate-project-context/customize.toml +41 -0
- package/src/bmm-skills/3-solutioning/bmad-generate-project-context/steps/step-03-complete.md +6 -0
- package/src/bmm-skills/4-implementation/bmad-agent-dev/SKILL.md +48 -43
- package/src/bmm-skills/4-implementation/bmad-agent-dev/customize.toml +90 -0
- package/src/bmm-skills/4-implementation/bmad-checkpoint-preview/SKILL.md +46 -7
- package/src/bmm-skills/4-implementation/bmad-checkpoint-preview/customize.toml +41 -0
- package/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-05-wrapup.md +6 -0
- package/src/bmm-skills/4-implementation/bmad-code-review/SKILL.md +85 -1
- package/src/bmm-skills/4-implementation/bmad-code-review/customize.toml +41 -0
- package/src/bmm-skills/4-implementation/bmad-code-review/steps/step-04-present.md +6 -0
- package/src/bmm-skills/4-implementation/bmad-correct-course/SKILL.md +296 -1
- package/src/bmm-skills/4-implementation/bmad-correct-course/customize.toml +41 -0
- package/src/bmm-skills/4-implementation/bmad-create-story/SKILL.md +424 -1
- package/src/bmm-skills/4-implementation/bmad-create-story/customize.toml +41 -0
- package/src/bmm-skills/4-implementation/bmad-dev-story/SKILL.md +480 -1
- package/src/bmm-skills/4-implementation/bmad-dev-story/customize.toml +41 -0
- package/src/bmm-skills/4-implementation/bmad-qa-generate-e2e-tests/SKILL.md +171 -1
- package/src/bmm-skills/4-implementation/bmad-qa-generate-e2e-tests/customize.toml +41 -0
- package/src/bmm-skills/4-implementation/bmad-quick-dev/SKILL.md +106 -1
- package/src/bmm-skills/4-implementation/bmad-quick-dev/customize.toml +41 -0
- package/src/bmm-skills/4-implementation/bmad-quick-dev/step-05-present.md +6 -0
- package/src/bmm-skills/4-implementation/bmad-quick-dev/step-oneshot.md +6 -0
- package/src/bmm-skills/4-implementation/bmad-retrospective/SKILL.md +1507 -1
- package/src/bmm-skills/4-implementation/bmad-retrospective/customize.toml +41 -0
- package/src/bmm-skills/4-implementation/bmad-sprint-planning/SKILL.md +294 -1
- package/src/bmm-skills/4-implementation/bmad-sprint-planning/customize.toml +41 -0
- package/src/bmm-skills/4-implementation/bmad-sprint-status/SKILL.md +292 -1
- package/src/bmm-skills/4-implementation/bmad-sprint-status/customize.toml +41 -0
- package/src/bmm-skills/module.yaml +49 -0
- package/src/core-skills/bmad-advanced-elicitation/SKILL.md +7 -1
- package/src/core-skills/bmad-customize/SKILL.md +111 -0
- package/src/core-skills/bmad-customize/scripts/list_customizable_skills.py +231 -0
- package/src/core-skills/bmad-customize/scripts/tests/test_list_customizable_skills.py +249 -0
- package/src/core-skills/bmad-distillator/resources/distillate-format-reference.md +1 -1
- package/src/core-skills/bmad-party-mode/SKILL.md +13 -10
- package/src/core-skills/module-help.csv +1 -0
- package/src/core-skills/module.yaml +2 -0
- package/src/scripts/resolve_config.py +176 -0
- package/src/scripts/resolve_customization.py +230 -0
- package/tools/installer/commands/install.js +13 -0
- package/tools/installer/core/config.js +4 -1
- package/tools/installer/core/install-paths.js +11 -5
- package/tools/installer/core/installer.js +181 -94
- package/tools/installer/core/manifest-generator.js +339 -184
- package/tools/installer/core/manifest.js +86 -86
- package/tools/installer/fs-native.js +5 -0
- package/tools/installer/ide/platform-codes.yaml +6 -0
- package/tools/installer/modules/channel-plan.js +203 -0
- package/tools/installer/modules/channel-resolver.js +241 -0
- package/tools/installer/modules/community-manager.js +130 -23
- package/tools/installer/modules/custom-module-manager.js +160 -19
- package/tools/installer/modules/external-manager.js +235 -32
- package/tools/installer/modules/official-modules.js +58 -12
- package/tools/installer/modules/registry-client.js +139 -7
- package/tools/installer/modules/registry-fallback.yaml +8 -0
- package/tools/installer/modules/version-resolver.js +336 -0
- package/tools/installer/project-root.js +54 -0
- package/tools/installer/ui.js +561 -50
- package/tools/platform-codes.yaml +6 -0
- package/src/bmm-skills/1-analysis/bmad-agent-analyst/bmad-skill-manifest.yaml +0 -11
- package/src/bmm-skills/1-analysis/bmad-agent-tech-writer/bmad-skill-manifest.yaml +0 -11
- package/src/bmm-skills/1-analysis/bmad-document-project/workflow.md +0 -25
- package/src/bmm-skills/1-analysis/research/bmad-domain-research/workflow.md +0 -51
- package/src/bmm-skills/1-analysis/research/bmad-market-research/workflow.md +0 -51
- package/src/bmm-skills/1-analysis/research/bmad-technical-research/workflow.md +0 -52
- package/src/bmm-skills/2-plan-workflows/bmad-agent-pm/bmad-skill-manifest.yaml +0 -11
- package/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/bmad-skill-manifest.yaml +0 -11
- package/src/bmm-skills/2-plan-workflows/bmad-create-prd/workflow.md +0 -61
- package/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/workflow.md +0 -35
- package/src/bmm-skills/2-plan-workflows/bmad-edit-prd/workflow.md +0 -62
- package/src/bmm-skills/2-plan-workflows/bmad-validate-prd/workflow.md +0 -61
- package/src/bmm-skills/3-solutioning/bmad-agent-architect/bmad-skill-manifest.yaml +0 -11
- package/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/workflow.md +0 -47
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/workflow.md +0 -32
- package/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/workflow.md +0 -51
- package/src/bmm-skills/3-solutioning/bmad-generate-project-context/workflow.md +0 -39
- package/src/bmm-skills/4-implementation/bmad-agent-dev/bmad-skill-manifest.yaml +0 -11
- package/src/bmm-skills/4-implementation/bmad-code-review/workflow.md +0 -55
- package/src/bmm-skills/4-implementation/bmad-correct-course/workflow.md +0 -267
- package/src/bmm-skills/4-implementation/bmad-create-story/workflow.md +0 -380
- package/src/bmm-skills/4-implementation/bmad-dev-story/workflow.md +0 -450
- package/src/bmm-skills/4-implementation/bmad-qa-generate-e2e-tests/workflow.md +0 -136
- package/src/bmm-skills/4-implementation/bmad-quick-dev/workflow.md +0 -76
- package/src/bmm-skills/4-implementation/bmad-retrospective/workflow.md +0 -1479
- package/src/bmm-skills/4-implementation/bmad-sprint-planning/workflow.md +0 -263
- package/src/bmm-skills/4-implementation/bmad-sprint-status/workflow.md +0 -261
|
@@ -11,6 +11,7 @@ const prompts = require('../prompts');
|
|
|
11
11
|
const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils');
|
|
12
12
|
const { InstallPaths } = require('./install-paths');
|
|
13
13
|
const { ExternalModuleManager } = require('../modules/external-manager');
|
|
14
|
+
const { resolveModuleVersion } = require('../modules/version-resolver');
|
|
14
15
|
|
|
15
16
|
const { ExistingInstall } = require('./existing-install');
|
|
16
17
|
|
|
@@ -24,44 +25,6 @@ class Installer {
|
|
|
24
25
|
this.bmadFolderName = BMAD_FOLDER_NAME;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
/**
|
|
28
|
-
* Read the module version from .claude-plugin/marketplace.json
|
|
29
|
-
* Walks up from sourcePath looking for .claude-plugin/marketplace.json
|
|
30
|
-
* @param {string} sourcePath - Module source directory
|
|
31
|
-
* @returns {string} Version string or empty string
|
|
32
|
-
*/
|
|
33
|
-
async _getMarketplaceVersion(sourcePath) {
|
|
34
|
-
let dir = sourcePath;
|
|
35
|
-
for (let i = 0; i < 5; i++) {
|
|
36
|
-
const marketplacePath = path.join(dir, '.claude-plugin', 'marketplace.json');
|
|
37
|
-
if (await fs.pathExists(marketplacePath)) {
|
|
38
|
-
try {
|
|
39
|
-
const data = JSON.parse(await fs.readFile(marketplacePath, 'utf8'));
|
|
40
|
-
return this._extractMarketplaceVersion(data);
|
|
41
|
-
} catch {
|
|
42
|
-
return '';
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
const parent = path.dirname(dir);
|
|
46
|
-
if (parent === dir) break;
|
|
47
|
-
dir = parent;
|
|
48
|
-
}
|
|
49
|
-
return '';
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Extract the highest version from marketplace.json plugins array
|
|
54
|
-
*/
|
|
55
|
-
_extractMarketplaceVersion(data) {
|
|
56
|
-
const plugins = data?.plugins;
|
|
57
|
-
if (!Array.isArray(plugins) || plugins.length === 0) return '';
|
|
58
|
-
let best = '';
|
|
59
|
-
for (const p of plugins) {
|
|
60
|
-
if (p.version && (!best || p.version > best)) best = p.version;
|
|
61
|
-
}
|
|
62
|
-
return best;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
28
|
/**
|
|
66
29
|
* Main installation method
|
|
67
30
|
* @param {Object} config - Installation configuration
|
|
@@ -244,6 +207,15 @@ class Installer {
|
|
|
244
207
|
|
|
245
208
|
const installTasks = [];
|
|
246
209
|
|
|
210
|
+
installTasks.push({
|
|
211
|
+
title: 'Installing shared scripts',
|
|
212
|
+
task: async () => {
|
|
213
|
+
await this._installSharedScripts(paths);
|
|
214
|
+
addResult('Shared scripts', 'ok');
|
|
215
|
+
return 'Shared scripts installed';
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
|
|
247
219
|
if (allModules.length > 0) {
|
|
248
220
|
installTasks.push({
|
|
249
221
|
title: isQuickUpdate ? `Updating ${allModules.length} module(s)` : `Installing ${allModules.length} module(s)`,
|
|
@@ -301,7 +273,8 @@ class Installer {
|
|
|
301
273
|
addResult('Configurations', 'ok', 'generated');
|
|
302
274
|
|
|
303
275
|
this.installedFiles.add(paths.manifestFile());
|
|
304
|
-
this.installedFiles.add(paths.
|
|
276
|
+
this.installedFiles.add(paths.centralConfig());
|
|
277
|
+
this.installedFiles.add(paths.centralUserConfig());
|
|
305
278
|
|
|
306
279
|
message('Generating manifests...');
|
|
307
280
|
const manifestGen = new ManifestGenerator();
|
|
@@ -322,10 +295,11 @@ class Installer {
|
|
|
322
295
|
await manifestGen.generateManifests(paths.bmadDir, allModulesForManifest, [...this.installedFiles], {
|
|
323
296
|
ides: config.ides || [],
|
|
324
297
|
preservedModules: modulesForCsvPreserve,
|
|
298
|
+
moduleConfigs,
|
|
325
299
|
});
|
|
326
300
|
|
|
327
301
|
message('Generating help catalog...');
|
|
328
|
-
await this.mergeModuleHelpCatalogs(paths.bmadDir);
|
|
302
|
+
await this.mergeModuleHelpCatalogs(paths.bmadDir, manifestGen.agents);
|
|
329
303
|
addResult('Help catalog', 'ok');
|
|
330
304
|
|
|
331
305
|
return 'Configurations generated';
|
|
@@ -558,6 +532,44 @@ class Installer {
|
|
|
558
532
|
return { tempBackupDir, tempModifiedBackupDir };
|
|
559
533
|
}
|
|
560
534
|
|
|
535
|
+
/**
|
|
536
|
+
* Sync src/scripts/* → _bmad/scripts/ so shared Python scripts
|
|
537
|
+
* (e.g. resolve_customization.py) are available at install time.
|
|
538
|
+
* Wipes the destination first so files removed or renamed in source
|
|
539
|
+
* don't linger and get recorded as installed. Also seeds
|
|
540
|
+
* _bmad/custom/.gitignore on fresh installs so *.user.toml overrides
|
|
541
|
+
* stay out of version control.
|
|
542
|
+
*/
|
|
543
|
+
async _installSharedScripts(paths) {
|
|
544
|
+
const srcScriptsDir = path.join(paths.srcDir, 'src', 'scripts');
|
|
545
|
+
if (!(await fs.pathExists(srcScriptsDir))) {
|
|
546
|
+
throw new Error(`Shared scripts source directory not found: ${srcScriptsDir}`);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
await fs.remove(paths.scriptsDir);
|
|
550
|
+
await fs.ensureDir(paths.scriptsDir);
|
|
551
|
+
await fs.copy(srcScriptsDir, paths.scriptsDir, { overwrite: true });
|
|
552
|
+
await this._trackFilesRecursive(paths.scriptsDir);
|
|
553
|
+
|
|
554
|
+
const customGitignore = path.join(paths.customDir, '.gitignore');
|
|
555
|
+
if (!(await fs.pathExists(customGitignore))) {
|
|
556
|
+
await fs.writeFile(customGitignore, '*.user.toml\n', 'utf8');
|
|
557
|
+
this.installedFiles.add(customGitignore);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
async _trackFilesRecursive(dir) {
|
|
562
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
563
|
+
for (const entry of entries) {
|
|
564
|
+
const full = path.join(dir, entry.name);
|
|
565
|
+
if (entry.isDirectory()) {
|
|
566
|
+
await this._trackFilesRecursive(full);
|
|
567
|
+
} else if (entry.isFile()) {
|
|
568
|
+
this.installedFiles.add(full);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
561
573
|
/**
|
|
562
574
|
* Install official (non-custom) modules.
|
|
563
575
|
* @param {Object} config - Installation configuration
|
|
@@ -589,19 +601,40 @@ class Installer {
|
|
|
589
601
|
moduleConfig: moduleConfig,
|
|
590
602
|
installer: this,
|
|
591
603
|
silent: true,
|
|
604
|
+
channelOptions: config.channelOptions,
|
|
592
605
|
},
|
|
593
606
|
);
|
|
594
607
|
|
|
595
|
-
// Get display name from source module.yaml
|
|
596
|
-
const sourcePath = await officialModules.findModuleSource(moduleName, {
|
|
608
|
+
// Get display name from source module.yaml and resolve the freshest version metadata we can find locally.
|
|
609
|
+
const sourcePath = await officialModules.findModuleSource(moduleName, {
|
|
610
|
+
silent: true,
|
|
611
|
+
channelOptions: config.channelOptions,
|
|
612
|
+
});
|
|
597
613
|
const moduleInfo = sourcePath ? await officialModules.getModuleInfo(sourcePath, moduleName, '') : null;
|
|
598
614
|
const displayName = moduleInfo?.name || moduleName;
|
|
599
615
|
|
|
600
|
-
|
|
601
|
-
|
|
616
|
+
const externalResolution = officialModules.externalModuleManager.getResolution(moduleName);
|
|
617
|
+
let communityResolution = null;
|
|
618
|
+
if (!externalResolution) {
|
|
619
|
+
const { CommunityModuleManager } = require('../modules/community-manager');
|
|
620
|
+
communityResolution = new CommunityModuleManager().getResolution(moduleName);
|
|
621
|
+
}
|
|
622
|
+
const resolution = externalResolution || communityResolution;
|
|
602
623
|
const cachedResolution = CustomModuleManager._resolutionCache.get(moduleName);
|
|
603
|
-
const
|
|
604
|
-
|
|
624
|
+
const versionInfo = await resolveModuleVersion(moduleName, {
|
|
625
|
+
moduleSourcePath: sourcePath,
|
|
626
|
+
fallbackVersion: resolution?.version || cachedResolution?.version,
|
|
627
|
+
marketplacePluginNames: cachedResolution?.pluginName ? [cachedResolution.pluginName] : [],
|
|
628
|
+
});
|
|
629
|
+
// Prefer the git tag recorded by the resolution (e.g. "v1.7.0") over
|
|
630
|
+
// the on-disk package.json (which may be ahead of the released tag).
|
|
631
|
+
const version = resolution?.version || versionInfo.version || '';
|
|
632
|
+
addResult(displayName, 'ok', '', {
|
|
633
|
+
moduleCode: moduleName,
|
|
634
|
+
newVersion: version,
|
|
635
|
+
newChannel: resolution?.channel || null,
|
|
636
|
+
newSha: resolution?.sha || null,
|
|
637
|
+
});
|
|
605
638
|
}
|
|
606
639
|
}
|
|
607
640
|
|
|
@@ -671,8 +704,11 @@ class Installer {
|
|
|
671
704
|
const customFiles = [];
|
|
672
705
|
const modifiedFiles = [];
|
|
673
706
|
|
|
674
|
-
// Memory
|
|
675
|
-
|
|
707
|
+
// Memory subtrees (v6.1: _bmad/_memory, current: _bmad/memory) hold
|
|
708
|
+
// per-user runtime data generated by agents with sidecars. These files
|
|
709
|
+
// aren't installer-managed and must never be reported as "custom" or
|
|
710
|
+
// "modified" — they're user state, not user overrides.
|
|
711
|
+
const bmadMemoryPaths = ['_memory', 'memory'];
|
|
676
712
|
|
|
677
713
|
// Check if the manifest has hashes - if not, we can't detect modifications
|
|
678
714
|
let manifestHasHashes = false;
|
|
@@ -738,7 +774,7 @@ class Installer {
|
|
|
738
774
|
continue;
|
|
739
775
|
}
|
|
740
776
|
|
|
741
|
-
if (relativePath.startsWith(
|
|
777
|
+
if (bmadMemoryPaths.some((mp) => relativePath === mp || relativePath.startsWith(mp + '/'))) {
|
|
742
778
|
continue;
|
|
743
779
|
}
|
|
744
780
|
|
|
@@ -789,9 +825,8 @@ class Installer {
|
|
|
789
825
|
|
|
790
826
|
// Get all installed module directories
|
|
791
827
|
const entries = await fs.readdir(bmadDir, { withFileTypes: true });
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
.map((entry) => entry.name);
|
|
828
|
+
const nonModuleDirs = new Set(['_config', '_memory', 'memory', 'docs', 'scripts', 'custom']);
|
|
829
|
+
const installedModules = entries.filter((entry) => entry.isDirectory() && !nonModuleDirs.has(entry.name)).map((entry) => entry.name);
|
|
795
830
|
|
|
796
831
|
// Generate config.yaml for each installed module
|
|
797
832
|
for (const moduleName of installedModules) {
|
|
@@ -873,53 +908,36 @@ class Installer {
|
|
|
873
908
|
}
|
|
874
909
|
|
|
875
910
|
/**
|
|
876
|
-
* Merge all module-help.csv files into a single bmad-help.csv
|
|
877
|
-
* Scans all installed modules for module-help.csv and merges them
|
|
878
|
-
* Enriches agent info from agent
|
|
879
|
-
* Output is written to _bmad/_config/bmad-help.csv
|
|
911
|
+
* Merge all module-help.csv files into a single bmad-help.csv.
|
|
912
|
+
* Scans all installed modules for module-help.csv and merges them.
|
|
913
|
+
* Enriches agent info from the in-memory agent list produced by ManifestGenerator.
|
|
914
|
+
* Output is written to _bmad/_config/bmad-help.csv.
|
|
880
915
|
* @param {string} bmadDir - BMAD installation directory
|
|
916
|
+
* @param {Array<Object>} agentEntries - Agents collected from module.yaml (code, name, title, icon, module, ...)
|
|
881
917
|
*/
|
|
882
|
-
async mergeModuleHelpCatalogs(bmadDir) {
|
|
918
|
+
async mergeModuleHelpCatalogs(bmadDir, agentEntries = []) {
|
|
883
919
|
const allRows = [];
|
|
884
920
|
const headerRow =
|
|
885
921
|
'module,phase,name,code,sequence,workflow-file,command,required,agent-name,agent-command,agent-display-name,agent-title,options,description,output-location,outputs';
|
|
886
922
|
|
|
887
|
-
//
|
|
888
|
-
const
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
const
|
|
893
|
-
const
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
if (cols.length >= 4) {
|
|
900
|
-
const agentName = cols[0].replaceAll('"', '').trim();
|
|
901
|
-
const displayName = cols[1].replaceAll('"', '').trim();
|
|
902
|
-
const title = cols[2].replaceAll('"', '').trim();
|
|
903
|
-
const icon = cols[3].replaceAll('"', '').trim();
|
|
904
|
-
const module = cols[10] ? cols[10].replaceAll('"', '').trim() : '';
|
|
905
|
-
|
|
906
|
-
// Build agent command: bmad:module:agent:name
|
|
907
|
-
const agentCommand = module ? `bmad:${module}:agent:${agentName}` : `bmad:agent:${agentName}`;
|
|
908
|
-
|
|
909
|
-
agentInfo.set(agentName, {
|
|
910
|
-
command: agentCommand,
|
|
911
|
-
displayName: displayName || agentName,
|
|
912
|
-
title: icon && title ? `${icon} ${title}` : title || agentName,
|
|
913
|
-
});
|
|
914
|
-
}
|
|
915
|
-
}
|
|
923
|
+
// Build agent lookup from the in-memory list (agent code → command + display fields).
|
|
924
|
+
const agentInfo = new Map();
|
|
925
|
+
for (const agent of agentEntries) {
|
|
926
|
+
if (!agent || !agent.code) continue;
|
|
927
|
+
const agentCommand = agent.module ? `bmad:${agent.module}:agent:${agent.code}` : `bmad:agent:${agent.code}`;
|
|
928
|
+
const displayName = agent.name || agent.code;
|
|
929
|
+
const titleCombined = agent.icon && agent.title ? `${agent.icon} ${agent.title}` : agent.title || agent.code;
|
|
930
|
+
agentInfo.set(agent.code, {
|
|
931
|
+
command: agentCommand,
|
|
932
|
+
displayName,
|
|
933
|
+
title: titleCombined,
|
|
934
|
+
});
|
|
916
935
|
}
|
|
917
936
|
|
|
918
937
|
// Get all installed module directories
|
|
919
938
|
const entries = await fs.readdir(bmadDir, { withFileTypes: true });
|
|
920
|
-
const
|
|
921
|
-
|
|
922
|
-
.map((entry) => entry.name);
|
|
939
|
+
const nonModuleDirs = new Set(['_config', '_memory', 'memory', 'docs', 'scripts', 'custom']);
|
|
940
|
+
const installedModules = entries.filter((entry) => entry.isDirectory() && !nonModuleDirs.has(entry.name)).map((entry) => entry.name);
|
|
923
941
|
|
|
924
942
|
// Add core module to scan (it's installed at root level as _config, but we check src/core-skills)
|
|
925
943
|
const coreModulePath = getSourcePath('core-skills');
|
|
@@ -1091,12 +1109,30 @@ class Installer {
|
|
|
1091
1109
|
let detail = '';
|
|
1092
1110
|
if (r.moduleCode && r.newVersion) {
|
|
1093
1111
|
const oldVersion = preVersions.get(r.moduleCode);
|
|
1094
|
-
|
|
1095
|
-
|
|
1112
|
+
// Format a version label for display:
|
|
1113
|
+
// "main" → "main @ <short-sha>" (next channel shows what SHA landed)
|
|
1114
|
+
// "v1.7.0" or "1.7.0" → "v1.7.0" (prefix 'v' when missing)
|
|
1115
|
+
// anything else (legacy strings) → as-is
|
|
1116
|
+
const fmt = (v, sha) => {
|
|
1117
|
+
if (typeof v !== 'string' || !v) return '';
|
|
1118
|
+
if (v === 'main' || v === 'HEAD') return sha ? `main @ ${sha.slice(0, 7)}` : 'main';
|
|
1119
|
+
if (/^v?\d+\.\d+\.\d+/.test(v)) return v.startsWith('v') ? v : `v${v}`;
|
|
1120
|
+
return v;
|
|
1121
|
+
};
|
|
1122
|
+
const newV = fmt(r.newVersion, r.newSha);
|
|
1123
|
+
// 'main'/'HEAD' strings only identify the channel, not the commit, so
|
|
1124
|
+
// we can't assert "no change" without comparing SHAs — and preVersions
|
|
1125
|
+
// doesn't carry the old SHA. Render these as a refresh instead of a
|
|
1126
|
+
// false-negative "no change".
|
|
1127
|
+
const isMainLike = oldVersion === 'main' || oldVersion === 'HEAD';
|
|
1128
|
+
if (oldVersion && oldVersion === r.newVersion && !isMainLike) {
|
|
1129
|
+
detail = ` (${newV}, no change)`;
|
|
1130
|
+
} else if (oldVersion && isMainLike) {
|
|
1131
|
+
detail = ` (${newV}, refreshed)`;
|
|
1096
1132
|
} else if (oldVersion) {
|
|
1097
|
-
detail = ` (
|
|
1133
|
+
detail = ` (${fmt(oldVersion, r.newSha)} → ${newV})`;
|
|
1098
1134
|
} else {
|
|
1099
|
-
detail = ` (
|
|
1135
|
+
detail = ` (${newV}, installed)`;
|
|
1100
1136
|
}
|
|
1101
1137
|
} else if (r.detail) {
|
|
1102
1138
|
detail = ` (${r.detail})`;
|
|
@@ -1216,9 +1252,59 @@ class Installer {
|
|
|
1216
1252
|
await prompts.log.warn(`Skipping ${skippedModules.length} module(s) - no source available: ${skippedModules.join(', ')}`);
|
|
1217
1253
|
}
|
|
1218
1254
|
|
|
1255
|
+
// Build channel options from the existing manifest FIRST so the config
|
|
1256
|
+
// collector below (which triggers external-module clones via
|
|
1257
|
+
// findModuleSource) knows each module's recorded channel and doesn't
|
|
1258
|
+
// silently redecide it. Without this, modules previously on 'next' or
|
|
1259
|
+
// 'pinned' would trigger a stable-channel tag lookup at config-collection
|
|
1260
|
+
// time, burning GitHub API quota and potentially failing.
|
|
1261
|
+
const manifestData = await this.manifest.read(bmadDir);
|
|
1262
|
+
const channelOptions = { global: null, nextSet: new Set(), pins: new Map(), warnings: [] };
|
|
1263
|
+
if (manifestData?.modulesDetailed) {
|
|
1264
|
+
const { fetchStableTags, classifyUpgrade, parseGitHubRepo } = require('../modules/channel-resolver');
|
|
1265
|
+
for (const entry of manifestData.modulesDetailed) {
|
|
1266
|
+
if (!entry?.name || !entry?.channel) continue;
|
|
1267
|
+
if (entry.channel === 'pinned' && entry.version) {
|
|
1268
|
+
channelOptions.pins.set(entry.name, entry.version);
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
if (entry.channel === 'next') {
|
|
1272
|
+
channelOptions.nextSet.add(entry.name);
|
|
1273
|
+
continue;
|
|
1274
|
+
}
|
|
1275
|
+
// Stable: classify the available upgrade. Patches and minors fall
|
|
1276
|
+
// through (stable default picks up the top tag). A major upgrade
|
|
1277
|
+
// requires opt-in, so under quick-update's non-interactive semantics
|
|
1278
|
+
// we pin to the current version to prevent a silent breaking jump.
|
|
1279
|
+
if (entry.channel === 'stable' && entry.version && entry.repoUrl) {
|
|
1280
|
+
const parsed = parseGitHubRepo(entry.repoUrl);
|
|
1281
|
+
if (!parsed) continue;
|
|
1282
|
+
try {
|
|
1283
|
+
const tags = await fetchStableTags(parsed.owner, parsed.repo);
|
|
1284
|
+
if (tags.length === 0) continue;
|
|
1285
|
+
const topTag = tags[0].tag;
|
|
1286
|
+
const cls = classifyUpgrade(entry.version, topTag);
|
|
1287
|
+
if (cls === 'major') {
|
|
1288
|
+
channelOptions.pins.set(entry.name, entry.version);
|
|
1289
|
+
await prompts.log.warn(
|
|
1290
|
+
`${entry.name} ${entry.version} → ${topTag} is a new major release; staying on ${entry.version}. ` +
|
|
1291
|
+
`Run \`bmad install\` (Modify) with \`--pin ${entry.name}=${topTag}\` to accept.`,
|
|
1292
|
+
);
|
|
1293
|
+
}
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
// Tag lookup failed (offline, rate-limited). Stay on the current
|
|
1296
|
+
// version rather than guessing — the existing cache is already
|
|
1297
|
+
// at that ref, so re-using it keeps the install stable.
|
|
1298
|
+
channelOptions.pins.set(entry.name, entry.version);
|
|
1299
|
+
await prompts.log.warn(`Could not check ${entry.name} for updates (${error.message}); staying on ${entry.version}.`);
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1219
1305
|
// Load existing configs and collect new fields (if any)
|
|
1220
1306
|
await prompts.log.info('Checking for new configuration options...');
|
|
1221
|
-
const quickModules = new OfficialModules();
|
|
1307
|
+
const quickModules = new OfficialModules({ channelOptions });
|
|
1222
1308
|
await quickModules.loadExistingConfig(projectDir);
|
|
1223
1309
|
|
|
1224
1310
|
let promptedForNewFields = false;
|
|
@@ -1257,6 +1343,7 @@ class Installer {
|
|
|
1257
1343
|
_quickUpdate: true,
|
|
1258
1344
|
_preserveModules: skippedModules,
|
|
1259
1345
|
_existingModules: installedModules,
|
|
1346
|
+
channelOptions,
|
|
1260
1347
|
};
|
|
1261
1348
|
|
|
1262
1349
|
await this.install(installConfig);
|