bmad-method 6.9.1-next.22 → 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 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 Auto (bmad-auto). Install BMad Auto instead."
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "bmad-method",
4
- "version": "6.9.1-next.22",
4
+ "version": "6.9.1-next.23",
5
5
  "description": "Breakthrough Method of Agile AI-driven Development",
6
6
  "keywords": [
7
7
  "agile",
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
@@ -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-auto-setup
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(`uv ${detected.version.raw} detected — ready to run BMAD's Python-powered scripts via \`uv run\`.`);
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
- * @param {string} code - The module code (e.g., 'cis')
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');
@@ -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
- if (officialCodes.has(moduleId)) continue;
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) {