bmad-method 6.2.3-next.30 → 6.2.3-next.32

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "bmad-method",
4
- "version": "6.2.3-next.30",
4
+ "version": "6.2.3-next.32",
5
5
  "description": "Breakthrough Method of Agile AI-driven Development",
6
6
  "keywords": [
7
7
  "agile",
@@ -0,0 +1,62 @@
1
+ # Compile Epic Context
2
+
3
+ **Task**
4
+ Given an epic number, the epics file, the planning artifacts directory, and a desired output path, compile a clean, focused, developer-ready context file (`epic-<N>-context.md`).
5
+
6
+ **Steps**
7
+
8
+ 1. Read the epics file and extract the target epic's title, goal, and list of stories.
9
+ 2. Scan the planning artifacts directory for the standard files (PRD, architecture, UX/design, product brief).
10
+ 3. Pull only the information relevant to this epic.
11
+ 4. Write the compiled context to the exact output path using the format below.
12
+
13
+ ## Exact Output Format
14
+
15
+ Use these headings:
16
+
17
+ ```markdown
18
+ # Epic {N} Context: {Epic Title}
19
+
20
+ <!-- Compiled from planning artifacts. Edit freely. Regenerate with compile-epic-context if planning docs change. -->
21
+
22
+ ## Goal
23
+
24
+ {One clear paragraph: what this epic achieves and why it matters.}
25
+
26
+ ## Stories
27
+
28
+ - Story X.Y: Brief title only
29
+ - ...
30
+
31
+ ## Requirements & Constraints
32
+
33
+ {Relevant functional/non-functional requirements and success criteria for this epic (describe by purpose, not source).}
34
+
35
+ ## Technical Decisions
36
+
37
+ {Key architecture decisions, constraints, patterns, data models, and conventions relevant to this epic.}
38
+
39
+ ## UX & Interaction Patterns
40
+
41
+ {Relevant UX flows, interaction patterns, and design constraints (omit section entirely if nothing relevant).}
42
+
43
+ ## Cross-Story Dependencies
44
+
45
+ {Dependencies between stories in this epic or with other epics/systems (omit if none).}
46
+ ```
47
+
48
+ ## Rules
49
+
50
+ - **Scope aggressively.** Include only what a developer working on any story in this epic actually needs. When in doubt, leave it out — the developer can always read the full planning doc.
51
+ - **Describe by purpose, not by source.** Write "API responses must include pagination metadata" not "Per PRD section 3.2.1, pagination is required." Planning doc internals will change; the constraint won't.
52
+ - **No full copies.** Never quote source documents, section numbers, or paste large blocks verbatim. Always distill.
53
+ - **No story-level details.** The story list is for orientation only. Individual story specs handle the details.
54
+ - **Nothing derivable from the codebase.** Don't document what a developer can learn by reading the code.
55
+ - **Be concise and actionable.** Target 800–1500 tokens total. This file loads into quick-dev's context alongside other material.
56
+ - **Never hallucinate content.** If source material doesn't say something, don't invent it.
57
+ - **Omit empty sections entirely**, except Goal and Stories, which are always required.
58
+
59
+ ## Error handling
60
+
61
+ - **If the epics file is missing or the target epic is not found:** write nothing and report the problem to the calling agent. Goal and Stories cannot be populated without a usable epics file.
62
+ - **If planning artifacts are missing or empty:** still produce the file with Goal and Stories populated from the epics file, and note the gap in the Goal section. Never hallucinate content to fill missing sections.
@@ -41,19 +41,32 @@ Never ask extra questions if you already understand what the user intends.
41
41
  1. Load context.
42
42
  - List files in `{planning_artifacts}` and `{implementation_artifacts}`.
43
43
  - If you find an unformatted spec or intent file, ingest its contents to form your understanding of the intent.
44
- - Planning artifacts are the output of BMAD phases 1-3. Typical files include:
45
- - **PRD** (`*prd*`) — product requirements and success criteria
46
- - **Architecture** (`*architecture*`) technical design decisions and constraints
47
- - **UX/Design** (`*ux*`) — user experience and interaction design
48
- - **Epics** (`*epic*`) feature breakdown into implementable stories
49
- - **Product Brief** (`*brief*`) — project vision and scope
50
- - Scan the listing for files matching these patterns. If any look relevant to the current intent, load them selectively you don't need all of them, but you need the right constraints and requirements rather than guessing from code alone.
51
- - **Previous story continuity.** Using the intent and loaded context (especially any epics file), infer whether the current work is a story from an epic. Do not rely on filename patterns or regex — reason about the intent, the artifact listing, and epics content together. If the intent is an epic story:
52
- 1. Identify the epic and story number.
53
- 2. Scan `{implementation_artifacts}` for specs from the same epic with `status: done` and a lower story number.
54
- 3. Load the most recent one (highest story number below current).
55
- 4. Extract its **Code Map**, **Design Notes**, **Spec Change Log**, and **task list** as continuity context for step-02 planning.
56
- If no `done` spec is found but an `in-review` spec exists for the same epic with a lower story number, note it to the user and ask whether to load it. If the intent is not an epic story, or no previous spec exists, skip this silently.
44
+ - **Determine context strategy.** Using the intent and the artifact listing, infer whether the current work is a story from an epic. Do not rely on filename patterns or regex — reason about the intent, the listing, and any epics file content together.
45
+
46
+ **A) Epic story path** — if the intent is clearly an epic story:
47
+
48
+ 1. Identify the epic number and (if present) the story number. If you can't identify an epic number, use path B.
49
+
50
+ 2. **Check for a valid cached epic context.** Look for `{implementation_artifacts}/epic-<N>-context.md` (where `<N>` is the epic number). A file is **valid** when it exists, is non-empty, starts with `# Epic <N> Context:` (with the correct epic number), and no file in `{planning_artifacts}` is newer.
51
+ - **If valid:** load it as the primary planning context. Do not load raw planning docs (PRD, architecture, UX, etc.). Skip to step 5.
52
+ - **If missing, empty, or invalid:** continue to step 3.
53
+
54
+ 3. **Compile epic context.** Produce `{implementation_artifacts}/epic-<N>-context.md` by following `./compile-epic-context.md`, in order of preference:
55
+ - **Preferred — sub-agent:** spawn a sub-agent with `./compile-epic-context.md` as its prompt. Pass it the epic number, the epics file path, the `{planning_artifacts}` directory, and the output path `{implementation_artifacts}/epic-<N>-context.md`.
56
+ - **Fallback inline** (for runtimes without sub-agent support, e.g. Copilot, Codex, local Ollama, older Claude): if your runtime cannot spawn sub-agents, or the spawn fails/times out, read `./compile-epic-context.md` yourself and follow its instructions to produce the same output file.
57
+
58
+ 4. **Verify.** After compilation, verify the output file exists, is non-empty, and starts with `# Epic <N> Context:`. If valid, load it. If verification fails, HALT and report the failure.
59
+
60
+ 5. **Previous story continuity.** Regardless of which context source succeeded above, scan `{implementation_artifacts}` for specs from the same epic with `status: done` and a lower story number. Load the most recent one (highest story number below current). Extract its **Code Map**, **Design Notes**, **Spec Change Log**, and **task list** as continuity context for step-02 planning. If no `done` spec is found but an `in-review` spec exists for the same epic with a lower story number, note it to the user and ask whether to load it.
61
+
62
+ **B) Freeform path** — if the intent is not an epic story:
63
+ - Planning artifacts are the output of BMAD phases 1-3. Typical files include:
64
+ - **PRD** (`*prd*`) — product requirements and success criteria
65
+ - **Architecture** (`*architecture*`) — technical design decisions and constraints
66
+ - **UX/Design** (`*ux*`) — user experience and interaction design
67
+ - **Epics** (`*epic*`) — feature breakdown into implementable stories
68
+ - **Product Brief** (`*brief*`) — project vision and scope
69
+ - Scan the listing for files matching these patterns. If any look relevant to the current intent, load them selectively — you don't need all of them, but you need the right constraints and requirements rather than guessing from code alone.
57
70
  2. Clarify intent. Do not fantasize, do not leave open questions. If you must ask questions, ask them as a numbered list. When the human replies, verify that every single numbered question was answered. If any were ignored, HALT and re-ask only the missing questions before proceeding. Keep looping until intent is clear enough to implement.
58
71
  3. Version control sanity check. Is the working tree clean? Does the current branch make sense for this intent — considering its name and recent history? If the tree is dirty or the branch is an obvious mismatch, HALT and ask the human before proceeding. If version control is unavailable, skip this check.
59
72
  4. Multi-goal check (see SCOPE STANDARD). If the intent fails the single-goal criteria:
@@ -22,6 +22,7 @@ module.exports = {
22
22
  ['--communication-language <lang>', 'Language for agent communication (default: English)'],
23
23
  ['--document-output-language <lang>', 'Language for document output (default: English)'],
24
24
  ['--output-folder <path>', 'Output folder path relative to project root (default: _bmad-output)'],
25
+ ['--custom-source <sources>', 'Comma-separated Git URLs or local paths to install custom modules from'],
25
26
  ['-y, --yes', 'Accept all defaults and skip prompts where possible'],
26
27
  ],
27
28
  action: async (options) => {
@@ -569,6 +569,7 @@ class Installer {
569
569
  */
570
570
  async _installOfficialModules(config, paths, officialModuleIds, addResult, isQuickUpdate, officialModules, ctx) {
571
571
  const { message, installedModuleNames } = ctx;
572
+ const { CustomModuleManager } = require('../modules/custom-module-manager');
572
573
 
573
574
  for (const moduleName of officialModuleIds) {
574
575
  if (installedModuleNames.has(moduleName)) continue;
@@ -591,11 +592,15 @@ class Installer {
591
592
  },
592
593
  );
593
594
 
594
- // Get display name from source module.yaml; version from marketplace.json
595
+ // Get display name from source module.yaml; version from resolution cache or marketplace.json
595
596
  const sourcePath = await officialModules.findModuleSource(moduleName, { silent: true });
596
597
  const moduleInfo = sourcePath ? await officialModules.getModuleInfo(sourcePath, moduleName, '') : null;
597
598
  const displayName = moduleInfo?.name || moduleName;
598
- const version = sourcePath ? await this._getMarketplaceVersion(sourcePath) : '';
599
+
600
+ // Prefer version from resolution cache (accurate for custom/local modules),
601
+ // fall back to marketplace.json walk-up for official modules
602
+ const cachedResolution = CustomModuleManager._resolutionCache.get(moduleName);
603
+ const version = cachedResolution?.version || (sourcePath ? await this._getMarketplaceVersion(sourcePath) : '');
599
604
  addResult(displayName, 'ok', '', { moduleCode: moduleName, newVersion: version });
600
605
  }
601
606
  }
@@ -1189,7 +1194,7 @@ class Installer {
1189
1194
  const customMgr = new CustomModuleManager();
1190
1195
  for (const moduleId of installedModules) {
1191
1196
  if (!availableModules.some((m) => m.id === moduleId)) {
1192
- const customSource = await customMgr.findModuleSourceByCode(moduleId);
1197
+ const customSource = await customMgr.findModuleSourceByCode(moduleId, { bmadDir });
1193
1198
  if (customSource) {
1194
1199
  availableModules.push({
1195
1200
  id: moduleId,
@@ -412,7 +412,7 @@ class ManifestGenerator {
412
412
  // Get existing install date if available
413
413
  const existing = existingModulesMap.get(moduleName);
414
414
 
415
- updatedModules.push({
415
+ const moduleEntry = {
416
416
  name: moduleName,
417
417
  version: versionInfo.version,
418
418
  installDate: existing?.installDate || new Date().toISOString(),
@@ -420,7 +420,9 @@ class ManifestGenerator {
420
420
  source: versionInfo.source,
421
421
  npmPackage: versionInfo.npmPackage,
422
422
  repoUrl: versionInfo.repoUrl,
423
- });
423
+ };
424
+ if (versionInfo.localPath) moduleEntry.localPath = versionInfo.localPath;
425
+ updatedModules.push(moduleEntry);
424
426
  }
425
427
 
426
428
  const manifest = {
@@ -181,10 +181,10 @@ class Manifest {
181
181
 
182
182
  // Handle adding a new module with version info
183
183
  if (updates.addModule) {
184
- const { name, version, source, npmPackage, repoUrl } = updates.addModule;
184
+ const { name, version, source, npmPackage, repoUrl, localPath } = updates.addModule;
185
185
  const existing = manifest.modules.find((m) => m.name === name);
186
186
  if (!existing) {
187
- manifest.modules.push({
187
+ const entry = {
188
188
  name,
189
189
  version: version || null,
190
190
  installDate: new Date().toISOString(),
@@ -192,7 +192,9 @@ class Manifest {
192
192
  source: source || 'external',
193
193
  npmPackage: npmPackage || null,
194
194
  repoUrl: repoUrl || null,
195
- });
195
+ };
196
+ if (localPath) entry.localPath = localPath;
197
+ manifest.modules.push(entry);
196
198
  }
197
199
  }
198
200
 
@@ -280,7 +282,7 @@ class Manifest {
280
282
 
281
283
  if (existingIndex === -1) {
282
284
  // Module doesn't exist, add it
283
- manifest.modules.push({
285
+ const entry = {
284
286
  name: moduleName,
285
287
  version: options.version || null,
286
288
  installDate: new Date().toISOString(),
@@ -288,7 +290,9 @@ class Manifest {
288
290
  source: options.source || 'unknown',
289
291
  npmPackage: options.npmPackage || null,
290
292
  repoUrl: options.repoUrl || null,
291
- });
293
+ };
294
+ if (options.localPath) entry.localPath = options.localPath;
295
+ manifest.modules.push(entry);
292
296
  } else {
293
297
  // Module exists, update its version info
294
298
  const existing = manifest.modules[existingIndex];
@@ -298,6 +302,7 @@ class Manifest {
298
302
  source: options.source || existing.source,
299
303
  npmPackage: options.npmPackage === undefined ? existing.npmPackage : options.npmPackage,
300
304
  repoUrl: options.repoUrl === undefined ? existing.repoUrl : options.repoUrl,
305
+ localPath: options.localPath === undefined ? existing.localPath : options.localPath,
301
306
  lastUpdated: new Date().toISOString(),
302
307
  };
303
308
  }
@@ -832,17 +837,19 @@ class Manifest {
832
837
  };
833
838
  }
834
839
 
835
- // Check if this is a custom module (from user-provided URL)
840
+ // Check if this is a custom module (from user-provided URL or local path)
836
841
  const { CustomModuleManager } = require('../modules/custom-module-manager');
837
842
  const customMgr = new CustomModuleManager();
838
- const customSource = await customMgr.findModuleSourceByCode(moduleName);
839
- if (customSource) {
840
- const customVersion = await this._readMarketplaceVersion(moduleName, moduleSourcePath);
843
+ const resolved = customMgr.getResolution(moduleName);
844
+ const customSource = await customMgr.findModuleSourceByCode(moduleName, { bmadDir });
845
+ if (customSource || resolved) {
846
+ const customVersion = resolved?.version || (await this._readMarketplaceVersion(moduleName, moduleSourcePath));
841
847
  return {
842
848
  version: customVersion,
843
849
  source: 'custom',
844
850
  npmPackage: null,
845
- repoUrl: null,
851
+ repoUrl: resolved?.repoUrl || null,
852
+ localPath: resolved?.localPath || null,
846
853
  };
847
854
  }
848
855