bmad-method 6.0.0-Beta.5 → 6.0.0-Beta.7

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 (119) hide show
  1. package/.claude/skills/changelog-social/SKILL.md +178 -0
  2. package/.claude/skills/changelog-social/examples/discord-example.md +53 -0
  3. package/.claude/skills/changelog-social/examples/linkedin-example.md +49 -0
  4. package/.claude/skills/changelog-social/examples/twitter-example.md +55 -0
  5. package/.claude/skills/changelog-social.skill +0 -0
  6. package/.claude/skills/draft-changelog/SKILL.md +2 -2
  7. package/.claude/skills/draft-changelog/prompts/instructions.md +25 -1
  8. package/.claude/skills/gh-triage/SKILL.md +1 -1
  9. package/.claude/skills/release-module/SKILL.md +1 -1
  10. package/.claude/skills/release-module/prompts/instructions.md +0 -4
  11. package/.github/workflows/quality.yaml +3 -0
  12. package/.vscode/settings.json +1 -2
  13. package/CHANGELOG.md +65 -1
  14. package/docs/bmgd/game-types.md +1 -0
  15. package/docs/bmgd/index.md +1 -1
  16. package/docs/bmgd/quick-flow-workflows.md +1 -0
  17. package/docs/reference/agents.md +22 -0
  18. package/docs/reference/commands.md +34 -0
  19. package/docs/reference/testing.md +21 -0
  20. package/docs/reference/workflow-map.md +1 -1
  21. package/package.json +5 -2
  22. package/src/bmm/agents/analyst.agent.yaml +11 -5
  23. package/src/bmm/agents/dev.agent.yaml +0 -1
  24. package/src/bmm/agents/pm.agent.yaml +3 -6
  25. package/src/bmm/agents/{quinn.agent.yaml → qa.agent.yaml} +3 -3
  26. package/src/bmm/module-help.csv +13 -20
  27. package/src/bmm/workflows/1-analysis/create-product-brief/workflow.md +0 -1
  28. package/src/bmm/workflows/1-analysis/research/workflow-domain-research.md +54 -0
  29. package/src/bmm/workflows/1-analysis/research/workflow-market-research.md +54 -0
  30. package/src/bmm/workflows/1-analysis/research/workflow-technical-research.md +54 -0
  31. package/src/bmm/workflows/2-plan-workflows/create-prd/data/domain-complexity.csv +2 -0
  32. package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +63 -0
  33. package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +65 -0
  34. package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +65 -0
  35. package/src/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +0 -1
  36. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +0 -1
  37. package/src/bmm/workflows/3-solutioning/create-architecture/data/domain-complexity.csv +2 -0
  38. package/src/bmm/workflows/3-solutioning/create-architecture/workflow.md +0 -1
  39. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +0 -1
  40. package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +0 -3
  41. package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +0 -4
  42. package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +0 -4
  43. package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +0 -4
  44. package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +0 -3
  45. package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +0 -4
  46. package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +0 -6
  47. package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +0 -1
  48. package/src/bmm/workflows/document-project/workflow.yaml +0 -8
  49. package/src/bmm/workflows/qa/automate/workflow.yaml +0 -2
  50. package/src/core/tasks/editorial-review-prose.xml +14 -12
  51. package/src/core/tasks/editorial-review-structure.xml +28 -28
  52. package/src/core/tasks/help.md +36 -16
  53. package/src/core/tasks/index-docs.xml +1 -1
  54. package/src/core/tasks/review-adversarial-general.xml +2 -2
  55. package/src/core/tasks/shard-doc.xml +1 -2
  56. package/src/core/tasks/workflow.xml +1 -1
  57. package/src/core/workflows/advanced-elicitation/workflow.xml +1 -1
  58. package/test/test-installation-components.js +1 -1
  59. package/tools/build-docs.js +21 -1
  60. package/tools/cli/bmad-cli.js +42 -3
  61. package/tools/cli/installers/lib/core/config-collector.js +5 -1
  62. package/tools/cli/installers/lib/core/dependency-resolver.js +1 -1
  63. package/tools/cli/installers/lib/core/installer.js +1 -6
  64. package/tools/cli/installers/lib/core/manifest-generator.js +149 -125
  65. package/tools/cli/installers/lib/custom/handler.js +1 -1
  66. package/tools/cli/installers/lib/ide/_base-ide.js +25 -15
  67. package/tools/cli/installers/lib/ide/_config-driven.js +79 -9
  68. package/tools/cli/installers/lib/ide/codex.js +7 -1
  69. package/tools/cli/installers/lib/ide/manager.js +8 -2
  70. package/tools/cli/installers/lib/ide/platform-codes.yaml +0 -3
  71. package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +2 -2
  72. package/tools/cli/installers/lib/ide/shared/bmad-artifacts.js +14 -3
  73. package/tools/cli/installers/lib/ide/shared/path-utils.js +9 -2
  74. package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +126 -29
  75. package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +2 -2
  76. package/tools/cli/installers/lib/ide/templates/combined/default-task.md +10 -0
  77. package/tools/cli/installers/lib/ide/templates/combined/default-tool.md +10 -0
  78. package/tools/cli/installers/lib/ide/templates/combined/gemini-task.toml +11 -0
  79. package/tools/cli/installers/lib/ide/templates/combined/gemini-tool.toml +11 -0
  80. package/tools/cli/installers/lib/modules/manager.js +3 -6
  81. package/tools/cli/lib/agent/installer.js +1 -1
  82. package/tools/cli/lib/prompts.js +192 -6
  83. package/tools/cli/lib/ui.js +124 -72
  84. package/tools/schema/agent.js +0 -1
  85. package/tools/validate-file-refs.js +480 -0
  86. package/website/astro.config.mjs +1 -35
  87. package/src/bmm/workflows/1-analysis/research/workflow.md +0 -173
  88. package/src/bmm/workflows/2-plan-workflows/create-prd/validation-report-prd-workflow.md +0 -433
  89. package/src/bmm/workflows/2-plan-workflows/create-prd/workflow.md +0 -150
  90. package/src/bmm/workflows/excalidraw-diagrams/_shared/excalidraw-library.json +0 -90
  91. package/src/bmm/workflows/excalidraw-diagrams/_shared/excalidraw-templates.yaml +0 -127
  92. package/src/bmm/workflows/excalidraw-diagrams/create-dataflow/checklist.md +0 -39
  93. package/src/bmm/workflows/excalidraw-diagrams/create-dataflow/instructions.md +0 -130
  94. package/src/bmm/workflows/excalidraw-diagrams/create-dataflow/workflow.yaml +0 -27
  95. package/src/bmm/workflows/excalidraw-diagrams/create-diagram/checklist.md +0 -43
  96. package/src/bmm/workflows/excalidraw-diagrams/create-diagram/instructions.md +0 -141
  97. package/src/bmm/workflows/excalidraw-diagrams/create-diagram/workflow.yaml +0 -27
  98. package/src/bmm/workflows/excalidraw-diagrams/create-flowchart/checklist.md +0 -49
  99. package/src/bmm/workflows/excalidraw-diagrams/create-flowchart/instructions.md +0 -241
  100. package/src/bmm/workflows/excalidraw-diagrams/create-flowchart/workflow.yaml +0 -27
  101. package/src/bmm/workflows/excalidraw-diagrams/create-wireframe/checklist.md +0 -38
  102. package/src/bmm/workflows/excalidraw-diagrams/create-wireframe/instructions.md +0 -133
  103. package/src/bmm/workflows/excalidraw-diagrams/create-wireframe/workflow.yaml +0 -27
  104. package/src/core/resources/excalidraw/README.md +0 -160
  105. package/src/core/resources/excalidraw/excalidraw-helpers.md +0 -127
  106. package/src/core/resources/excalidraw/library-loader.md +0 -50
  107. package/src/core/resources/excalidraw/validate-json-instructions.md +0 -79
  108. package/tools/flattener/aggregate.js +0 -76
  109. package/tools/flattener/binary.js +0 -80
  110. package/tools/flattener/discovery.js +0 -71
  111. package/tools/flattener/files.js +0 -35
  112. package/tools/flattener/ignoreRules.js +0 -172
  113. package/tools/flattener/main.js +0 -483
  114. package/tools/flattener/projectRoot.js +0 -201
  115. package/tools/flattener/prompts.js +0 -44
  116. package/tools/flattener/stats.helpers.js +0 -368
  117. package/tools/flattener/stats.js +0 -75
  118. package/tools/flattener/test-matrix.js +0 -409
  119. package/tools/flattener/xml.js +0 -82
@@ -0,0 +1,480 @@
1
+ /**
2
+ * File Reference Validator
3
+ *
4
+ * Validates cross-file references in BMAD source files (agents, workflows, tasks, steps).
5
+ * Catches broken file paths, missing referenced files, and absolute path leaks.
6
+ *
7
+ * What it checks:
8
+ * - {project-root}/_bmad/ references in YAML and markdown resolve to real src/ files
9
+ * - Relative path references (./file.md, ../data/file.csv) point to existing files
10
+ * - exec="..." and <invoke-task> targets exist
11
+ * - Step metadata (thisStepFile, nextStepFile) references are valid
12
+ * - Load directives (Load: `./file.md`) target existing files
13
+ * - No absolute paths (/Users/, /home/, C:\) leak into source files
14
+ *
15
+ * What it does NOT check (deferred):
16
+ * - {installed_path} variable interpolation (self-referential, low risk)
17
+ * - {{mustache}} template variables (runtime substitution)
18
+ * - {config_source}:key dynamic YAML dereferences
19
+ *
20
+ * Usage:
21
+ * node tools/validate-file-refs.js # Warn on broken references (exit 0)
22
+ * node tools/validate-file-refs.js --strict # Fail on broken references (exit 1)
23
+ * node tools/validate-file-refs.js --verbose # Show all checked references
24
+ *
25
+ * Default mode is warning-only (exit 0) so adoption is non-disruptive.
26
+ * Use --strict when you want CI or pre-commit to enforce valid references.
27
+ */
28
+
29
+ const fs = require('node:fs');
30
+ const path = require('node:path');
31
+ const yaml = require('yaml');
32
+
33
+ const PROJECT_ROOT = path.resolve(__dirname, '..');
34
+ const SRC_DIR = path.join(PROJECT_ROOT, 'src');
35
+ const VERBOSE = process.argv.includes('--verbose');
36
+ const STRICT = process.argv.includes('--strict');
37
+
38
+ // --- Constants ---
39
+
40
+ // File extensions to scan
41
+ const SCAN_EXTENSIONS = new Set(['.yaml', '.yml', '.md', '.xml']);
42
+
43
+ // Skip directories
44
+ const SKIP_DIRS = new Set(['node_modules', '_module-installer', '.git']);
45
+
46
+ // Pattern: {project-root}/_bmad/ references
47
+ const PROJECT_ROOT_REF = /\{project-root\}\/_bmad\/([^\s'"<>})\]`]+)/g;
48
+
49
+ // Pattern: {_bmad}/ shorthand references
50
+ const BMAD_SHORTHAND_REF = /\{_bmad\}\/([^\s'"<>})\]`]+)/g;
51
+
52
+ // Pattern: exec="..." attributes
53
+ const EXEC_ATTR = /exec="([^"]+)"/g;
54
+
55
+ // Pattern: <invoke-task> content
56
+ const INVOKE_TASK = /<invoke-task>([^<]+)<\/invoke-task>/g;
57
+
58
+ // Pattern: relative paths in quotes
59
+ const RELATIVE_PATH_QUOTED = /['"](\.\.\/?[^'"]+\.(?:md|yaml|yml|xml|json|csv|txt))['"]/g;
60
+ const RELATIVE_PATH_DOT = /['"](\.\/[^'"]+\.(?:md|yaml|yml|xml|json|csv|txt))['"]/g;
61
+
62
+ // Pattern: step metadata
63
+ const STEP_META = /(?:thisStepFile|nextStepFile|continueStepFile|skipToStepFile|altStepFile|workflowFile):\s*['"](\.[^'"]+)['"]/g;
64
+
65
+ // Pattern: Load directives
66
+ const LOAD_DIRECTIVE = /Load[:\s]+`(\.[^`]+)`/g;
67
+
68
+ // Pattern: absolute path leaks
69
+ const ABS_PATH_LEAK = /(?:\/Users\/|\/home\/|[A-Z]:\\\\)/;
70
+
71
+ // --- Output Escaping ---
72
+
73
+ function escapeAnnotation(str) {
74
+ return str.replaceAll('%', '%25').replaceAll('\r', '%0D').replaceAll('\n', '%0A');
75
+ }
76
+
77
+ function escapeTableCell(str) {
78
+ return String(str).replaceAll('|', String.raw`\|`);
79
+ }
80
+
81
+ // Path prefixes/patterns that only exist in installed structure, not in source
82
+ const INSTALL_ONLY_PATHS = ['_config/'];
83
+
84
+ // Files that are generated at install time and don't exist in the source tree
85
+ const INSTALL_GENERATED_FILES = ['config.yaml'];
86
+
87
+ // Variables that indicate a path is not statically resolvable
88
+ const UNRESOLVABLE_VARS = [
89
+ '{output_folder}',
90
+ '{value}',
91
+ '{timestamp}',
92
+ '{config_source}:',
93
+ '{installed_path}',
94
+ '{shared_path}',
95
+ '{planning_artifacts}',
96
+ '{research_topic}',
97
+ '{user_name}',
98
+ '{communication_language}',
99
+ '{epic_number}',
100
+ '{next_epic_num}',
101
+ '{epic_num}',
102
+ '{part_id}',
103
+ '{count}',
104
+ '{date}',
105
+ '{outputFile}',
106
+ '{nextStepFile}',
107
+ ];
108
+
109
+ // --- File Discovery ---
110
+
111
+ function getSourceFiles(dir) {
112
+ const files = [];
113
+
114
+ function walk(currentDir) {
115
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
116
+
117
+ for (const entry of entries) {
118
+ if (SKIP_DIRS.has(entry.name)) continue;
119
+
120
+ const fullPath = path.join(currentDir, entry.name);
121
+
122
+ if (entry.isDirectory()) {
123
+ walk(fullPath);
124
+ } else if (entry.isFile() && SCAN_EXTENSIONS.has(path.extname(entry.name))) {
125
+ files.push(fullPath);
126
+ }
127
+ }
128
+ }
129
+
130
+ walk(dir);
131
+ return files;
132
+ }
133
+
134
+ // --- Code Block Stripping ---
135
+
136
+ function stripCodeBlocks(content) {
137
+ return content.replaceAll(/```[\s\S]*?```/g, (m) => m.replaceAll(/[^\n]/g, ''));
138
+ }
139
+
140
+ function stripJsonExampleBlocks(content) {
141
+ // Strip bare JSON example blocks: { and } each on their own line.
142
+ // These are example/template data (not real file references).
143
+ return content.replaceAll(/^\{\s*\n(?:.*\n)*?^\}\s*$/gm, (m) => m.replaceAll(/[^\n]/g, ''));
144
+ }
145
+
146
+ // --- Path Mapping ---
147
+
148
+ function mapInstalledToSource(refPath) {
149
+ // Strip {project-root}/_bmad/ or {_bmad}/ prefix
150
+ let cleaned = refPath.replace(/^\{project-root\}\/_bmad\//, '').replace(/^\{_bmad\}\//, '');
151
+
152
+ // Also handle bare _bmad/ prefix (seen in some invoke-task)
153
+ cleaned = cleaned.replace(/^_bmad\//, '');
154
+
155
+ // Skip install-only paths (generated at install time, not in source)
156
+ if (isInstallOnly(cleaned)) return null;
157
+
158
+ // core/, bmm/, and utility/ are directly under src/
159
+ if (cleaned.startsWith('core/') || cleaned.startsWith('bmm/') || cleaned.startsWith('utility/')) {
160
+ return path.join(SRC_DIR, cleaned);
161
+ }
162
+
163
+ // Fallback: map directly under src/
164
+ return path.join(SRC_DIR, cleaned);
165
+ }
166
+
167
+ // --- Reference Extraction ---
168
+
169
+ function isResolvable(refStr) {
170
+ // Skip refs containing unresolvable runtime variables
171
+ if (refStr.includes('{{')) return false;
172
+ for (const v of UNRESOLVABLE_VARS) {
173
+ if (refStr.includes(v)) return false;
174
+ }
175
+ return true;
176
+ }
177
+
178
+ function isInstallOnly(cleanedPath) {
179
+ // Skip paths that only exist in the installed _bmad/ structure, not in src/
180
+ for (const prefix of INSTALL_ONLY_PATHS) {
181
+ if (cleanedPath.startsWith(prefix)) return true;
182
+ }
183
+ // Skip files that are generated during installation
184
+ const basename = path.basename(cleanedPath);
185
+ for (const generated of INSTALL_GENERATED_FILES) {
186
+ if (basename === generated) return true;
187
+ }
188
+ return false;
189
+ }
190
+
191
+ function extractYamlRefs(filePath, content) {
192
+ const refs = [];
193
+
194
+ let doc;
195
+ try {
196
+ doc = yaml.parseDocument(content);
197
+ } catch {
198
+ return refs; // Skip unparseable YAML (schema validator handles this)
199
+ }
200
+
201
+ function checkValue(value, range, keyPath) {
202
+ if (typeof value !== 'string') return;
203
+ if (!isResolvable(value)) return;
204
+
205
+ const line = range ? offsetToLine(content, range[0]) : undefined;
206
+
207
+ // Check for {project-root}/_bmad/ refs
208
+ const prMatch = value.match(/\{project-root\}\/_bmad\/[^\s'"<>})\]`]+/);
209
+ if (prMatch) {
210
+ refs.push({ file: filePath, raw: prMatch[0], type: 'project-root', line, key: keyPath });
211
+ }
212
+
213
+ // Check for {_bmad}/ refs
214
+ const bmMatch = value.match(/\{_bmad\}\/[^\s'"<>})\]`]+/);
215
+ if (bmMatch) {
216
+ refs.push({ file: filePath, raw: bmMatch[0], type: 'project-root', line, key: keyPath });
217
+ }
218
+
219
+ // Check for relative paths
220
+ const relMatch = value.match(/^\.\.?\/[^\s'"<>})\]`]+\.(?:md|yaml|yml|xml|json|csv|txt)$/);
221
+ if (relMatch) {
222
+ refs.push({ file: filePath, raw: relMatch[0], type: 'relative', line, key: keyPath });
223
+ }
224
+ }
225
+
226
+ function walkNode(node, keyPath) {
227
+ if (!node) return;
228
+
229
+ if (yaml.isMap(node)) {
230
+ for (const item of node.items) {
231
+ const key = item.key && item.key.value !== undefined ? item.key.value : '?';
232
+ const childPath = keyPath ? `${keyPath}.${key}` : String(key);
233
+ walkNode(item.value, childPath);
234
+ }
235
+ } else if (yaml.isSeq(node)) {
236
+ for (const [i, item] of node.items.entries()) {
237
+ walkNode(item, `${keyPath}[${i}]`);
238
+ }
239
+ } else if (yaml.isScalar(node)) {
240
+ checkValue(node.value, node.range, keyPath);
241
+ }
242
+ }
243
+
244
+ walkNode(doc.contents, '');
245
+ return refs;
246
+ }
247
+
248
+ function offsetToLine(content, offset) {
249
+ let line = 1;
250
+ for (let i = 0; i < offset && i < content.length; i++) {
251
+ if (content[i] === '\n') line++;
252
+ }
253
+ return line;
254
+ }
255
+
256
+ function extractMarkdownRefs(filePath, content) {
257
+ const refs = [];
258
+ const stripped = stripJsonExampleBlocks(stripCodeBlocks(content));
259
+
260
+ function runPattern(regex, type) {
261
+ regex.lastIndex = 0;
262
+ let match;
263
+ while ((match = regex.exec(stripped)) !== null) {
264
+ const raw = match[1];
265
+ if (!isResolvable(raw)) continue;
266
+ refs.push({ file: filePath, raw, type, line: offsetToLine(stripped, match.index) });
267
+ }
268
+ }
269
+
270
+ // {project-root}/_bmad/ refs
271
+ runPattern(PROJECT_ROOT_REF, 'project-root');
272
+
273
+ // {_bmad}/ shorthand
274
+ runPattern(BMAD_SHORTHAND_REF, 'project-root');
275
+
276
+ // exec="..." attributes
277
+ runPattern(EXEC_ATTR, 'exec-attr');
278
+
279
+ // <invoke-task> tags
280
+ runPattern(INVOKE_TASK, 'invoke-task');
281
+
282
+ // Step metadata
283
+ runPattern(STEP_META, 'relative');
284
+
285
+ // Load directives
286
+ runPattern(LOAD_DIRECTIVE, 'relative');
287
+
288
+ // Relative paths in quotes
289
+ runPattern(RELATIVE_PATH_QUOTED, 'relative');
290
+ runPattern(RELATIVE_PATH_DOT, 'relative');
291
+
292
+ return refs;
293
+ }
294
+
295
+ // --- Reference Resolution ---
296
+
297
+ function resolveRef(ref) {
298
+ if (ref.type === 'project-root') {
299
+ return mapInstalledToSource(ref.raw);
300
+ }
301
+
302
+ if (ref.type === 'relative') {
303
+ return path.resolve(path.dirname(ref.file), ref.raw);
304
+ }
305
+
306
+ if (ref.type === 'exec-attr') {
307
+ let execPath = ref.raw;
308
+ if (execPath.includes('{project-root}')) {
309
+ return mapInstalledToSource(execPath);
310
+ }
311
+ if (execPath.includes('{_bmad}')) {
312
+ return mapInstalledToSource(execPath);
313
+ }
314
+ if (execPath.startsWith('_bmad/')) {
315
+ return mapInstalledToSource(execPath);
316
+ }
317
+ // Relative exec path
318
+ return path.resolve(path.dirname(ref.file), execPath);
319
+ }
320
+
321
+ if (ref.type === 'invoke-task') {
322
+ // Extract file path from invoke-task content
323
+ const prMatch = ref.raw.match(/\{project-root\}\/_bmad\/([^\s'"<>})\]`]+)/);
324
+ if (prMatch) return mapInstalledToSource(prMatch[0]);
325
+
326
+ const bmMatch = ref.raw.match(/\{_bmad\}\/([^\s'"<>})\]`]+)/);
327
+ if (bmMatch) return mapInstalledToSource(bmMatch[0]);
328
+
329
+ const bareMatch = ref.raw.match(/_bmad\/([^\s'"<>})\]`]+)/);
330
+ if (bareMatch) return mapInstalledToSource(bareMatch[0]);
331
+
332
+ return null; // Can't resolve — skip
333
+ }
334
+
335
+ return null;
336
+ }
337
+
338
+ // --- Absolute Path Leak Detection ---
339
+
340
+ function checkAbsolutePathLeaks(filePath, content) {
341
+ const leaks = [];
342
+ const stripped = stripCodeBlocks(content);
343
+ const lines = stripped.split('\n');
344
+
345
+ for (const [i, line] of lines.entries()) {
346
+ if (ABS_PATH_LEAK.test(line)) {
347
+ leaks.push({ file: filePath, line: i + 1, content: line.trim() });
348
+ }
349
+ }
350
+
351
+ return leaks;
352
+ }
353
+
354
+ // --- Main ---
355
+
356
+ console.log(`\nValidating file references in: ${SRC_DIR}`);
357
+ console.log(`Mode: ${STRICT ? 'STRICT (exit 1 on issues)' : 'WARNING (exit 0)'}${VERBOSE ? ' + VERBOSE' : ''}\n`);
358
+
359
+ const files = getSourceFiles(SRC_DIR);
360
+ console.log(`Found ${files.length} source files\n`);
361
+
362
+ let totalRefs = 0;
363
+ let brokenRefs = 0;
364
+ let totalLeaks = 0;
365
+ let filesWithIssues = 0;
366
+ const allIssues = []; // Collect for $GITHUB_STEP_SUMMARY
367
+
368
+ for (const filePath of files) {
369
+ const relativePath = path.relative(PROJECT_ROOT, filePath);
370
+ const content = fs.readFileSync(filePath, 'utf-8');
371
+ const ext = path.extname(filePath);
372
+
373
+ // Extract references
374
+ let refs;
375
+ if (ext === '.yaml' || ext === '.yml') {
376
+ refs = extractYamlRefs(filePath, content);
377
+ } else {
378
+ refs = extractMarkdownRefs(filePath, content);
379
+ }
380
+
381
+ // Resolve and check
382
+ const broken = [];
383
+
384
+ if (VERBOSE && refs.length > 0) {
385
+ console.log(`\n${relativePath}`);
386
+ }
387
+
388
+ for (const ref of refs) {
389
+ totalRefs++;
390
+ const resolved = resolveRef(ref);
391
+
392
+ if (resolved && !fs.existsSync(resolved)) {
393
+ // For paths without extensions, also check if it's a directory
394
+ const hasExt = path.extname(resolved) !== '';
395
+ if (!hasExt) {
396
+ // Could be a directory reference — skip if not clearly a file
397
+ continue;
398
+ }
399
+ broken.push({ ref, resolved: path.relative(PROJECT_ROOT, resolved) });
400
+ brokenRefs++;
401
+ continue;
402
+ }
403
+
404
+ if (VERBOSE && resolved) {
405
+ console.log(` [OK] ${ref.raw}`);
406
+ }
407
+ }
408
+
409
+ // Check absolute path leaks
410
+ const leaks = checkAbsolutePathLeaks(filePath, content);
411
+ totalLeaks += leaks.length;
412
+
413
+ // Report issues for this file
414
+ if (broken.length > 0 || leaks.length > 0) {
415
+ filesWithIssues++;
416
+ if (!VERBOSE) {
417
+ console.log(`\n${relativePath}`);
418
+ }
419
+
420
+ for (const { ref, resolved } of broken) {
421
+ const location = ref.line ? `line ${ref.line}` : ref.key ? `key: ${ref.key}` : '';
422
+ console.log(` [BROKEN] ${ref.raw}${location ? ` (${location})` : ''}`);
423
+ console.log(` Target not found: ${resolved}`);
424
+ allIssues.push({ file: relativePath, line: ref.line || 1, ref: ref.raw, issue: 'broken ref' });
425
+ if (process.env.GITHUB_ACTIONS) {
426
+ const line = ref.line || 1;
427
+ console.log(`::warning file=${relativePath},line=${line}::${escapeAnnotation(`Broken reference: ${ref.raw} → ${resolved}`)}`);
428
+ }
429
+ }
430
+
431
+ for (const leak of leaks) {
432
+ console.log(` [ABS-PATH] Line ${leak.line}: ${leak.content}`);
433
+ allIssues.push({ file: relativePath, line: leak.line, ref: leak.content, issue: 'abs-path' });
434
+ if (process.env.GITHUB_ACTIONS) {
435
+ console.log(`::warning file=${relativePath},line=${leak.line}::${escapeAnnotation(`Absolute path leak: ${leak.content}`)}`);
436
+ }
437
+ }
438
+ }
439
+ }
440
+
441
+ // Summary
442
+ console.log(`\n${'─'.repeat(60)}`);
443
+ console.log(`\nSummary:`);
444
+ console.log(` Files scanned: ${files.length}`);
445
+ console.log(` References checked: ${totalRefs}`);
446
+ console.log(` Broken references: ${brokenRefs}`);
447
+ console.log(` Absolute path leaks: ${totalLeaks}`);
448
+
449
+ const hasIssues = brokenRefs > 0 || totalLeaks > 0;
450
+
451
+ if (hasIssues) {
452
+ console.log(`\n ${filesWithIssues} file(s) with issues`);
453
+
454
+ if (STRICT) {
455
+ console.log(`\n [STRICT MODE] Exiting with failure.`);
456
+ } else {
457
+ console.log(`\n Run with --strict to treat warnings as errors.`);
458
+ }
459
+ } else {
460
+ console.log(`\n All file references valid!`);
461
+ }
462
+
463
+ console.log('');
464
+
465
+ // Write GitHub Actions step summary
466
+ if (process.env.GITHUB_STEP_SUMMARY) {
467
+ let summary = '## File Reference Validation\n\n';
468
+ if (allIssues.length > 0) {
469
+ summary += '| File | Line | Reference | Issue |\n';
470
+ summary += '|------|------|-----------|-------|\n';
471
+ for (const issue of allIssues) {
472
+ summary += `| ${escapeTableCell(issue.file)} | ${issue.line} | ${escapeTableCell(issue.ref)} | ${issue.issue} |\n`;
473
+ }
474
+ summary += '\n';
475
+ }
476
+ summary += `**${files.length} files scanned, ${totalRefs} references checked, ${brokenRefs + totalLeaks} issues found**\n`;
477
+ fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, summary);
478
+ }
479
+
480
+ process.exit(hasIssues && STRICT ? 1 : 0);
@@ -110,41 +110,7 @@ export default defineConfig({
110
110
  collapsed: true,
111
111
  autogenerate: { directory: 'reference' },
112
112
  },
113
- {
114
- label: 'TEA - Testing in BMAD',
115
- collapsed: true,
116
- items: [
117
- {
118
- label: 'Tutorials',
119
- autogenerate: { directory: 'tea/tutorials' },
120
- },
121
- {
122
- label: 'How-To Guides',
123
- items: [
124
- {
125
- label: 'Workflows',
126
- autogenerate: { directory: 'tea/how-to/workflows' },
127
- },
128
- {
129
- label: 'Customization',
130
- autogenerate: { directory: 'tea/how-to/customization' },
131
- },
132
- {
133
- label: 'Brownfield',
134
- autogenerate: { directory: 'tea/how-to/brownfield' },
135
- },
136
- ],
137
- },
138
- {
139
- label: 'Explanation',
140
- autogenerate: { directory: 'tea/explanation' },
141
- },
142
- {
143
- label: 'Reference',
144
- autogenerate: { directory: 'tea/reference' },
145
- },
146
- ],
147
- },
113
+ // TEA docs moved to standalone module site; keep BMM sidebar focused.
148
114
  ],
149
115
 
150
116
  // Credits in footer
@@ -1,173 +0,0 @@
1
- ---
2
- name: research
3
- description: Conduct comprehensive research across multiple domains using current web data and verified sources - Market, Technical, Domain and other research types.
4
- web_bundle: true
5
- ---
6
-
7
- # Research Workflow
8
-
9
- **Goal:** Conduct comprehensive, exhaustive research across multiple domains using current web data and verified sources to produce complete research documents with compelling narratives and proper citations.
10
-
11
- **Document Standards:**
12
-
13
- - **Comprehensive Coverage**: Exhaustive research with no critical gaps
14
- - **Source Verification**: Every factual claim backed by web sources with URL citations
15
- - **Document Length**: As long as needed to fully cover the research topic
16
- - **Professional Structure**: Compelling narrative introduction, detailed TOC, and comprehensive summary
17
- - **Authoritative Sources**: Multiple independent sources for all critical claims
18
-
19
- **Your Role:** You are a research facilitator and web data analyst working with an expert partner. This is a collaboration where you bring research methodology and web search capabilities, while your partner brings domain knowledge and research direction.
20
-
21
- **Final Deliverable**: A complete research document that serves as an authoritative reference on the research topic with:
22
-
23
- - Compelling narrative introduction
24
- - Comprehensive table of contents
25
- - Detailed research sections with proper citations
26
- - Executive summary and conclusions
27
-
28
- ## WORKFLOW ARCHITECTURE
29
-
30
- This uses **micro-file architecture** with **routing-based discovery**:
31
-
32
- - Each research type has its own step folder
33
- - Step 01 discovers research type and routes to appropriate sub-workflow
34
- - Sequential progression within each research type
35
- - Document state tracked in output frontmatter
36
-
37
- ## INITIALIZATION
38
-
39
- ### Configuration Loading
40
-
41
- Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
42
-
43
- - `project_name`, `output_folder`, , `planning_artifacts`, `user_name`
44
- - `communication_language`, `document_output_language`, `user_skill_level`
45
- - `date` as a system-generated value
46
-
47
- ### Paths
48
-
49
- - `installed_path` = `{project-root}/_bmad/bmm/workflows/1-analysis/research`
50
- - `template_path` = `{installed_path}/research.template.md`
51
- - `default_output_file` = `{planning_artifacts}/research/{{research_type}}-{{topic}}-research-{{date}}.md` (dynamic based on research type)
52
-
53
- ## PREREQUISITE
54
-
55
- **⛔ Web search required.** If unavailable, abort and tell the user.
56
-
57
- ## RESEARCH BEHAVIOR
58
-
59
- ### Web Research Standards
60
-
61
- - **Current Data Only**: Search the web to verify and supplement your knowledge with current facts
62
- - **Source Verification**: Require citations for all factual claims
63
- - **Anti-Hallucination Protocol**: Never present information without verified sources
64
- - **Multiple Sources**: Require at least 2 independent sources for critical claims
65
- - **Conflict Resolution**: Present conflicting views and note discrepancies
66
- - **Confidence Levels**: Flag uncertain data with [High/Medium/Low Confidence]
67
-
68
- ### Source Quality Standards
69
-
70
- - **Distinguish Clearly**: Facts (from sources) vs Analysis (interpretation) vs Speculation
71
- - **URL Citation**: Always include source URLs when presenting web search data
72
- - **Critical Claims**: Market size, growth rates, competitive data need verification
73
- - **Fact Checking**: Apply fact-checking to critical data points
74
-
75
- ## Implementation Instructions
76
-
77
- Execute research type discovery and routing:
78
-
79
- ### Research Type Discovery
80
-
81
- **Your Role:** You are a research facilitator and web data analyst working with an expert partner. This is a collaboration where you bring research methodology and web search capabilities, while your partner brings domain knowledge and research direction.
82
-
83
- **Research Standards:**
84
-
85
- - **Anti-Hallucination Protocol**: Never present information without verified sources
86
- - **Current Data Only**: Search the web to verify and supplement your knowledge with current facts
87
- - **Source Citation**: Always include URLs for factual claims from web searches
88
- - **Multiple Sources**: Require 2+ independent sources for critical claims
89
- - **Conflict Resolution**: Present conflicting views and note discrepancies
90
- - **Confidence Levels**: Flag uncertain data with [High/Medium/Low Confidence]
91
-
92
- ### Collaborative Research Discovery
93
-
94
- "Welcome {{user_name}}! I'm excited to work with you as your research partner. I bring web research capabilities with rigorous source verification, while you bring the domain expertise and research direction.
95
-
96
- **Let me help you clarify what you'd like to research.**
97
-
98
- **First, tell me: What specific topic, problem, or area do you want to research?**
99
-
100
- For example:
101
-
102
- - 'The electric vehicle market in Europe'
103
- - 'Cloud migration strategies for healthcare'
104
- - 'AI implementation in financial services'
105
- - 'Sustainable packaging regulations'
106
- - 'Or anything else you have in mind...'
107
-
108
- ### Topic Exploration and Clarification
109
-
110
- Based on the user's initial topic, explore and refine the research scope:
111
-
112
- #### Topic Clarification Questions:
113
-
114
- 1. **Core Topic**: "What exactly about [topic] are you most interested in?"
115
- 2. **Research Goals**: "What do you hope to achieve with this research?"
116
- 3. **Scope**: "Should we focus broadly or dive deep into specific aspects?"
117
- 4. **Timeline**: "Are you looking at current state, historical context, or future trends?"
118
- 5. **Application**: "How will you use this research? (product development, strategy, academic, etc.)"
119
-
120
- #### Context Building:
121
-
122
- - **Initial Input**: User provides topic or research interest
123
- - **Collaborative Refinement**: Work together to clarify scope and objectives
124
- - **Goal Alignment**: Ensure research direction matches user needs
125
- - **Research Boundaries**: Establish clear focus areas and deliverables
126
-
127
- ### Research Type Identification
128
-
129
- After understanding the research topic and goals, identify the most appropriate research approach:
130
-
131
- **Research Type Options:**
132
-
133
- 1. **Market Research** - Market size, growth, competition, customer insights
134
- _Best for: Understanding market dynamics, customer behavior, competitive landscape_
135
-
136
- 2. **Domain Research** - Industry analysis, regulations, technology trends in specific domain
137
- _Best for: Understanding industry context, regulatory environment, ecosystem_
138
-
139
- 3. **Technical Research** - Technology evaluation, architecture decisions, implementation approaches
140
- _Best for: Technical feasibility, technology selection, implementation strategies_
141
-
142
- **Recommendation**: Based on [topic] and [goals], I recommend [suggested research type] because [specific rationale].
143
-
144
- **What type of research would work best for your needs?**
145
-
146
- ### Research Type Routing
147
-
148
- <critical>Based on user selection, route to appropriate sub-workflow with the discovered topic using the following IF block sets of instructions. YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`</critical>
149
-
150
- #### If Market Research:
151
-
152
- - Set `research_type = "market"`
153
- - Set `research_topic = [discovered topic from discussion]`
154
- - Create the starter output file: `{planning_artifacts}/research/market-{{research_topic}}-research-{{date}}.md` with exact copy of the ./research.template.md contents
155
- - Load: `./market-steps/step-01-init.md` with topic context
156
-
157
- #### If Domain Research:
158
-
159
- - Set `research_type = "domain"`
160
- - Set `research_topic = [discovered topic from discussion]`
161
- - Create the starter output file: `{planning_artifacts}/research/domain-{{research_topic}}-research-{{date}}.md` with exact copy of the ./research.template.md contents
162
- - Load: `./domain-steps/step-01-init.md` with topic context
163
-
164
- #### If Technical Research:
165
-
166
- - Set `research_type = "technical"`
167
- - Set `research_topic = [discovered topic from discussion]`
168
- - Create the starter output file: `{planning_artifacts}/research/technical-{{research_topic}}-research-{{date}}.md` with exact copy of the ./research.template.md contents
169
- - Load: `./technical-steps/step-01-init.md` with topic context
170
-
171
- **Important**: The discovered topic from the collaborative discussion should be passed to the research initialization steps, so they don't need to ask "What do you want to research?" again - they can focus on refining the scope for their specific research type.
172
-
173
- **Note:** All research workflows require web search for current data and source verification.