bmad-method 6.0.5-next.8 → 6.1.0

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 (262) hide show
  1. package/package.json +1 -1
  2. package/src/bmm/agents/analyst.agent.yaml +1 -1
  3. package/src/bmm/module-help.csv +1 -1
  4. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +1 -1
  5. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +1 -1
  6. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +1 -1
  7. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +1 -1
  8. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +1 -1
  9. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +1 -1
  10. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +1 -1
  11. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +1 -1
  12. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +1 -1
  13. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +1 -1
  14. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +1 -1
  15. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +1 -1
  16. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +1 -1
  17. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +1 -1
  18. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +1 -1
  19. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +1 -1
  20. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +1 -1
  21. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +1 -1
  22. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +1 -1
  23. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +2 -2
  24. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +2 -2
  25. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +2 -2
  26. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +2 -2
  27. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +2 -2
  28. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +2 -2
  29. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +2 -2
  30. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +2 -2
  31. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +2 -2
  32. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +2 -2
  33. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +2 -2
  34. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +2 -2
  35. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +2 -2
  36. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +2 -2
  37. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +2 -2
  38. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +2 -2
  39. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +2 -2
  40. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md +31 -13
  41. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +1 -1
  42. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +6 -2
  43. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +1 -1
  44. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/templates/epics-template.md +4 -0
  45. package/src/bmm/workflows/4-implementation/code-review/workflow.md +4 -7
  46. package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/workflow.md +0 -4
  47. package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +1 -1
  48. package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +1 -1
  49. package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +1 -1
  50. package/src/core/module-help.csv +2 -2
  51. package/src/core/workflows/bmad-brainstorming/SKILL.md +6 -0
  52. package/src/core/workflows/bmad-brainstorming/bmad-skill-manifest.yaml +1 -0
  53. package/src/core/workflows/{brainstorming → bmad-brainstorming}/workflow.md +2 -5
  54. package/src/core/workflows/bmad-party-mode/SKILL.md +6 -0
  55. package/src/core/workflows/bmad-party-mode/bmad-skill-manifest.yaml +1 -0
  56. package/src/core/workflows/{party-mode → bmad-party-mode}/steps/step-03-graceful-exit.md +0 -1
  57. package/src/core/workflows/{party-mode → bmad-party-mode}/workflow.md +0 -4
  58. package/tools/cli/external-official-modules.yaml +18 -18
  59. package/tools/cli/installers/lib/core/installer.js +25 -8
  60. package/tools/cli/installers/lib/ide/_base-ide.js +0 -1
  61. package/tools/cli/installers/lib/ide/_config-driven.js +9 -4
  62. package/tools/cli/installers/lib/ide/manager.js +3 -3
  63. package/tools/cli/lib/agent/compiler.js +1 -1
  64. package/.augment/code_review_guidelines.yaml +0 -231
  65. package/.coderabbit.yaml +0 -85
  66. package/.github/CODE_OF_CONDUCT.md +0 -128
  67. package/.github/FUNDING.yaml +0 -15
  68. package/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -124
  69. package/.github/ISSUE_TEMPLATE/config.yaml +0 -8
  70. package/.github/ISSUE_TEMPLATE/documentation.yaml +0 -55
  71. package/.github/ISSUE_TEMPLATE/feature-request.md +0 -22
  72. package/.github/ISSUE_TEMPLATE/issue.md +0 -32
  73. package/.github/PULL_REQUEST_TEMPLATE.md +0 -13
  74. package/.github/scripts/discord-helpers.sh +0 -34
  75. package/.github/workflows/coderabbit-review.yaml +0 -22
  76. package/.github/workflows/discord.yaml +0 -90
  77. package/.github/workflows/docs.yaml +0 -64
  78. package/.github/workflows/publish.yaml +0 -133
  79. package/.github/workflows/quality.yaml +0 -116
  80. package/.husky/pre-commit +0 -20
  81. package/.markdownlint-cli2.yaml +0 -41
  82. package/.nvmrc +0 -1
  83. package/.prettierignore +0 -12
  84. package/.vscode/settings.json +0 -96
  85. package/CHANGELOG.md +0 -1785
  86. package/CNAME +0 -1
  87. package/CONTRIBUTING.md +0 -176
  88. package/CONTRIBUTORS.md +0 -32
  89. package/SECURITY.md +0 -85
  90. package/TRADEMARK.md +0 -55
  91. package/Wordmark.png +0 -0
  92. package/banner-bmad-method.png +0 -0
  93. package/docs/404.md +0 -9
  94. package/docs/_STYLE_GUIDE.md +0 -370
  95. package/docs/explanation/advanced-elicitation.md +0 -49
  96. package/docs/explanation/adversarial-review.md +0 -59
  97. package/docs/explanation/brainstorming.md +0 -33
  98. package/docs/explanation/established-projects-faq.md +0 -50
  99. package/docs/explanation/party-mode.md +0 -59
  100. package/docs/explanation/preventing-agent-conflicts.md +0 -112
  101. package/docs/explanation/project-context.md +0 -157
  102. package/docs/explanation/quick-dev-new-preview.md +0 -73
  103. package/docs/explanation/quick-flow.md +0 -77
  104. package/docs/explanation/why-solutioning-matters.md +0 -77
  105. package/docs/how-to/customize-bmad.md +0 -172
  106. package/docs/how-to/established-projects.md +0 -117
  107. package/docs/how-to/get-answers-about-bmad.md +0 -138
  108. package/docs/how-to/install-bmad.md +0 -116
  109. package/docs/how-to/non-interactive-installation.md +0 -171
  110. package/docs/how-to/project-context.md +0 -136
  111. package/docs/how-to/quick-fixes.md +0 -123
  112. package/docs/how-to/shard-large-documents.md +0 -78
  113. package/docs/how-to/upgrade-to-v6.md +0 -100
  114. package/docs/index.md +0 -60
  115. package/docs/reference/agents.md +0 -28
  116. package/docs/reference/commands.md +0 -145
  117. package/docs/reference/modules.md +0 -76
  118. package/docs/reference/testing.md +0 -106
  119. package/docs/reference/workflow-map.md +0 -89
  120. package/docs/roadmap.mdx +0 -136
  121. package/docs/tutorials/getting-started.md +0 -275
  122. package/docs/zh-cn/404.md +0 -9
  123. package/docs/zh-cn/_STYLE_GUIDE.md +0 -370
  124. package/docs/zh-cn/explanation/advanced-elicitation.md +0 -62
  125. package/docs/zh-cn/explanation/adversarial-review.md +0 -71
  126. package/docs/zh-cn/explanation/brainstorming.md +0 -43
  127. package/docs/zh-cn/explanation/established-projects-faq.md +0 -60
  128. package/docs/zh-cn/explanation/party-mode.md +0 -79
  129. package/docs/zh-cn/explanation/preventing-agent-conflicts.md +0 -137
  130. package/docs/zh-cn/explanation/project-context.md +0 -176
  131. package/docs/zh-cn/explanation/quick-flow.md +0 -93
  132. package/docs/zh-cn/explanation/why-solutioning-matters.md +0 -90
  133. package/docs/zh-cn/how-to/customize-bmad.md +0 -182
  134. package/docs/zh-cn/how-to/established-projects.md +0 -134
  135. package/docs/zh-cn/how-to/get-answers-about-bmad.md +0 -144
  136. package/docs/zh-cn/how-to/install-bmad.md +0 -105
  137. package/docs/zh-cn/how-to/non-interactive-installation.md +0 -181
  138. package/docs/zh-cn/how-to/project-context.md +0 -152
  139. package/docs/zh-cn/how-to/quick-fixes.md +0 -140
  140. package/docs/zh-cn/how-to/shard-large-documents.md +0 -86
  141. package/docs/zh-cn/how-to/upgrade-to-v6.md +0 -120
  142. package/docs/zh-cn/index.md +0 -69
  143. package/docs/zh-cn/reference/agents.md +0 -41
  144. package/docs/zh-cn/reference/commands.md +0 -166
  145. package/docs/zh-cn/reference/modules.md +0 -94
  146. package/docs/zh-cn/reference/testing.md +0 -122
  147. package/docs/zh-cn/reference/workflow-map.md +0 -104
  148. package/docs/zh-cn/roadmap.mdx +0 -152
  149. package/docs/zh-cn/tutorials/getting-started.md +0 -300
  150. package/eslint.config.mjs +0 -141
  151. package/prettier.config.mjs +0 -32
  152. package/src/core/workflows/brainstorming/bmad-skill-manifest.yaml +0 -3
  153. package/src/core/workflows/party-mode/bmad-skill-manifest.yaml +0 -3
  154. package/test/README.md +0 -295
  155. package/test/adversarial-review-tests/README.md +0 -56
  156. package/test/adversarial-review-tests/sample-content.md +0 -46
  157. package/test/adversarial-review-tests/test-cases.yaml +0 -103
  158. package/test/fixtures/agent-schema/invalid/critical-actions/actions-as-string.agent.yaml +0 -27
  159. package/test/fixtures/agent-schema/invalid/critical-actions/empty-string-in-actions.agent.yaml +0 -30
  160. package/test/fixtures/agent-schema/invalid/menu/empty-menu.agent.yaml +0 -22
  161. package/test/fixtures/agent-schema/invalid/menu/missing-menu.agent.yaml +0 -20
  162. package/test/fixtures/agent-schema/invalid/menu-commands/empty-command-target.agent.yaml +0 -25
  163. package/test/fixtures/agent-schema/invalid/menu-commands/no-command-target.agent.yaml +0 -24
  164. package/test/fixtures/agent-schema/invalid/menu-triggers/camel-case.agent.yaml +0 -25
  165. package/test/fixtures/agent-schema/invalid/menu-triggers/compound-invalid-format.agent.yaml +0 -25
  166. package/test/fixtures/agent-schema/invalid/menu-triggers/compound-mismatched-kebab.agent.yaml +0 -25
  167. package/test/fixtures/agent-schema/invalid/menu-triggers/duplicate-triggers.agent.yaml +0 -31
  168. package/test/fixtures/agent-schema/invalid/menu-triggers/empty-trigger.agent.yaml +0 -25
  169. package/test/fixtures/agent-schema/invalid/menu-triggers/leading-asterisk.agent.yaml +0 -25
  170. package/test/fixtures/agent-schema/invalid/menu-triggers/snake-case.agent.yaml +0 -25
  171. package/test/fixtures/agent-schema/invalid/menu-triggers/trigger-with-spaces.agent.yaml +0 -25
  172. package/test/fixtures/agent-schema/invalid/metadata/empty-module-string.agent.yaml +0 -26
  173. package/test/fixtures/agent-schema/invalid/metadata/empty-name.agent.yaml +0 -24
  174. package/test/fixtures/agent-schema/invalid/metadata/extra-metadata-fields.agent.yaml +0 -27
  175. package/test/fixtures/agent-schema/invalid/metadata/missing-id.agent.yaml +0 -23
  176. package/test/fixtures/agent-schema/invalid/persona/empty-principles-array.agent.yaml +0 -24
  177. package/test/fixtures/agent-schema/invalid/persona/empty-string-in-principles.agent.yaml +0 -27
  178. package/test/fixtures/agent-schema/invalid/persona/extra-persona-fields.agent.yaml +0 -27
  179. package/test/fixtures/agent-schema/invalid/persona/missing-role.agent.yaml +0 -24
  180. package/test/fixtures/agent-schema/invalid/prompts/empty-content.agent.yaml +0 -29
  181. package/test/fixtures/agent-schema/invalid/prompts/extra-prompt-fields.agent.yaml +0 -31
  182. package/test/fixtures/agent-schema/invalid/prompts/missing-content.agent.yaml +0 -28
  183. package/test/fixtures/agent-schema/invalid/prompts/missing-id.agent.yaml +0 -28
  184. package/test/fixtures/agent-schema/invalid/top-level/empty-file.agent.yaml +0 -5
  185. package/test/fixtures/agent-schema/invalid/top-level/extra-top-level-keys.agent.yaml +0 -28
  186. package/test/fixtures/agent-schema/invalid/top-level/missing-agent-key.agent.yaml +0 -11
  187. package/test/fixtures/agent-schema/invalid/yaml-errors/invalid-indentation.agent.yaml +0 -19
  188. package/test/fixtures/agent-schema/invalid/yaml-errors/malformed-yaml.agent.yaml +0 -18
  189. package/test/fixtures/agent-schema/valid/critical-actions/empty-critical-actions.agent.yaml +0 -24
  190. package/test/fixtures/agent-schema/valid/critical-actions/no-critical-actions.agent.yaml +0 -22
  191. package/test/fixtures/agent-schema/valid/critical-actions/valid-critical-actions.agent.yaml +0 -27
  192. package/test/fixtures/agent-schema/valid/menu/multiple-menu-items.agent.yaml +0 -31
  193. package/test/fixtures/agent-schema/valid/menu/single-menu-item.agent.yaml +0 -22
  194. package/test/fixtures/agent-schema/valid/menu-commands/all-command-types.agent.yaml +0 -38
  195. package/test/fixtures/agent-schema/valid/menu-commands/multiple-commands.agent.yaml +0 -23
  196. package/test/fixtures/agent-schema/valid/menu-triggers/compound-triggers.agent.yaml +0 -31
  197. package/test/fixtures/agent-schema/valid/menu-triggers/kebab-case-triggers.agent.yaml +0 -34
  198. package/test/fixtures/agent-schema/valid/metadata/core-agent-with-module.agent.yaml +0 -24
  199. package/test/fixtures/agent-schema/valid/metadata/empty-module-name-in-path.agent.yaml +0 -24
  200. package/test/fixtures/agent-schema/valid/metadata/malformed-path-treated-as-core.agent.yaml +0 -24
  201. package/test/fixtures/agent-schema/valid/metadata/module-agent-correct.agent.yaml +0 -24
  202. package/test/fixtures/agent-schema/valid/metadata/module-agent-missing-module.agent.yaml +0 -23
  203. package/test/fixtures/agent-schema/valid/metadata/wrong-module-value.agent.yaml +0 -24
  204. package/test/fixtures/agent-schema/valid/persona/complete-persona.agent.yaml +0 -24
  205. package/test/fixtures/agent-schema/valid/prompts/empty-prompts.agent.yaml +0 -24
  206. package/test/fixtures/agent-schema/valid/prompts/no-prompts.agent.yaml +0 -22
  207. package/test/fixtures/agent-schema/valid/prompts/valid-prompts-minimal.agent.yaml +0 -28
  208. package/test/fixtures/agent-schema/valid/prompts/valid-prompts-with-description.agent.yaml +0 -30
  209. package/test/fixtures/agent-schema/valid/top-level/minimal-core-agent.agent.yaml +0 -24
  210. package/test/fixtures/file-refs-csv/invalid/all-empty-workflow.csv +0 -3
  211. package/test/fixtures/file-refs-csv/invalid/empty-data.csv +0 -1
  212. package/test/fixtures/file-refs-csv/invalid/no-workflow-column.csv +0 -3
  213. package/test/fixtures/file-refs-csv/invalid/unresolvable-vars.csv +0 -3
  214. package/test/fixtures/file-refs-csv/valid/bmm-style.csv +0 -3
  215. package/test/fixtures/file-refs-csv/valid/core-style.csv +0 -3
  216. package/test/fixtures/file-refs-csv/valid/minimal.csv +0 -2
  217. package/test/test-agent-schema.js +0 -387
  218. package/test/test-cli-integration.sh +0 -159
  219. package/test/test-file-refs-csv.js +0 -133
  220. package/test/test-install-to-bmad.js +0 -154
  221. package/test/test-installation-components.js +0 -1796
  222. package/test/test-rehype-plugins.mjs +0 -1050
  223. package/test/test-workflow-path-regex.js +0 -88
  224. package/test/unit-test-schema.js +0 -133
  225. package/tools/build-docs.mjs +0 -464
  226. package/tools/docs/_prompt-external-modules-page.md +0 -59
  227. package/tools/docs/fix-refs.md +0 -91
  228. package/tools/docs/native-skills-migration-checklist.md +0 -281
  229. package/tools/fix-doc-links.js +0 -285
  230. package/tools/validate-agent-schema.js +0 -110
  231. package/tools/validate-doc-links.js +0 -407
  232. package/tools/validate-file-refs.js +0 -556
  233. package/website/README.md +0 -75
  234. package/website/astro.config.mjs +0 -157
  235. package/website/public/diagrams/quick-dev-diagram.png +0 -0
  236. package/website/public/favicon.ico +0 -0
  237. package/website/public/img/bmad-dark.png +0 -0
  238. package/website/public/img/bmad-light.png +0 -0
  239. package/website/public/workflow-map-diagram.html +0 -361
  240. package/website/src/components/Banner.astro +0 -62
  241. package/website/src/components/Header.astro +0 -96
  242. package/website/src/components/MobileMenuFooter.astro +0 -33
  243. package/website/src/content/config.ts +0 -7
  244. package/website/src/content/i18n/zh-CN.json +0 -28
  245. package/website/src/lib/site-url.mjs +0 -25
  246. package/website/src/pages/404.astro +0 -11
  247. package/website/src/pages/robots.txt.ts +0 -48
  248. package/website/src/rehype-base-paths.js +0 -112
  249. package/website/src/rehype-markdown-links.js +0 -119
  250. package/website/src/styles/custom.css +0 -805
  251. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/brain-methods.csv +0 -0
  252. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-01-session-setup.md +0 -0
  253. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-01b-continue.md +0 -0
  254. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02a-user-selected.md +0 -0
  255. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02b-ai-recommended.md +0 -0
  256. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02c-random-selection.md +0 -0
  257. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02d-progressive-flow.md +0 -0
  258. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-03-technique-execution.md +0 -0
  259. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-04-idea-organization.md +0 -0
  260. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/template.md +0 -0
  261. /package/src/core/workflows/{party-mode → bmad-party-mode}/steps/step-01-agent-loading.md +0 -0
  262. /package/src/core/workflows/{party-mode → bmad-party-mode}/steps/step-02-discussion-orchestration.md +0 -0
@@ -1,556 +0,0 @@
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
- const { parse: parseCsv } = require('csv-parse/sync');
33
-
34
- const PROJECT_ROOT = path.resolve(__dirname, '..');
35
- const SRC_DIR = path.join(PROJECT_ROOT, 'src');
36
- const VERBOSE = process.argv.includes('--verbose');
37
- const STRICT = process.argv.includes('--strict');
38
-
39
- // --- Constants ---
40
-
41
- // File extensions to scan
42
- const SCAN_EXTENSIONS = new Set(['.yaml', '.yml', '.md', '.xml', '.csv']);
43
-
44
- // Skip directories
45
- const SKIP_DIRS = new Set(['node_modules', '.git']);
46
-
47
- // Pattern: {project-root}/_bmad/ references
48
- const PROJECT_ROOT_REF = /\{project-root\}\/_bmad\/([^\s'"<>})\]`]+)/g;
49
-
50
- // Pattern: {_bmad}/ shorthand references
51
- const BMAD_SHORTHAND_REF = /\{_bmad\}\/([^\s'"<>})\]`]+)/g;
52
-
53
- // Pattern: exec="..." attributes
54
- const EXEC_ATTR = /exec="([^"]+)"/g;
55
-
56
- // Pattern: <invoke-task> content
57
- const INVOKE_TASK = /<invoke-task>([^<]+)<\/invoke-task>/g;
58
-
59
- // Pattern: relative paths in quotes
60
- const RELATIVE_PATH_QUOTED = /['"](\.\.\/?[^'"]+\.(?:md|yaml|yml|xml|json|csv|txt))['"]/g;
61
- const RELATIVE_PATH_DOT = /['"](\.\/[^'"]+\.(?:md|yaml|yml|xml|json|csv|txt))['"]/g;
62
-
63
- // Pattern: step metadata
64
- const STEP_META = /(?:thisStepFile|nextStepFile|continueStepFile|skipToStepFile|altStepFile|workflowFile):\s*['"](\.[^'"]+)['"]/g;
65
-
66
- // Pattern: Load directives
67
- const LOAD_DIRECTIVE = /Load[:\s]+`(\.[^`]+)`/g;
68
-
69
- // Pattern: absolute path leaks
70
- const ABS_PATH_LEAK = /(?:\/Users\/|\/home\/|[A-Z]:\\\\)/;
71
-
72
- // --- Output Escaping ---
73
-
74
- function escapeAnnotation(str) {
75
- return str.replaceAll('%', '%25').replaceAll('\r', '%0D').replaceAll('\n', '%0A');
76
- }
77
-
78
- function escapeTableCell(str) {
79
- return String(str).replaceAll('|', String.raw`\|`);
80
- }
81
-
82
- // Path prefixes/patterns that only exist in installed structure, not in source
83
- const INSTALL_ONLY_PATHS = ['_config/'];
84
-
85
- // Files that are generated at install time and don't exist in the source tree
86
- const INSTALL_GENERATED_FILES = ['config.yaml'];
87
-
88
- // Variables that indicate a path is not statically resolvable
89
- const UNRESOLVABLE_VARS = [
90
- '{output_folder}',
91
- '{value}',
92
- '{timestamp}',
93
- '{config_source}:',
94
- '{installed_path}',
95
- '{shared_path}',
96
- '{planning_artifacts}',
97
- '{research_topic}',
98
- '{user_name}',
99
- '{communication_language}',
100
- '{epic_number}',
101
- '{next_epic_num}',
102
- '{epic_num}',
103
- '{part_id}',
104
- '{count}',
105
- '{date}',
106
- '{outputFile}',
107
- '{nextStepFile}',
108
- ];
109
-
110
- // --- File Discovery ---
111
-
112
- function getSourceFiles(dir) {
113
- const files = [];
114
-
115
- function walk(currentDir) {
116
- const entries = fs.readdirSync(currentDir, { withFileTypes: true });
117
-
118
- for (const entry of entries) {
119
- if (SKIP_DIRS.has(entry.name)) continue;
120
-
121
- const fullPath = path.join(currentDir, entry.name);
122
-
123
- if (entry.isDirectory()) {
124
- walk(fullPath);
125
- } else if (entry.isFile() && SCAN_EXTENSIONS.has(path.extname(entry.name))) {
126
- files.push(fullPath);
127
- }
128
- }
129
- }
130
-
131
- walk(dir);
132
- return files;
133
- }
134
-
135
- // --- Code Block Stripping ---
136
-
137
- function stripCodeBlocks(content) {
138
- return content.replaceAll(/```[\s\S]*?```/g, (m) => m.replaceAll(/[^\n]/g, ''));
139
- }
140
-
141
- function stripJsonExampleBlocks(content) {
142
- // Strip bare JSON example blocks: { and } each on their own line.
143
- // These are example/template data (not real file references).
144
- return content.replaceAll(/^\{\s*\n(?:.*\n)*?^\}\s*$/gm, (m) => m.replaceAll(/[^\n]/g, ''));
145
- }
146
-
147
- // --- Path Mapping ---
148
-
149
- function mapInstalledToSource(refPath) {
150
- // Strip {project-root}/_bmad/ or {_bmad}/ prefix
151
- let cleaned = refPath.replace(/^\{project-root\}\/_bmad\//, '').replace(/^\{_bmad\}\//, '');
152
-
153
- // Also handle bare _bmad/ prefix (seen in some invoke-task)
154
- cleaned = cleaned.replace(/^_bmad\//, '');
155
-
156
- // Skip install-only paths (generated at install time, not in source)
157
- if (isInstallOnly(cleaned)) return null;
158
-
159
- // core/, bmm/, and utility/ are directly under src/
160
- if (cleaned.startsWith('core/') || cleaned.startsWith('bmm/') || cleaned.startsWith('utility/')) {
161
- return path.join(SRC_DIR, cleaned);
162
- }
163
-
164
- // Fallback: map directly under src/
165
- return path.join(SRC_DIR, cleaned);
166
- }
167
-
168
- // --- Reference Extraction ---
169
-
170
- function isResolvable(refStr) {
171
- // Skip refs containing unresolvable runtime variables
172
- if (refStr.includes('{{')) return false;
173
- for (const v of UNRESOLVABLE_VARS) {
174
- if (refStr.includes(v)) return false;
175
- }
176
- return true;
177
- }
178
-
179
- function isInstallOnly(cleanedPath) {
180
- // Skip paths that only exist in the installed _bmad/ structure, not in src/
181
- for (const prefix of INSTALL_ONLY_PATHS) {
182
- if (cleanedPath.startsWith(prefix)) return true;
183
- }
184
- // Skip files that are generated during installation
185
- const basename = path.basename(cleanedPath);
186
- for (const generated of INSTALL_GENERATED_FILES) {
187
- if (basename === generated) return true;
188
- }
189
- return false;
190
- }
191
-
192
- function extractYamlRefs(filePath, content) {
193
- const refs = [];
194
-
195
- let doc;
196
- try {
197
- doc = yaml.parseDocument(content);
198
- } catch {
199
- return refs; // Skip unparseable YAML (schema validator handles this)
200
- }
201
-
202
- function checkValue(value, range, keyPath) {
203
- if (typeof value !== 'string') return;
204
- if (!isResolvable(value)) return;
205
-
206
- const line = range ? offsetToLine(content, range[0]) : undefined;
207
-
208
- // Check for {project-root}/_bmad/ refs
209
- const prMatch = value.match(/\{project-root\}\/_bmad\/[^\s'"<>})\]`]+/);
210
- if (prMatch) {
211
- refs.push({ file: filePath, raw: prMatch[0], type: 'project-root', line, key: keyPath });
212
- }
213
-
214
- // Check for {_bmad}/ refs
215
- const bmMatch = value.match(/\{_bmad\}\/[^\s'"<>})\]`]+/);
216
- if (bmMatch) {
217
- refs.push({ file: filePath, raw: bmMatch[0], type: 'project-root', line, key: keyPath });
218
- }
219
-
220
- // Check for relative paths
221
- const relMatch = value.match(/^\.\.?\/[^\s'"<>})\]`]+\.(?:md|yaml|yml|xml|json|csv|txt)$/);
222
- if (relMatch) {
223
- refs.push({ file: filePath, raw: relMatch[0], type: 'relative', line, key: keyPath });
224
- }
225
- }
226
-
227
- function walkNode(node, keyPath) {
228
- if (!node) return;
229
-
230
- if (yaml.isMap(node)) {
231
- for (const item of node.items) {
232
- const key = item.key && item.key.value !== undefined ? item.key.value : '?';
233
- const childPath = keyPath ? `${keyPath}.${key}` : String(key);
234
- walkNode(item.value, childPath);
235
- }
236
- } else if (yaml.isSeq(node)) {
237
- for (const [i, item] of node.items.entries()) {
238
- walkNode(item, `${keyPath}[${i}]`);
239
- }
240
- } else if (yaml.isScalar(node)) {
241
- checkValue(node.value, node.range, keyPath);
242
- }
243
- }
244
-
245
- walkNode(doc.contents, '');
246
- return refs;
247
- }
248
-
249
- function offsetToLine(content, offset) {
250
- let line = 1;
251
- for (let i = 0; i < offset && i < content.length; i++) {
252
- if (content[i] === '\n') line++;
253
- }
254
- return line;
255
- }
256
-
257
- function extractMarkdownRefs(filePath, content) {
258
- const refs = [];
259
- const stripped = stripJsonExampleBlocks(stripCodeBlocks(content));
260
-
261
- function runPattern(regex, type) {
262
- regex.lastIndex = 0;
263
- let match;
264
- while ((match = regex.exec(stripped)) !== null) {
265
- const raw = match[1];
266
- if (!isResolvable(raw)) continue;
267
- refs.push({ file: filePath, raw, type, line: offsetToLine(stripped, match.index) });
268
- }
269
- }
270
-
271
- // {project-root}/_bmad/ refs
272
- runPattern(PROJECT_ROOT_REF, 'project-root');
273
-
274
- // {_bmad}/ shorthand
275
- runPattern(BMAD_SHORTHAND_REF, 'project-root');
276
-
277
- // exec="..." attributes
278
- runPattern(EXEC_ATTR, 'exec-attr');
279
-
280
- // <invoke-task> tags
281
- runPattern(INVOKE_TASK, 'invoke-task');
282
-
283
- // Step metadata
284
- runPattern(STEP_META, 'relative');
285
-
286
- // Load directives
287
- runPattern(LOAD_DIRECTIVE, 'relative');
288
-
289
- // Relative paths in quotes
290
- runPattern(RELATIVE_PATH_QUOTED, 'relative');
291
- runPattern(RELATIVE_PATH_DOT, 'relative');
292
-
293
- return refs;
294
- }
295
-
296
- function extractCsvRefs(filePath, content) {
297
- const refs = [];
298
-
299
- let records;
300
- try {
301
- records = parseCsv(content, {
302
- columns: true,
303
- skip_empty_lines: true,
304
- relax_column_count: true,
305
- });
306
- } catch (error) {
307
- // No CSV schema validator exists yet (planned as Layer 2c) — surface parse errors visibly.
308
- // YAML equivalent (line ~198) defers to validate-agent-schema.js; CSV has no such fallback.
309
- const rel = path.relative(PROJECT_ROOT, filePath);
310
- console.error(` [CSV-PARSE-ERROR] ${rel}: ${error.message}`);
311
- if (process.env.GITHUB_ACTIONS) {
312
- console.log(`::warning file=${rel},line=1::${escapeAnnotation(`CSV parse error: ${error.message}`)}`);
313
- }
314
- return refs;
315
- }
316
-
317
- // Only process if workflow-file column exists
318
- const firstRecord = records[0];
319
- if (!firstRecord || !('workflow-file' in firstRecord)) {
320
- return refs;
321
- }
322
-
323
- for (const [i, record] of records.entries()) {
324
- const raw = record['workflow-file'];
325
- if (!raw || raw.trim() === '') continue;
326
- if (!isResolvable(raw)) continue;
327
- // skill: prefixed references are resolved by the IDE/CLI, not as file paths
328
- if (raw.startsWith('skill:')) continue;
329
-
330
- // Line = header (1) + data row index (0-based) + 1
331
- const line = i + 2;
332
- refs.push({ file: filePath, raw, type: 'project-root', line });
333
- }
334
-
335
- return refs;
336
- }
337
-
338
- // --- Reference Resolution ---
339
-
340
- function resolveRef(ref) {
341
- if (ref.type === 'project-root') {
342
- return mapInstalledToSource(ref.raw);
343
- }
344
-
345
- if (ref.type === 'relative') {
346
- return path.resolve(path.dirname(ref.file), ref.raw);
347
- }
348
-
349
- if (ref.type === 'exec-attr') {
350
- let execPath = ref.raw;
351
- if (execPath.includes('{project-root}')) {
352
- return mapInstalledToSource(execPath);
353
- }
354
- if (execPath.includes('{_bmad}')) {
355
- return mapInstalledToSource(execPath);
356
- }
357
- if (execPath.startsWith('_bmad/')) {
358
- return mapInstalledToSource(execPath);
359
- }
360
- // Relative exec path
361
- return path.resolve(path.dirname(ref.file), execPath);
362
- }
363
-
364
- if (ref.type === 'invoke-task') {
365
- // Extract file path from invoke-task content
366
- const prMatch = ref.raw.match(/\{project-root\}\/_bmad\/([^\s'"<>})\]`]+)/);
367
- if (prMatch) return mapInstalledToSource(prMatch[0]);
368
-
369
- const bmMatch = ref.raw.match(/\{_bmad\}\/([^\s'"<>})\]`]+)/);
370
- if (bmMatch) return mapInstalledToSource(bmMatch[0]);
371
-
372
- const bareMatch = ref.raw.match(/_bmad\/([^\s'"<>})\]`]+)/);
373
- if (bareMatch) return mapInstalledToSource(bareMatch[0]);
374
-
375
- return null; // Can't resolve — skip
376
- }
377
-
378
- return null;
379
- }
380
-
381
- // --- Absolute Path Leak Detection ---
382
-
383
- function checkAbsolutePathLeaks(filePath, content) {
384
- const leaks = [];
385
- const stripped = stripCodeBlocks(content);
386
- const lines = stripped.split('\n');
387
-
388
- for (const [i, line] of lines.entries()) {
389
- if (ABS_PATH_LEAK.test(line)) {
390
- leaks.push({ file: filePath, line: i + 1, content: line.trim() });
391
- }
392
- }
393
-
394
- return leaks;
395
- }
396
-
397
- // --- Exports (for testing) ---
398
- module.exports = { extractCsvRefs };
399
-
400
- // --- Main ---
401
-
402
- if (require.main === module) {
403
- console.log(`\nValidating file references in: ${SRC_DIR}`);
404
- console.log(`Mode: ${STRICT ? 'STRICT (exit 1 on issues)' : 'WARNING (exit 0)'}${VERBOSE ? ' + VERBOSE' : ''}\n`);
405
-
406
- const files = getSourceFiles(SRC_DIR);
407
- console.log(`Found ${files.length} source files\n`);
408
-
409
- let totalRefs = 0;
410
- let brokenRefs = 0;
411
- let totalLeaks = 0;
412
- let filesWithIssues = 0;
413
- const allIssues = []; // Collect for $GITHUB_STEP_SUMMARY
414
-
415
- for (const filePath of files) {
416
- const relativePath = path.relative(PROJECT_ROOT, filePath);
417
- const content = fs.readFileSync(filePath, 'utf-8');
418
- const ext = path.extname(filePath);
419
-
420
- // Extract references
421
- let refs;
422
- if (ext === '.yaml' || ext === '.yml') {
423
- refs = extractYamlRefs(filePath, content);
424
- } else if (ext === '.csv') {
425
- refs = extractCsvRefs(filePath, content);
426
- } else {
427
- refs = extractMarkdownRefs(filePath, content);
428
- }
429
-
430
- // Resolve and classify all refs before printing anything.
431
- // This avoids the confusing pattern of printing headers at two different
432
- // times depending on verbosity — collect first, then print once.
433
- const broken = [];
434
- const ok = [];
435
-
436
- for (const ref of refs) {
437
- totalRefs++;
438
- const resolved = resolveRef(ref);
439
-
440
- if (resolved && !fs.existsSync(resolved)) {
441
- // Extensionless paths may be directory references or partial templates.
442
- // If the path has no extension, check whether it exists as a directory.
443
- // Flag it if nothing exists at all — likely a real broken reference.
444
- const hasExt = path.extname(resolved) !== '';
445
- if (!hasExt) {
446
- if (fs.existsSync(resolved)) {
447
- ok.push({ ref, tag: 'OK-DIR' });
448
- } else {
449
- // No extension and nothing exists — not a file, not a directory.
450
- // Flag as UNRESOLVED (distinct from BROKEN which means "file with extension not found").
451
- broken.push({ ref, resolved: path.relative(PROJECT_ROOT, resolved), kind: 'unresolved' });
452
- brokenRefs++;
453
- }
454
- continue;
455
- }
456
- broken.push({ ref, resolved: path.relative(PROJECT_ROOT, resolved), kind: 'broken' });
457
- brokenRefs++;
458
- continue;
459
- }
460
-
461
- if (resolved) {
462
- ok.push({ ref, tag: 'OK' });
463
- }
464
- }
465
-
466
- // Check absolute path leaks
467
- const leaks = checkAbsolutePathLeaks(filePath, content);
468
- totalLeaks += leaks.length;
469
-
470
- // Print results — file header appears once, in one place
471
- const hasFileIssues = broken.length > 0 || leaks.length > 0;
472
-
473
- if (hasFileIssues) {
474
- filesWithIssues++;
475
- console.log(`\n${relativePath}`);
476
-
477
- if (VERBOSE) {
478
- for (const { ref, tag, note } of ok) {
479
- const suffix = note ? ` (${note})` : '';
480
- console.log(` [${tag}] ${ref.raw}${suffix}`);
481
- }
482
- }
483
-
484
- for (const { ref, resolved, kind } of broken) {
485
- const location = ref.line ? `line ${ref.line}` : ref.key ? `key: ${ref.key}` : '';
486
- const tag = kind === 'unresolved' ? 'UNRESOLVED' : 'BROKEN';
487
- const detail = kind === 'unresolved' ? 'Not found as file or directory' : 'Target not found';
488
- const issueType = kind === 'unresolved' ? 'unresolved path' : 'broken ref';
489
- console.log(` [${tag}] ${ref.raw}${location ? ` (${location})` : ''}`);
490
- console.log(` ${detail}: ${resolved}`);
491
- allIssues.push({ file: relativePath, line: ref.line || 1, ref: ref.raw, issue: issueType });
492
- if (process.env.GITHUB_ACTIONS) {
493
- const line = ref.line || 1;
494
- console.log(
495
- `::warning file=${relativePath},line=${line}::${escapeAnnotation(`${tag === 'UNRESOLVED' ? 'Unresolved path' : 'Broken reference'}: ${ref.raw} → ${resolved}`)}`,
496
- );
497
- }
498
- }
499
-
500
- for (const leak of leaks) {
501
- console.log(` [ABS-PATH] Line ${leak.line}: ${leak.content}`);
502
- allIssues.push({ file: relativePath, line: leak.line, ref: leak.content, issue: 'abs-path' });
503
- if (process.env.GITHUB_ACTIONS) {
504
- console.log(`::warning file=${relativePath},line=${leak.line}::${escapeAnnotation(`Absolute path leak: ${leak.content}`)}`);
505
- }
506
- }
507
- } else if (VERBOSE && refs.length > 0) {
508
- console.log(`\n${relativePath}`);
509
- for (const { ref, tag, note } of ok) {
510
- const suffix = note ? ` (${note})` : '';
511
- console.log(` [${tag}] ${ref.raw}${suffix}`);
512
- }
513
- }
514
- }
515
-
516
- // Summary
517
- console.log(`\n${'─'.repeat(60)}`);
518
- console.log(`\nSummary:`);
519
- console.log(` Files scanned: ${files.length}`);
520
- console.log(` References checked: ${totalRefs}`);
521
- console.log(` Broken references: ${brokenRefs}`);
522
- console.log(` Absolute path leaks: ${totalLeaks}`);
523
-
524
- const hasIssues = brokenRefs > 0 || totalLeaks > 0;
525
-
526
- if (hasIssues) {
527
- console.log(`\n ${filesWithIssues} file(s) with issues`);
528
-
529
- if (STRICT) {
530
- console.log(`\n [STRICT MODE] Exiting with failure.`);
531
- } else {
532
- console.log(`\n Run with --strict to treat warnings as errors.`);
533
- }
534
- } else {
535
- console.log(`\n All file references valid!`);
536
- }
537
-
538
- console.log('');
539
-
540
- // Write GitHub Actions step summary
541
- if (process.env.GITHUB_STEP_SUMMARY) {
542
- let summary = '## File Reference Validation\n\n';
543
- if (allIssues.length > 0) {
544
- summary += '| File | Line | Reference | Issue |\n';
545
- summary += '|------|------|-----------|-------|\n';
546
- for (const issue of allIssues) {
547
- summary += `| ${escapeTableCell(issue.file)} | ${issue.line} | ${escapeTableCell(issue.ref)} | ${issue.issue} |\n`;
548
- }
549
- summary += '\n';
550
- }
551
- summary += `**${files.length} files scanned, ${totalRefs} references checked, ${brokenRefs + totalLeaks} issues found**\n`;
552
- fs.appendFileSync(process.env.GITHUB_STEP_SUMMARY, summary);
553
- }
554
-
555
- process.exit(hasIssues && STRICT ? 1 : 0);
556
- }
package/website/README.md DELETED
@@ -1,75 +0,0 @@
1
- # BMAD Method Documentation Site
2
-
3
- This directory contains the Astro + Starlight configuration for the BMAD Method documentation site.
4
-
5
- ## Architecture
6
-
7
- The documentation uses a symlink architecture to keep content in `docs/` at the repo root while serving it through Astro:
8
-
9
- ```
10
- bmad2/
11
- ├── docs/ # Content lives here (repo root)
12
- │ ├── index.md
13
- │ ├── tutorials/
14
- │ ├── how-to/
15
- │ ├── explanation/
16
- │ └── reference/
17
- └── website/
18
- ├── astro.config.mjs # Astro + Starlight config
19
- ├── src/
20
- │ ├── content/
21
- │ │ └── docs -> ../../docs # Symlink to content
22
- │ └── styles/
23
- │ └── custom.css # Custom styling
24
- └── public/ # Static assets
25
- ```
26
-
27
- ## Development
28
-
29
- ```bash
30
- # From repo root
31
- npm run docs:dev # Start dev server
32
- npm run docs:build # Build for production
33
- npm run docs:preview # Preview production build
34
- ```
35
-
36
- ## Platform Notes
37
-
38
- ### Windows Symlink Support
39
-
40
- The `website/src/content/docs` symlink may not work correctly on Windows without Developer Mode enabled or administrator privileges.
41
-
42
- **To enable symlinks on Windows:**
43
-
44
- 1. **Enable Developer Mode** (recommended):
45
- - Settings → Update & Security → For developers → Developer Mode: On
46
- - This allows creating symlinks without admin rights
47
-
48
- 2. **Or use Git's symlink support**:
49
- ```bash
50
- git config core.symlinks true
51
- ```
52
- Then re-clone the repository.
53
-
54
- 3. **Or create a junction** (alternative):
55
- ```cmd
56
- # Run as Administrator
57
- mklink /J website\src\content\docs ..\..\docs
58
- ```
59
-
60
- **If symlinks don't work**, you can copy the docs folder instead:
61
- ```bash
62
- # Remove the symlink
63
- rm website/src/content/docs
64
-
65
- # Copy the docs folder
66
- cp -r docs website/src/content/docs
67
- ```
68
-
69
- Note: If copying, remember to keep the copy in sync with changes to `docs/`.
70
-
71
- ## Build Output
72
-
73
- The build pipeline (`npm run docs:build`) produces:
74
- - Static HTML site in `build/site/`
75
- - LLM-friendly files: `llms.txt`, `llms-full.txt`