bmad-method 6.9.1-next.21 → 6.9.1-next.23
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/bmad-modules.yaml +32 -22
- package/package.json +1 -1
- package/removals.txt +5 -0
- package/src/core-skills/bmad-help/SKILL.md +1 -1
- package/tools/installer/core/installer.js +36 -2
- package/tools/installer/core/uv-check.js +1 -1
- package/tools/installer/modules/external-manager.js +32 -3
- package/tools/installer/ui.js +6 -1
package/bmad-modules.yaml
CHANGED
|
@@ -26,8 +26,39 @@
|
|
|
26
26
|
# Interactive installs require the user to acknowledge it (press Enter);
|
|
27
27
|
# non-interactive (--yes) installs print it and continue. Use for required
|
|
28
28
|
# follow-up steps (e.g. "run the X setup skill").
|
|
29
|
+
#
|
|
30
|
+
# aliases (optional) — prior `code` values this module was registered under.
|
|
31
|
+
# An existing install recorded under an alias resolves to this entry (source,
|
|
32
|
+
# name, description, post-install message) instead of being orphaned as
|
|
33
|
+
# "no source available" when the code changes. quick-update also migrates the
|
|
34
|
+
# install to the new code and removes the stale `_bmad/<alias>/` directory.
|
|
29
35
|
|
|
30
36
|
modules:
|
|
37
|
+
bmad-loop:
|
|
38
|
+
url: https://github.com/bmad-code-org/bmad-loop
|
|
39
|
+
module-definition: src/bmad_loop/data/skills/bmad-loop-setup/assets/module.yaml
|
|
40
|
+
code: bmad-loop
|
|
41
|
+
# bauto is the pre-rename code (module was bmad-auto before both the repo
|
|
42
|
+
# and its contents were renamed to bmad-loop); keeps existing bauto
|
|
43
|
+
# installs migrating forward instead of being orphaned.
|
|
44
|
+
aliases: [bauto]
|
|
45
|
+
name: "BMad Loop"
|
|
46
|
+
description: "Deterministic, Python-based unattended dev loop with adversarial review"
|
|
47
|
+
defaultSelected: false
|
|
48
|
+
type: bmad-org
|
|
49
|
+
default_channel: stable
|
|
50
|
+
# Skills live outside a single module.yaml dir; resolve them from
|
|
51
|
+
# .claude-plugin/marketplace.json via the plugin resolver (see external-manager).
|
|
52
|
+
marketplace-plugin: true
|
|
53
|
+
post-install-message: |
|
|
54
|
+
BMad Loop installed. To finish setup, run the bmad-loop-setup skill
|
|
55
|
+
from your agent:
|
|
56
|
+
|
|
57
|
+
> use the bmad-loop-setup skill
|
|
58
|
+
|
|
59
|
+
It installs the bmad-loop orchestrator tool and wires up the per-project
|
|
60
|
+
hooks and policy. The automation skills don't run until setup completes.
|
|
61
|
+
|
|
31
62
|
bmad-method-test-architecture-enterprise:
|
|
32
63
|
url: https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise
|
|
33
64
|
module-definition: src/module.yaml
|
|
@@ -61,28 +92,7 @@ modules:
|
|
|
61
92
|
npmPackage: bmad-story-automator
|
|
62
93
|
default_channel: next
|
|
63
94
|
deprecated: true
|
|
64
|
-
deprecation-message: "BMad Automator has been deprecated and is replaced by BMad
|
|
65
|
-
|
|
66
|
-
bmad-auto:
|
|
67
|
-
url: https://github.com/bmad-code-org/bmad-auto
|
|
68
|
-
module-definition: src/automator/data/skills/bmad-auto-setup/assets/module.yaml
|
|
69
|
-
code: bauto
|
|
70
|
-
name: "BMad Auto"
|
|
71
|
-
description: "Automation-mode skills driven by the bmad-auto orchestrator: unattended dev, adversarial review, and deferred-work sweep triage"
|
|
72
|
-
defaultSelected: false
|
|
73
|
-
type: bmad-org
|
|
74
|
-
default_channel: stable
|
|
75
|
-
# Skills live outside a single module.yaml dir; resolve them from
|
|
76
|
-
# .claude-plugin/marketplace.json via the plugin resolver (see external-manager).
|
|
77
|
-
marketplace-plugin: true
|
|
78
|
-
post-install-message: |
|
|
79
|
-
BMad Auto installed. To finish setup, run the bmad-auto-setup skill
|
|
80
|
-
from your agent:
|
|
81
|
-
|
|
82
|
-
> use the bmad-auto-setup skill
|
|
83
|
-
|
|
84
|
-
It installs the bmad-auto orchestrator tool and wires up the per-project
|
|
85
|
-
hooks and policy. The automation skills don't run until setup completes.
|
|
95
|
+
deprecation-message: "BMad Automator has been deprecated and is replaced by BMad Loop (bmad-loop). Install BMad Loop instead."
|
|
86
96
|
|
|
87
97
|
bmad-creative-intelligence-suite:
|
|
88
98
|
url: https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite
|
package/package.json
CHANGED
package/removals.txt
CHANGED
|
@@ -63,3 +63,8 @@ bmad-create-ux-design
|
|
|
63
63
|
# bmad-investigate: retired. Plain investigation reaches the same conclusions at
|
|
64
64
|
# lower cost.
|
|
65
65
|
bmad-investigate
|
|
66
|
+
|
|
67
|
+
# Removed skills (v6.10.0)
|
|
68
|
+
# bmad-auto-setup: renamed to bmad-loop-setup as part of the bmad-auto ->
|
|
69
|
+
# bmad-loop module rename (BMad Automator's replacement).
|
|
70
|
+
bmad-auto-setup
|
|
@@ -23,7 +23,7 @@ When this skill completes, the user should:
|
|
|
23
23
|
## Data Sources
|
|
24
24
|
|
|
25
25
|
- **Catalog**: `{project-root}/_bmad/_config/bmad-help.csv` — assembled manifest of all installed module skills
|
|
26
|
-
- **Config**: `
|
|
26
|
+
- **Config**: Run `uv run --python 3.11 {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root}` and use the merged JSON to resolve `output-location` variables and read `core.communication_language` and `modules.bmm.project_knowledge`. The resolver merges `_bmad/config.toml`, `_bmad/config.user.toml`, `_bmad/custom/config.toml`, and `_bmad/custom/config.user.toml` in that order.
|
|
27
27
|
- **Artifacts**: Files matching `outputs` patterns at resolved `output-location` paths reveal which steps are possibly completed; their content may also provide grounding context for recommendations
|
|
28
28
|
- **Project knowledge**: If `project_knowledge` resolves to an existing path, read it for grounding context. Never fabricate project-specific details.
|
|
29
29
|
- **Module docs**: Rows with `_meta` in the `skill` column carry a URL or path in `output-location` pointing to the module's documentation (e.g., llms.txt). Fetch and use these to answer general questions about that module.
|
|
@@ -1253,7 +1253,7 @@ class Installer {
|
|
|
1253
1253
|
|
|
1254
1254
|
/**
|
|
1255
1255
|
* Display registry-defined post-install messages for the modules installed in
|
|
1256
|
-
* this run. These are "action needed" notices (e.g. "run the bmad-
|
|
1256
|
+
* this run. These are "action needed" notices (e.g. "run the bmad-loop-setup
|
|
1257
1257
|
* skill") that the user must see to finish setup. They are defined via the
|
|
1258
1258
|
* `post-install-message` property on a module's bmad-modules.yaml entry.
|
|
1259
1259
|
*
|
|
@@ -1317,10 +1317,32 @@ class Installer {
|
|
|
1317
1317
|
|
|
1318
1318
|
// Detect existing installation
|
|
1319
1319
|
const existingInstall = await ExistingInstall.detect(bmadDir);
|
|
1320
|
-
const installedModules = existingInstall.moduleIds;
|
|
1321
1320
|
const configuredIdes = existingInstall.ides;
|
|
1322
1321
|
const projectRoot = path.dirname(bmadDir);
|
|
1323
1322
|
|
|
1323
|
+
// Resolve any legacy/aliased module codes (e.g. an install recorded as
|
|
1324
|
+
// `bauto` before the registry renamed it to `bmad-loop`) to their current
|
|
1325
|
+
// canonical code up front. Without this, a renamed module's old installs
|
|
1326
|
+
// would fall out of `availableModuleIds` below and get silently frozen
|
|
1327
|
+
// (see the `baut` → `automator` incident in CHANGELOG v6.7.1) instead of
|
|
1328
|
+
// migrating forward.
|
|
1329
|
+
const aliasMigrations = [];
|
|
1330
|
+
const seenModuleIds = new Set();
|
|
1331
|
+
const installedModules = [];
|
|
1332
|
+
for (const rawId of existingInstall.moduleIds) {
|
|
1333
|
+
const canonicalId = await this.externalModuleManager.resolveCanonicalCode(rawId);
|
|
1334
|
+
if (canonicalId !== rawId) {
|
|
1335
|
+
aliasMigrations.push({ from: rawId, to: canonicalId });
|
|
1336
|
+
}
|
|
1337
|
+
if (!seenModuleIds.has(canonicalId)) {
|
|
1338
|
+
seenModuleIds.add(canonicalId);
|
|
1339
|
+
installedModules.push(canonicalId);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
for (const { from, to } of aliasMigrations) {
|
|
1343
|
+
await prompts.log.info(`Migrating installed module '${from}' to its renamed successor '${to}'.`);
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1324
1346
|
// Get available modules (what we have source for)
|
|
1325
1347
|
const availableModulesData = await new OfficialModules().listAvailable();
|
|
1326
1348
|
const availableModules = [...availableModulesData.modules];
|
|
@@ -1465,6 +1487,18 @@ class Installer {
|
|
|
1465
1487
|
|
|
1466
1488
|
await this.install(installConfig);
|
|
1467
1489
|
|
|
1490
|
+
// Now that the canonical module has been installed successfully, remove
|
|
1491
|
+
// the stale directory left behind under its old code so the two don't
|
|
1492
|
+
// coexist (e.g. `_bmad/bauto/` once `_bmad/bmad-loop/` is in place).
|
|
1493
|
+
for (const { from, to } of aliasMigrations) {
|
|
1494
|
+
if (!modulesToUpdate.includes(to)) continue; // new code wasn't actually installed this run
|
|
1495
|
+
const oldModuleDir = path.join(bmadDir, from);
|
|
1496
|
+
if (await fs.pathExists(oldModuleDir)) {
|
|
1497
|
+
await fs.remove(oldModuleDir);
|
|
1498
|
+
await prompts.log.success(`Removed legacy '${from}' directory after migrating to '${to}'.`);
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1468
1502
|
return {
|
|
1469
1503
|
success: true,
|
|
1470
1504
|
moduleCount: modulesToUpdate.length,
|
|
@@ -77,7 +77,7 @@ async function checkUvEnvironment() {
|
|
|
77
77
|
const detected = module.exports.detectUv();
|
|
78
78
|
|
|
79
79
|
if (detected) {
|
|
80
|
-
await prompts.log.success(
|
|
80
|
+
await prompts.log.success(`✅ Python UV check pass (uv ${detected.version.raw} detected).`);
|
|
81
81
|
return { status: 'found', detected };
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -135,6 +135,10 @@ class ExternalModuleManager {
|
|
|
135
135
|
postInstallMessage: mod.post_install_message || mod['post-install-message'] || mod.postInstallMessage || null,
|
|
136
136
|
builtIn: mod.built_in === true,
|
|
137
137
|
isExternal: mod.built_in !== true,
|
|
138
|
+
// Prior codes this module was registered under (e.g. `bmad-loop` was
|
|
139
|
+
// `bauto`). Lets a renamed module keep resolving existing installs
|
|
140
|
+
// instead of orphaning them — see getModuleByCode().
|
|
141
|
+
aliases: Array.isArray(mod.aliases) ? mod.aliases : [],
|
|
138
142
|
};
|
|
139
143
|
}
|
|
140
144
|
|
|
@@ -159,13 +163,27 @@ class ExternalModuleManager {
|
|
|
159
163
|
}
|
|
160
164
|
|
|
161
165
|
/**
|
|
162
|
-
* Get module info by code
|
|
163
|
-
*
|
|
166
|
+
* Get module info by code. Falls back to matching a registry entry's
|
|
167
|
+
* `aliases` list, so a module that was renamed (its `code` changed) still
|
|
168
|
+
* resolves for installs recorded under the prior code.
|
|
169
|
+
* @param {string} code - The module code (e.g., 'cis'), current or aliased
|
|
164
170
|
* @returns {Object|null} Module info or null if not found
|
|
165
171
|
*/
|
|
166
172
|
async getModuleByCode(code) {
|
|
167
173
|
const modules = await this.listAvailable();
|
|
168
|
-
return modules.find((m) => m.code === code) || null;
|
|
174
|
+
return modules.find((m) => m.code === code) || modules.find((m) => m.aliases.includes(code)) || null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Resolve a possibly-legacy module code to its current canonical code.
|
|
179
|
+
* Returns the input unchanged if it doesn't match any registry entry or
|
|
180
|
+
* alias (e.g. a custom/unknown module).
|
|
181
|
+
* @param {string} code
|
|
182
|
+
* @returns {Promise<string>}
|
|
183
|
+
*/
|
|
184
|
+
async resolveCanonicalCode(code) {
|
|
185
|
+
const info = await this.getModuleByCode(code);
|
|
186
|
+
return info ? info.code : code;
|
|
169
187
|
}
|
|
170
188
|
|
|
171
189
|
/**
|
|
@@ -196,6 +214,11 @@ class ExternalModuleManager {
|
|
|
196
214
|
throw new Error(`External module '${moduleCode}' not found in the BMad registry`);
|
|
197
215
|
}
|
|
198
216
|
|
|
217
|
+
// Normalize to the canonical code so cache dir, in-memory resolutions,
|
|
218
|
+
// and log/error text stay consistent even when called with a renamed
|
|
219
|
+
// module's prior alias (getModuleByCode resolves aliases above).
|
|
220
|
+
moduleCode = moduleInfo.code;
|
|
221
|
+
|
|
199
222
|
const cacheDir = this.getExternalCacheDir();
|
|
200
223
|
const moduleCacheDir = path.join(cacheDir, moduleCode);
|
|
201
224
|
const silent = options.silent || false;
|
|
@@ -488,6 +511,9 @@ class ExternalModuleManager {
|
|
|
488
511
|
return null;
|
|
489
512
|
}
|
|
490
513
|
|
|
514
|
+
// Normalize to the canonical code — see cloneExternalModule for why.
|
|
515
|
+
moduleCode = moduleInfo.code;
|
|
516
|
+
|
|
491
517
|
// Marketplace-plugin modules (registry entries flagged `marketplace-plugin`)
|
|
492
518
|
// ship a .claude-plugin/marketplace.json and keep their module.yaml inside a
|
|
493
519
|
// skill's assets/ rather than in one directory alongside the skills. Resolve
|
|
@@ -573,6 +599,9 @@ class ExternalModuleManager {
|
|
|
573
599
|
return null;
|
|
574
600
|
}
|
|
575
601
|
|
|
602
|
+
// Normalize to the canonical code — see cloneExternalModule for why.
|
|
603
|
+
moduleCode = moduleInfo.code;
|
|
604
|
+
|
|
576
605
|
const cloneDir = await this.cloneExternalModule(moduleCode, options);
|
|
577
606
|
|
|
578
607
|
const marketplacePath = path.join(cloneDir, '.claude-plugin', 'marketplace.json');
|
package/tools/installer/ui.js
CHANGED
|
@@ -133,7 +133,12 @@ class UI {
|
|
|
133
133
|
for (const moduleId of installedModuleIds) {
|
|
134
134
|
if (moduleId === 'core') continue;
|
|
135
135
|
if (!selectedSet.has(moduleId) && !options.preserveUnselected) continue;
|
|
136
|
-
|
|
136
|
+
// Resolve a possibly-renamed module code (e.g. `bauto` -> `bmad-loop`)
|
|
137
|
+
// before checking availability, so a registry rename doesn't freeze
|
|
138
|
+
// the install here the way it would have prior to the alias support
|
|
139
|
+
// in ExternalModuleManager.getModuleByCode().
|
|
140
|
+
const canonicalId = await externalManager.resolveCanonicalCode(moduleId);
|
|
141
|
+
if (officialCodes.has(canonicalId)) continue;
|
|
137
142
|
|
|
138
143
|
const customSource = await customMgr.findModuleSourceByCode(moduleId, { bmadDir });
|
|
139
144
|
if (!customSource) {
|