bmad-method 6.12.1 → 6.12.2

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.
Files changed (25) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/bmad-modules.yaml +5 -0
  3. package/package.json +1 -1
  4. package/src/bmm-skills/plan/bmad-architecture/scripts/lint_spine.py +4 -0
  5. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc +0 -0
  6. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/sprint_plan.py +4 -0
  7. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-311-pytest-9.1.1.pyc +0 -0
  8. package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc +0 -0
  9. package/src/bmm-skills/ship/bmad-retrospective/scripts/git_evidence.py +4 -0
  10. package/src/bmm-skills/ship/bmad-retrospective/scripts/sprint_status.py +4 -0
  11. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-311-pytest-9.1.1.pyc +0 -0
  12. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-311-pytest-9.1.1.pyc +0 -0
  13. package/src/core-skills/bmad-customize/scripts/list_customizable_skills.py +4 -0
  14. package/src/core-skills/bmad-deep-recon/scripts/recon_kit.py +4 -0
  15. package/src/scripts/__pycache__/config_utils.cpython-311.pyc +0 -0
  16. package/src/scripts/memlog.py +4 -0
  17. package/src/scripts/tests/__pycache__/test_config_utils.cpython-311.pyc +0 -0
  18. package/src/scripts/tests/__pycache__/test_resolve_config.cpython-311.pyc +0 -0
  19. package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-311.pyc +0 -0
  20. package/tools/installer/core/installer.js +3 -0
  21. package/tools/installer/install-messages.yaml +13 -6
  22. package/tools/installer/modules/channel-plan.js +6 -1
  23. package/tools/installer/modules/external-manager.js +2 -0
  24. package/tools/installer/ui.js +13 -3
  25. package/tools/tests/__pycache__/test_validate_skills.cpython-311.pyc +0 -0
@@ -14,7 +14,7 @@
14
14
  "displayName": "BMad Method Analyze Plan Build",
15
15
  "source": "./",
16
16
  "description": "Full-lifecycle AI development framework — agents and workflows for product analysis, planning, architecture, and implementation.",
17
- "version": "6.12.1",
17
+ "version": "6.12.2",
18
18
  "author": {
19
19
  "name": "Brian (BMad) Madison"
20
20
  },
package/bmad-modules.yaml CHANGED
@@ -8,6 +8,9 @@
8
8
  # override with --channel/--pin/--next. Valid values: stable | next.
9
9
  # Omit to inherit the installer's hardcoded default (stable).
10
10
  #
11
+ # pin (optional) — a git tag to install instead of the channel. Use it when
12
+ # newer releases no longer work with this installer. Only --pin overrides it.
13
+ #
11
14
  # deprecated (optional, default false) — when true, the module is hidden from
12
15
  # the installer picker UNLESS it is already installed (so existing users can
13
16
  # still see/manage it, but new users are not offered it).
@@ -55,6 +58,7 @@ modules:
55
58
  type: bmad-org
56
59
  npmPackage: bmad-creative-intelligence-suite
57
60
  default_channel: stable
61
+ pin: v0.3.2
58
62
 
59
63
  bmad-method-test-architecture-enterprise:
60
64
  url: https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise
@@ -66,6 +70,7 @@ modules:
66
70
  type: bmad-org
67
71
  npmPackage: bmad-method-test-architecture-enterprise
68
72
  default_channel: stable
73
+ pin: v1.27.2
69
74
 
70
75
  bmad-loop:
71
76
  url: https://github.com/bmad-code-org/bmad-loop
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.12.1",
4
+ "version": "6.12.2",
5
5
  "description": "Breakthrough Method of Agile AI-driven Development",
6
6
  "keywords": [
7
7
  "agile",
@@ -254,4 +254,8 @@ def main(argv: list[str] | None = None) -> int:
254
254
 
255
255
 
256
256
  if __name__ == "__main__":
257
+ if sys.platform == "win32":
258
+ # Piped output on Windows defaults to a legacy code page, not UTF-8.
259
+ sys.stdout.reconfigure(encoding="utf-8")
260
+ sys.stderr.reconfigure(encoding="utf-8")
257
261
  sys.exit(main())
@@ -694,4 +694,8 @@ def main(argv=None):
694
694
 
695
695
 
696
696
  if __name__ == "__main__":
697
+ if sys.platform == "win32":
698
+ # Piped output on Windows defaults to a legacy code page, not UTF-8.
699
+ sys.stdout.reconfigure(encoding="utf-8")
700
+ sys.stderr.reconfigure(encoding="utf-8")
697
701
  main()
@@ -301,4 +301,8 @@ def main(argv=None):
301
301
 
302
302
 
303
303
  if __name__ == "__main__":
304
+ if sys.platform == "win32":
305
+ # Piped output on Windows defaults to a legacy code page, not UTF-8.
306
+ sys.stdout.reconfigure(encoding="utf-8")
307
+ sys.stderr.reconfigure(encoding="utf-8")
304
308
  main()
@@ -743,4 +743,8 @@ def main(argv=None):
743
743
 
744
744
 
745
745
  if __name__ == "__main__":
746
+ if sys.platform == "win32":
747
+ # Piped output on Windows defaults to a legacy code page, not UTF-8.
748
+ sys.stdout.reconfigure(encoding="utf-8")
749
+ sys.stderr.reconfigure(encoding="utf-8")
746
750
  main()
@@ -228,4 +228,8 @@ def main(argv: list[str]) -> int:
228
228
 
229
229
 
230
230
  if __name__ == "__main__":
231
+ if sys.platform == "win32":
232
+ # Piped output on Windows defaults to a legacy code page, not UTF-8.
233
+ sys.stdout.reconfigure(encoding="utf-8")
234
+ sys.stderr.reconfigure(encoding="utf-8")
231
235
  sys.exit(main(sys.argv[1:]))
@@ -319,4 +319,8 @@ def main(argv: list[str] | None = None) -> int:
319
319
 
320
320
 
321
321
  if __name__ == "__main__":
322
+ if sys.platform == "win32":
323
+ # Piped output on Windows defaults to a legacy code page, not UTF-8.
324
+ sys.stdout.reconfigure(encoding="utf-8")
325
+ sys.stderr.reconfigure(encoding="utf-8")
322
326
  sys.exit(main())
@@ -221,4 +221,8 @@ def main(argv: list[str] | None = None) -> int:
221
221
 
222
222
 
223
223
  if __name__ == "__main__":
224
+ if sys.platform == "win32":
225
+ # Piped output on Windows defaults to a legacy code page, not UTF-8.
226
+ sys.stdout.reconfigure(encoding="utf-8")
227
+ sys.stderr.reconfigure(encoding="utf-8")
224
228
  sys.exit(main())
@@ -1326,6 +1326,9 @@ class Installer {
1326
1326
  rounded: true,
1327
1327
  formatBorder: color.green,
1328
1328
  });
1329
+
1330
+ const { MessageLoader } = require('../message-loader');
1331
+ await new MessageLoader().displayEndMessage();
1329
1332
  }
1330
1333
 
1331
1334
  /**
@@ -6,16 +6,19 @@
6
6
  startMessage: |
7
7
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
8
8
 
9
- Agile AI-Driven Development. Powered by BMad Core and a growing module ecosystem.
9
+ The Breakthrough Method of Agile AI-Driven Development - the original and best AI SDLC. Powered by BMad Core and a growing module ecosystem.
10
10
  Install official and community modules during setup to customize your experience.
11
11
 
12
12
  🌟 100% free. 100% open source. Always.
13
13
  No paywalls. No gated content. Knowledge shared, not sold.
14
14
 
15
+ 🚀 BMad v7 is close, and you can preview and test it now:
16
+ npx skills add bmad-code-org/BMAD-METHOD
17
+ then ask your agent for `bmad setup`. After setup, `bmad migrate`
18
+ tests the v6 to v7 migration (still in beta).
19
+
15
20
  🐍 REQUIRED: uv (https://docs.astral.sh/uv/) runs the Python scripts BMAD
16
- skills rely on (`uv run <script>`) and provisions the interpreter itself.
17
- Without it, bmad-build and bmad-build-auto halt on activation.
18
- If it's not set up yet, ask your AI agent to "install and set up uv for me".
21
+ skills rely on. If it's not set up yet, ask your AI agent to "install and set up uv for me".
19
22
 
20
23
  🌐 CONNECT:
21
24
  Website: https://bmadcode.com/
@@ -33,5 +36,9 @@ startMessage: |
33
36
 
34
37
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
35
38
 
36
- # No end message - install summary and next steps are rendered by the installer
37
- endMessage: ""
39
+ # Display at the END of installation (after the install summary)
40
+ endMessage: |
41
+ 🚀 BMad v7 is close, and you can preview and test it now:
42
+ npx skills add bmad-code-org/BMAD-METHOD
43
+ then ask your agent for `bmad setup`. After setup, `bmad migrate`
44
+ tests the v6 to v7 migration (still in beta).
@@ -104,15 +104,19 @@ function parsePinSpec(spec) {
104
104
  * @param {string} args.code
105
105
  * @param {Object} args.channelOptions - from parseChannelOptions
106
106
  * @param {string} [args.registryDefault] - module's default_channel, if any
107
+ * @param {string} [args.registryPin] - module's registry pin, if any
107
108
  * @returns {{channel: 'stable'|'next'|'pinned', pin?: string, source: string}}
108
109
  * source describes where the decision came from, for logging / debugging.
109
110
  */
110
- function decideChannelForModule({ code, channelOptions, registryDefault }) {
111
+ function decideChannelForModule({ code, channelOptions, registryDefault, registryPin }) {
111
112
  const { global, nextSet, pins } = channelOptions || { nextSet: new Set(), pins: new Map() };
112
113
 
113
114
  if (pins && pins.has(code)) {
114
115
  return { channel: 'pinned', pin: pins.get(code), source: 'flag:--pin' };
115
116
  }
117
+ if (registryPin) {
118
+ return { channel: 'pinned', pin: registryPin, source: 'registry:pin' };
119
+ }
116
120
  if (nextSet && nextSet.has(code)) {
117
121
  return { channel: 'next', source: 'flag:--next' };
118
122
  }
@@ -144,6 +148,7 @@ function buildPlan({ modules, channelOptions }) {
144
148
  code: mod.code,
145
149
  channelOptions,
146
150
  registryDefault: mod.defaultChannel,
151
+ registryPin: mod.pin,
147
152
  }),
148
153
  );
149
154
  }
@@ -130,6 +130,7 @@ class ExternalModuleManager {
130
130
  npmPackage: mod.npm_package || mod.npmPackage || null,
131
131
  pluginName: mod.plugin_name || mod.pluginName || null,
132
132
  defaultChannel: normalizeChannelName(mod.default_channel || mod.defaultChannel) || 'stable',
133
+ pin: mod.pin || null,
133
134
  deprecated: mod.deprecated === true,
134
135
  deprecationMessage: mod.deprecation_message || mod['deprecation-message'] || mod.deprecationMessage || null,
135
136
  marketplacePlugin: mod.marketplace_plugin === true || mod['marketplace-plugin'] === true || mod.marketplacePlugin === true,
@@ -273,6 +274,7 @@ class ExternalModuleManager {
273
274
  code: moduleCode,
274
275
  channelOptions: options.channelOptions,
275
276
  registryDefault: moduleInfo.defaultChannel,
277
+ registryPin: moduleInfo.pin,
276
278
  });
277
279
 
278
280
  // Same-plan short-circuit: a single install calls cloneExternalModule
@@ -70,15 +70,17 @@ function buildModuleLabel(name, latestVersion, installedVersion = '') {
70
70
  * @param {Object} options
71
71
  * @param {string|null} [options.repoUrl] - Module repository URL for tag resolution
72
72
  * @param {string|null} [options.registryDefault] - Registry default channel
73
+ * @param {string|null} [options.registryPin] - Registry pinned tag
73
74
  * @param {Object|null} [options.channelOptions] - Parsed installer channel options
74
75
  * @returns {Promise<{version: string, lookupAttempted: boolean, lookupSucceeded: boolean}>}
75
76
  */
76
- async function getModuleVersion(moduleCode, { repoUrl = null, registryDefault = null, channelOptions = null } = {}) {
77
+ async function getModuleVersion(moduleCode, { repoUrl = null, registryDefault = null, registryPin = null, channelOptions = null } = {}) {
77
78
  if (repoUrl) {
78
79
  const plan = decideChannelForModule({
79
80
  code: moduleCode,
80
81
  channelOptions,
81
82
  registryDefault,
83
+ registryPin,
82
84
  });
83
85
 
84
86
  try {
@@ -291,6 +293,13 @@ class UI {
291
293
  }
292
294
  confirmedDirectory = expandedDir;
293
295
  await prompts.log.info(`Using directory from command-line: ${confirmedDirectory}`);
296
+ } else if (options.yes) {
297
+ confirmedDirectory = process.cwd();
298
+ const validation = this.validateDirectorySync(confirmedDirectory);
299
+ if (validation) {
300
+ throw new Error(`Invalid directory: ${validation}`);
301
+ }
302
+ await prompts.log.info(`Using current directory: ${confirmedDirectory}`);
294
303
  } else {
295
304
  confirmedDirectory = await this.getConfirmedDirectory();
296
305
  }
@@ -1058,10 +1067,10 @@ class UI {
1058
1067
  const allOptions = [];
1059
1068
  const initialValues = [];
1060
1069
 
1061
- const buildModuleEntry = async (code, name, description, isDefault, repoUrl = null, registryDefault = null) => {
1070
+ const buildModuleEntry = async (code, name, description, isDefault, repoUrl = null, registryDefault = null, registryPin = null) => {
1062
1071
  const isInstalled = installedModuleIds.has(code);
1063
1072
  const installedVersion = installedModuleVersions.get(code) || '';
1064
- const versionState = await getModuleVersion(code, { repoUrl, registryDefault, channelOptions });
1073
+ const versionState = await getModuleVersion(code, { repoUrl, registryDefault, registryPin, channelOptions });
1065
1074
  const label = buildModuleLabel(name, versionState.version, installedVersion);
1066
1075
  return {
1067
1076
  label,
@@ -1109,6 +1118,7 @@ class UI {
1109
1118
  mod.defaultSelected,
1110
1119
  mod.url || null,
1111
1120
  mod.defaultChannel || null,
1121
+ mod.pin || null,
1112
1122
  );
1113
1123
  if (mod.deprecated && mod.deprecationMessage) {
1114
1124
  entry.hint = entry.hint ? `${entry.hint} — ${mod.deprecationMessage}` : mod.deprecationMessage;