bmad-method 6.11.1-next.2 → 6.11.1-next.21

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 (99) hide show
  1. package/package.json +2 -2
  2. package/src/bmm-skills/agents/bmad-agent-analyst/customize.toml +1 -3
  3. package/src/bmm-skills/agents/bmad-agent-architect/customize.toml +1 -3
  4. package/src/bmm-skills/agents/bmad-agent-dev/customize.toml +1 -3
  5. package/src/bmm-skills/agents/bmad-agent-pm/customize.toml +1 -3
  6. package/src/bmm-skills/agents/bmad-agent-ux-designer/customize.toml +1 -3
  7. package/src/bmm-skills/plan/bmad-architecture/SKILL.md +1 -1
  8. package/src/bmm-skills/plan/bmad-architecture/customize.toml +5 -6
  9. package/src/bmm-skills/plan/bmad-create-epics-and-stories/customize.toml +1 -3
  10. package/src/bmm-skills/plan/bmad-generate-project-context/SKILL.md +2 -0
  11. package/src/bmm-skills/plan/bmad-prd/customize.toml +5 -6
  12. package/src/bmm-skills/plan/bmad-prfaq/customize.toml +1 -3
  13. package/src/bmm-skills/plan/bmad-product-brief/customize.toml +5 -6
  14. package/src/bmm-skills/plan/bmad-project-context/SKILL.md +23 -12
  15. package/src/bmm-skills/plan/bmad-project-context/references/best-practices.md +26 -7
  16. package/src/bmm-skills/plan/bmad-project-context/references/template.md +1 -1
  17. package/src/bmm-skills/plan/bmad-spec/customize.toml +5 -5
  18. package/src/bmm-skills/plan/bmad-sprint-planning/customize.toml +1 -3
  19. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc +0 -0
  20. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-311-pytest-9.1.1.pyc +0 -0
  21. package/src/bmm-skills/plan/bmad-ux/customize.toml +1 -3
  22. package/src/bmm-skills/ship/bmad-build/SKILL.md +1 -1
  23. package/src/bmm-skills/ship/bmad-build/customize.toml +13 -16
  24. package/src/bmm-skills/ship/bmad-build/references/claims-check.md +14 -0
  25. package/src/bmm-skills/ship/bmad-build/review-prompts/edge-case-hunter.md +29 -7
  26. package/src/bmm-skills/ship/bmad-build/review-prompts/verification-gap.md +1 -1
  27. package/src/bmm-skills/ship/bmad-build/step-01-clarify-and-route.md +12 -7
  28. package/src/bmm-skills/ship/bmad-build/step-02-plan.md +13 -10
  29. package/src/bmm-skills/ship/bmad-build/step-03-implement.md +3 -1
  30. package/src/bmm-skills/ship/bmad-build/step-04-review.md +7 -5
  31. package/src/bmm-skills/ship/bmad-build/step-oneshot.md +7 -8
  32. package/src/bmm-skills/ship/bmad-build-auto/customize.toml +16 -18
  33. package/src/bmm-skills/ship/bmad-build-auto/references/claims-check.md +14 -0
  34. package/src/bmm-skills/ship/bmad-build-auto/review-prompts/edge-case-hunter.md +29 -7
  35. package/src/bmm-skills/ship/bmad-build-auto/review-prompts/verification-gap.md +1 -1
  36. package/src/bmm-skills/ship/bmad-build-auto/step-03-implement.md +5 -1
  37. package/src/bmm-skills/ship/bmad-build-auto/step-04-review.md +7 -5
  38. package/src/bmm-skills/ship/bmad-checkpoint-preview/customize.toml +1 -3
  39. package/src/bmm-skills/ship/bmad-code-review/customize.toml +14 -17
  40. package/src/bmm-skills/ship/bmad-code-review/references/claims-check.md +14 -0
  41. package/src/bmm-skills/ship/bmad-code-review/review-prompts/edge-case-hunter.md +29 -7
  42. package/src/bmm-skills/ship/bmad-code-review/review-prompts/verification-gap.md +1 -1
  43. package/src/bmm-skills/ship/bmad-code-review/steps/step-01-gather-context.md +22 -15
  44. package/src/bmm-skills/ship/bmad-code-review/steps/step-02-review.md +2 -2
  45. package/src/bmm-skills/ship/bmad-correct-course/SKILL.md +11 -3
  46. package/src/bmm-skills/ship/bmad-correct-course/customize.toml +1 -3
  47. package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/customize.toml +1 -3
  48. package/src/bmm-skills/ship/bmad-retrospective/customize.toml +1 -3
  49. package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc +0 -0
  50. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-311-pytest-9.1.1.pyc +0 -0
  51. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-311-pytest-9.1.1.pyc +0 -0
  52. package/src/bmm-skills/v6-shims/bmad-create-architecture/SKILL.md +2 -0
  53. package/src/bmm-skills/v6-shims/bmad-create-architecture/customize.toml +1 -3
  54. package/src/bmm-skills/v6-shims/bmad-create-prd/SKILL.md +2 -0
  55. package/src/bmm-skills/v6-shims/bmad-create-prd/customize.toml +1 -3
  56. package/src/bmm-skills/v6-shims/bmad-create-story/SKILL.md +3 -1
  57. package/src/bmm-skills/v6-shims/bmad-create-story/customize.toml +1 -3
  58. package/src/bmm-skills/v6-shims/bmad-dev-auto/SKILL.md +2 -0
  59. package/src/bmm-skills/v6-shims/bmad-dev-story/SKILL.md +2 -0
  60. package/src/bmm-skills/v6-shims/bmad-dev-story/customize.toml +1 -6
  61. package/src/bmm-skills/v6-shims/bmad-document-project/SKILL.md +2 -0
  62. package/src/bmm-skills/v6-shims/bmad-domain-research/SKILL.md +2 -0
  63. package/src/bmm-skills/v6-shims/bmad-edit-prd/SKILL.md +2 -0
  64. package/src/bmm-skills/v6-shims/bmad-edit-prd/customize.toml +1 -3
  65. package/src/bmm-skills/v6-shims/bmad-market-research/SKILL.md +2 -0
  66. package/src/bmm-skills/v6-shims/bmad-quick-dev/SKILL.md +2 -0
  67. package/src/bmm-skills/v6-shims/bmad-sprint-status/SKILL.md +2 -0
  68. package/src/bmm-skills/v6-shims/bmad-sprint-status/customize.toml +1 -3
  69. package/src/bmm-skills/v6-shims/bmad-technical-research/SKILL.md +2 -0
  70. package/src/bmm-skills/v6-shims/bmad-validate-prd/SKILL.md +2 -0
  71. package/src/bmm-skills/v6-shims/bmad-validate-prd/customize.toml +1 -3
  72. package/src/core-skills/bmad-advanced-elicitation/SKILL.md +21 -22
  73. package/src/core-skills/bmad-brainstorming/customize.toml +5 -6
  74. package/src/core-skills/bmad-forge-idea/customize.toml +5 -6
  75. package/src/core-skills/bmad-party-mode/customize.toml +4 -4
  76. package/src/core-skills/bmad-review/SKILL.md +5 -4
  77. package/src/core-skills/bmad-review/customize.toml +1 -1
  78. package/src/core-skills/bmad-review/references/lens-edge-case-hunter.md +16 -0
  79. package/src/core-skills/v6-shims/bmad-editorial-review/SKILL.md +2 -0
  80. package/src/core-skills/v6-shims/bmad-editorial-review-prose/SKILL.md +2 -0
  81. package/src/core-skills/v6-shims/bmad-editorial-review-structure/SKILL.md +2 -0
  82. package/src/core-skills/v6-shims/bmad-review-adversarial-general/SKILL.md +2 -0
  83. package/src/core-skills/v6-shims/bmad-review-edge-case-hunter/SKILL.md +2 -0
  84. package/src/core-skills/v6-shims/bmad-review-verification-gap/SKILL.md +2 -0
  85. package/src/scripts/__pycache__/config_utils.cpython-311.pyc +0 -0
  86. package/src/scripts/tests/__pycache__/test_config_utils.cpython-311.pyc +0 -0
  87. package/src/scripts/tests/__pycache__/test_resolve_config.cpython-311.pyc +0 -0
  88. package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-311.pyc +0 -0
  89. package/tools/installer/commands/install.js +2 -0
  90. package/tools/installer/core/config.js +3 -0
  91. package/tools/installer/core/installer.js +57 -1
  92. package/tools/installer/core/manifest-generator.js +6 -0
  93. package/tools/installer/core/manifest.js +6 -0
  94. package/tools/installer/core/shim-policy.js +159 -0
  95. package/tools/installer/ide/_config-driven.js +3 -3
  96. package/tools/installer/ide/platform-codes.yaml +7 -0
  97. package/tools/installer/modules/official-modules.js +38 -6
  98. package/tools/installer/prompts.js +15 -2
  99. package/tools/installer/ui.js +68 -3
@@ -5,6 +5,7 @@ const prompts = require('../prompts');
5
5
  const { getProjectRoot, getSourcePath, getModulePath } = require('../project-root');
6
6
  const { CLIUtils } = require('../cli-utils');
7
7
  const { ExternalModuleManager } = require('./external-manager');
8
+ const { discoverShims } = require('../core/shim-policy');
8
9
 
9
10
  class OfficialModules {
10
11
  constructor(options = {}) {
@@ -131,6 +132,23 @@ class OfficialModules {
131
132
  return { modules };
132
133
  }
133
134
 
135
+ async discoverShims(moduleNames = [], options = {}) {
136
+ const shims = [];
137
+
138
+ for (const moduleName of moduleNames) {
139
+ const sourcePath = await this.findModuleSource(moduleName, {
140
+ silent: true,
141
+ channelOptions: options.channelOptions,
142
+ });
143
+ if (!sourcePath) continue;
144
+
145
+ const moduleShims = await discoverShims(sourcePath);
146
+ for (const shim of moduleShims) shims.push({ ...shim, module: moduleName });
147
+ }
148
+
149
+ return shims;
150
+ }
151
+
134
152
  /**
135
153
  * Get module information from a module path
136
154
  * @param {string} modulePath - Path to the module directory
@@ -296,9 +314,13 @@ class OfficialModules {
296
314
  `Aborting to avoid a partial install with no skills.`,
297
315
  );
298
316
  }
299
- await this._copyResolvedSkills(pluginResolution, targetPath, fileTrackingCallback, options.moduleConfig);
317
+ await this._copyResolvedSkills(pluginResolution, targetPath, fileTrackingCallback, options.moduleConfig, {
318
+ installShims: options.installShims,
319
+ });
300
320
  } else {
301
- await this.copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback, options.moduleConfig);
321
+ await this.copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback, options.moduleConfig, {
322
+ installShims: options.installShims,
323
+ });
302
324
  }
303
325
 
304
326
  if (!options.skipModuleInstaller) {
@@ -336,7 +358,7 @@ class OfficialModules {
336
358
  * @param {Function} fileTrackingCallback - Optional callback to track installed files
337
359
  * @param {Object} moduleConfig - Module configuration passed to copy filtering
338
360
  */
339
- async _copyResolvedSkills(resolved, targetPath, fileTrackingCallback = null, moduleConfig = {}) {
361
+ async _copyResolvedSkills(resolved, targetPath, fileTrackingCallback = null, moduleConfig = {}, installOptions = {}) {
340
362
  await fs.ensureDir(targetPath);
341
363
 
342
364
  // Copy each skill directory, flattened by leaf name. Leaf names must be
@@ -354,7 +376,7 @@ class OfficialModules {
354
376
  }
355
377
  seenLeaves.set(skillDirName, skillPath);
356
378
  const skillTarget = path.join(targetPath, skillDirName);
357
- await this.copyModuleWithFiltering(skillPath, skillTarget, fileTrackingCallback, moduleConfig);
379
+ await this.copyModuleWithFiltering(skillPath, skillTarget, fileTrackingCallback, moduleConfig, installOptions);
358
380
  }
359
381
 
360
382
  // Place module-help.csv at the module root.
@@ -385,7 +407,9 @@ class OfficialModules {
385
407
  await fs.remove(targetPath);
386
408
  }
387
409
 
388
- await this._copyResolvedSkills(resolved, targetPath, fileTrackingCallback, options.moduleConfig);
410
+ await this._copyResolvedSkills(resolved, targetPath, fileTrackingCallback, options.moduleConfig, {
411
+ installShims: options.installShims,
412
+ });
389
413
 
390
414
  // Create directories declared in module.yaml (strategies 1-4 may have these)
391
415
  if (!options.skipModuleInstaller) {
@@ -522,11 +546,19 @@ class OfficialModules {
522
546
  * @param {Function} fileTrackingCallback - Optional callback to track installed files
523
547
  * @param {Object} moduleConfig - Module configuration with conditional flags
524
548
  */
525
- async copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback = null, moduleConfig = {}) {
549
+ async copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback = null, moduleConfig = {}, installOptions = {}) {
526
550
  // Get all files in source
527
551
  const sourceFiles = await this.getFileList(sourcePath);
552
+ const shimDirectories =
553
+ installOptions.installShims === false
554
+ ? (await discoverShims(sourcePath)).map((shim) => shim.relativeDirectory.split(path.sep).join('/'))
555
+ : [];
528
556
 
529
557
  for (const file of sourceFiles) {
558
+ const normalizedFile = file.split(path.sep).join('/');
559
+ if (shimDirectories.some((shimDir) => shimDir === '' || normalizedFile === shimDir || normalizedFile.startsWith(`${shimDir}/`))) {
560
+ continue;
561
+ }
530
562
  // Skip sub-modules directory - these are IDE-specific and handled separately
531
563
  if (file.startsWith('sub-modules/')) {
532
564
  continue;
@@ -316,7 +316,9 @@ async function autocompleteMultiselect(options) {
316
316
 
317
317
  switch (this.state) {
318
318
  case 'submit': {
319
- return `${title}${color.gray(clack.S_BAR)} ${color.dim(`${this.selectedValues.length} items selected`)}`;
319
+ const count = this.selectedValues.length;
320
+ const emptyHint = count === 0 && options.emptyLabel ? ` (${options.emptyLabel})` : '';
321
+ return `${title}${color.gray(clack.S_BAR)} ${color.dim(`${count} item${count === 1 ? '' : 's'} selected${emptyHint}`)}`;
320
322
  }
321
323
 
322
324
  case 'cancel': {
@@ -331,7 +333,18 @@ async function autocompleteMultiselect(options) {
331
333
 
332
334
  const errorLine = this.state === 'error' ? [`${bar} ${color.yellow(this.error)}`] : [];
333
335
 
334
- const headerLines = [...`${title}${bar}`.split('\n'), `${bar} ${searchDisplay}${matchCount}`, ...noMatchesLine, ...errorLine];
336
+ const emptyLine =
337
+ this.selectedValues.length === 0 && options.emptyLabel
338
+ ? [`${bar} ${color.dim(`Nothing selected: installs ${options.emptyLabel}`)}`]
339
+ : [];
340
+
341
+ const headerLines = [
342
+ ...`${title}${bar}`.split('\n'),
343
+ `${bar} ${searchDisplay}${matchCount}`,
344
+ ...noMatchesLine,
345
+ ...errorLine,
346
+ ...emptyLine,
347
+ ];
335
348
 
336
349
  const footerLines = [`${bar} ${color.dim(hints.join(' • '))}`, `${barEnd}`];
337
350
 
@@ -17,6 +17,7 @@ const {
17
17
  const channelResolver = require('./modules/channel-resolver');
18
18
  const prompts = require('./prompts');
19
19
  const { parseSetEntries } = require('./set-overrides');
20
+ const { inferShimPreference, readInstalledSkillIds } = require('./core/shim-policy');
20
21
 
21
22
  const manifest = new Manifest();
22
23
 
@@ -110,6 +111,43 @@ async function getModuleVersion(moduleCode, { repoUrl = null, registryDefault =
110
111
  * UI utilities for the installer
111
112
  */
112
113
  class UI {
114
+ async _selectShimPreference({ selectedModules, bmadDir, existing, options, channelOptions, quickUpdate = false }) {
115
+ const { OfficialModules } = require('./modules/official-modules');
116
+ const officialModules = new OfficialModules({ channelOptions });
117
+ const availableShims = await officialModules.discoverShims(selectedModules, { channelOptions });
118
+
119
+ // The prompt is capability-driven. Once the last shim leaves the incoming
120
+ // release this becomes an ordinary empty set, regardless of old state.
121
+ if (availableShims.length === 0) return;
122
+
123
+ const previousManifest = existing ? await manifest.read(bmadDir) : null;
124
+ const installedSkillIds = existing ? await readInstalledSkillIds(bmadDir) : new Set();
125
+ const currentValue = inferShimPreference({
126
+ requested: options.shims,
127
+ persisted: previousManifest?.installShims,
128
+ availableShims,
129
+ installedSkillIds,
130
+ existing,
131
+ });
132
+
133
+ if (typeof options.shims === 'boolean' || options.yes) return currentValue;
134
+
135
+ // clack's confirm never resolves without a TTY: a scripted run would exit mid-install.
136
+ if (!process.stdin.isTTY) return currentValue;
137
+
138
+ // Nothing to give up, so nothing to ask on every single update.
139
+ if (quickUpdate && !currentValue) return currentValue;
140
+
141
+ const verb = currentValue ? 'Keep' : 'Install';
142
+ const message =
143
+ `${verb} ${availableShims.length} deprecated compatibility shim skill(s)? Recommended: No. ` +
144
+ `If you say yes, the deprecated skills will exist as a skill that forwards to its replacement skill. ` +
145
+ `Shims will be removed with v7. You should only retain if you customized a shimmed skill and need to ` +
146
+ `still transition it to the replacement.`;
147
+
148
+ return prompts.confirm({ message, default: currentValue });
149
+ }
150
+
113
151
  /**
114
152
  * Warn once for each selected module the registry marks deprecated.
115
153
  *
@@ -302,7 +340,7 @@ class UI {
302
340
  throw new Error('No valid actions available for this installation');
303
341
  }
304
342
  const hasQuickUpdate = choices.some((c) => c.value === 'quick-update');
305
- const needsFullUpdate = !!options.customSource;
343
+ const needsFullUpdate = !!options.customSource || typeof options.shims === 'boolean';
306
344
  actionType = hasQuickUpdate && !needsFullUpdate ? 'quick-update' : (choices.find((c) => c.value === 'update') || choices[0]).value;
307
345
  await prompts.log.info(`Non-interactive mode (--yes): defaulting to ${actionType}`);
308
346
  } else {
@@ -318,10 +356,21 @@ class UI {
318
356
  // Quick update never shows the module picker, so this is the only
319
357
  // place an existing install of a deprecated module hears about it.
320
358
  await this._warnDeprecatedModules(existingInstall.moduleIds || []);
359
+
360
+ const installShims = await this._selectShimPreference({
361
+ selectedModules: existingInstall.moduleIds || [],
362
+ bmadDir,
363
+ existing: true,
364
+ options,
365
+ channelOptions,
366
+ quickUpdate: true,
367
+ });
368
+
321
369
  return {
322
370
  actionType: 'quick-update',
323
371
  directory: confirmedDirectory,
324
372
  skipPrompts: options.yes || false,
373
+ installShims: installShims === undefined ? options.shims : installShims,
325
374
  };
326
375
  }
327
376
 
@@ -406,6 +455,13 @@ class UI {
406
455
  ...options,
407
456
  channelOptions,
408
457
  });
458
+ const installShims = await this._selectShimPreference({
459
+ selectedModules,
460
+ bmadDir,
461
+ existing: true,
462
+ options,
463
+ channelOptions,
464
+ });
409
465
 
410
466
  // Warn about --pin/--next flags that refer to modules the user didn't
411
467
  // select, or that target bundled modules (core/bmm) where channel
@@ -432,6 +488,7 @@ class UI {
432
488
  skipPrompts: options.yes || false,
433
489
  channelOptions,
434
490
  _preserveModules: preservedModules,
491
+ installShims,
435
492
  };
436
493
  }
437
494
  }
@@ -487,6 +544,13 @@ class UI {
487
544
  ...options,
488
545
  channelOptions,
489
546
  });
547
+ const installShims = await this._selectShimPreference({
548
+ selectedModules,
549
+ bmadDir,
550
+ existing: false,
551
+ options,
552
+ channelOptions,
553
+ });
490
554
 
491
555
  // Warn about --pin/--next flags that refer to modules the user didn't
492
556
  // select, or that target bundled modules (core/bmm) where channel
@@ -512,6 +576,7 @@ class UI {
512
576
  setOverrides,
513
577
  skipPrompts: options.yes || false,
514
578
  channelOptions,
579
+ installShims,
515
580
  };
516
581
  }
517
582
 
@@ -1071,9 +1136,9 @@ class UI {
1071
1136
  message: 'Select official modules to install:',
1072
1137
  options: allOptions,
1073
1138
  initialValues: initialValues.length > 0 ? initialValues : undefined,
1074
- // Not required: core is installed either way, so an empty selection is a
1075
- // legitimate "core only" install rather than a mistake to block on.
1139
+ // Core installs either way and is not a row here, so empty is a valid core-only install.
1076
1140
  required: false,
1141
+ emptyLabel: 'core only',
1077
1142
  maxItems: allOptions.length,
1078
1143
  });
1079
1144