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,285 +0,0 @@
1
- /**
2
- * Fix Documentation Links
3
- *
4
- * Converts relative markdown links to repo-relative paths with .md extension.
5
- * This ensures links work both in GitHub and on the Astro/Starlight site
6
- * (the rehype plugin transforms /docs/path/file.md → /path/file/ at build time).
7
- *
8
- * - ./file.md → /docs/current/path/file.md
9
- * - ../other/file.md → /docs/resolved/path/file.md
10
- * - /path/file/ → /docs/path/file.md (or /docs/path/file/index.md if it's a directory)
11
- *
12
- * Usage:
13
- * node tools/fix-doc-links.js # Dry run (shows what would change)
14
- * node tools/fix-doc-links.js --write # Actually write changes
15
- */
16
-
17
- const fs = require('node:fs');
18
- const path = require('node:path');
19
-
20
- const DOCS_ROOT = path.resolve(__dirname, '../docs');
21
- const DRY_RUN = !process.argv.includes('--write');
22
-
23
- // Match all markdown links; filtering (external, anchors, assets) happens in convertToRepoRelative.
24
- // This intentionally matches broadly so the handler can make context-aware decisions.
25
- const ALL_MARKDOWN_LINKS_REGEX = /\[([^\]]*)\]\(([^)]+)\)/g;
26
-
27
- /**
28
- * Get all markdown files in docs directory, excluding _* directories/files
29
- */
30
- function getMarkdownFiles(dir) {
31
- const files = [];
32
-
33
- function walk(currentDir) {
34
- const entries = fs.readdirSync(currentDir, { withFileTypes: true });
35
-
36
- for (const entry of entries) {
37
- const fullPath = path.join(currentDir, entry.name);
38
-
39
- // Skip underscore-prefixed entries
40
- if (entry.name.startsWith('_')) {
41
- continue;
42
- }
43
-
44
- if (entry.isDirectory()) {
45
- walk(fullPath);
46
- } else if (entry.isFile() && entry.name.endsWith('.md')) {
47
- files.push(fullPath);
48
- }
49
- }
50
- }
51
-
52
- walk(dir);
53
- return files;
54
- }
55
-
56
- /**
57
- * Convert a markdown link href to repo-relative path with .md extension
58
- *
59
- * @param {string} href - The original href (e.g., "./file.md", "/path/to/page/", "/path/to/page/#anchor")
60
- * @param {string} currentFilePath - Absolute path to the file containing this link
61
- * @returns {string|null} - Repo-relative path (e.g., "/docs/path/to/file.md"), or null if shouldn't be converted
62
- */
63
- function convertToRepoRelative(href, currentFilePath) {
64
- // Skip external links (including protocol-relative URLs like //cdn.example.com)
65
- if (href.includes('://') || href.startsWith('//') || href.startsWith('mailto:') || href.startsWith('tel:')) {
66
- return null;
67
- }
68
-
69
- // Skip anchor-only links
70
- if (href.startsWith('#')) {
71
- return null;
72
- }
73
-
74
- // Extract anchor and query string if present
75
- let anchor = '';
76
- let query = '';
77
- let pathPortion = href;
78
-
79
- const hashIndex = href.indexOf('#');
80
- const queryIndex = href.indexOf('?');
81
-
82
- if (hashIndex !== -1 || queryIndex !== -1) {
83
- const firstDelimiter = Math.min(hashIndex === -1 ? Infinity : hashIndex, queryIndex === -1 ? Infinity : queryIndex);
84
- pathPortion = href.slice(0, Math.max(0, firstDelimiter));
85
-
86
- const suffix = href.slice(Math.max(0, firstDelimiter));
87
- const anchorInSuffix = suffix.indexOf('#');
88
-
89
- if (suffix.startsWith('?')) {
90
- if (anchorInSuffix === -1) {
91
- query = suffix;
92
- } else {
93
- query = suffix.slice(0, Math.max(0, anchorInSuffix));
94
- anchor = suffix.slice(Math.max(0, anchorInSuffix));
95
- }
96
- } else {
97
- anchor = suffix;
98
- }
99
- }
100
-
101
- // Skip non-documentation links (images, external assets, etc.)
102
- const ext = path.extname(pathPortion).toLowerCase();
103
- if (
104
- ext &&
105
- ext !== '.md' &&
106
- !['.md'].includes(ext) && // Has an extension that's not .md - skip unless it's a trailing slash path
107
- !pathPortion.endsWith('/')
108
- ) {
109
- return null;
110
- }
111
-
112
- // Check if original path ends with / (directory reference) BEFORE path.join normalizes it
113
- const isDirectoryPath = pathPortion.endsWith('/');
114
-
115
- let absolutePath;
116
-
117
- if (pathPortion.startsWith('/docs/')) {
118
- // Already repo-relative with /docs/ prefix
119
- absolutePath = path.join(path.dirname(DOCS_ROOT), pathPortion);
120
- } else if (pathPortion.startsWith('/')) {
121
- // Site-relative (e.g., /tutorials/getting-started/) - resolve from docs root
122
- absolutePath = path.join(DOCS_ROOT, pathPortion);
123
- } else {
124
- // Relative path (./, ../, or bare filename) - resolve from current file's directory
125
- const currentDir = path.dirname(currentFilePath);
126
- absolutePath = path.resolve(currentDir, pathPortion);
127
- }
128
-
129
- // Convert to repo-relative path (with /docs/ prefix)
130
- let repoRelative = '/docs/' + path.relative(DOCS_ROOT, absolutePath);
131
-
132
- // Normalize path separators for Windows
133
- repoRelative = repoRelative.split(path.sep).join('/');
134
-
135
- // If original path was a directory reference (ended with /), check for index.md or file.md
136
- if (isDirectoryPath) {
137
- const relativeDir = repoRelative.slice(6); // Remove '/docs/'
138
-
139
- // Handle root path case (relativeDir is empty or just '.')
140
- const normalizedDir = relativeDir === '' || relativeDir === '.' ? '' : relativeDir;
141
- const indexPath = path.join(DOCS_ROOT, normalizedDir, 'index.md');
142
- const filePath = normalizedDir ? path.join(DOCS_ROOT, normalizedDir + '.md') : null;
143
-
144
- if (fs.existsSync(indexPath)) {
145
- // Avoid double slash when repoRelative is '/docs/' (root case)
146
- repoRelative = repoRelative.endsWith('/') ? repoRelative + 'index.md' : repoRelative + '/index.md';
147
- } else if (filePath && fs.existsSync(filePath)) {
148
- repoRelative = repoRelative + '.md';
149
- } else {
150
- // Neither exists - default to index.md and let validation catch it
151
- repoRelative = repoRelative.endsWith('/') ? repoRelative + 'index.md' : repoRelative + '/index.md';
152
- }
153
- } else if (!repoRelative.endsWith('.md')) {
154
- // Path doesn't end with .md - add .md
155
- repoRelative = repoRelative + '.md';
156
- }
157
-
158
- return repoRelative + query + anchor;
159
- }
160
-
161
- /**
162
- * Process a single markdown file, skipping links inside fenced code blocks
163
- *
164
- * @param {string} filePath - Absolute path to the file
165
- * @returns {Object} - { changed: boolean, original: string, updated: string, changes: Array }
166
- */
167
- function processFile(filePath) {
168
- const original = fs.readFileSync(filePath, 'utf-8');
169
- const changes = [];
170
-
171
- // Extract fenced code blocks and replace with placeholders
172
- const codeBlocks = [];
173
- const CODE_PLACEHOLDER = '\u0000CODE_BLOCK_';
174
-
175
- let contentWithPlaceholders = original.replaceAll(/```[\s\S]*?```/g, (match) => {
176
- const index = codeBlocks.length;
177
- codeBlocks.push(match);
178
- return `${CODE_PLACEHOLDER}${index}\u0000`;
179
- });
180
-
181
- // Process links only in non-code-block content
182
- contentWithPlaceholders = contentWithPlaceholders.replaceAll(ALL_MARKDOWN_LINKS_REGEX, (match, linkText, href) => {
183
- const newHref = convertToRepoRelative(href, filePath);
184
-
185
- // Skip if conversion returned null (external link, anchor, etc.)
186
- if (newHref === null) {
187
- return match;
188
- }
189
-
190
- // Only record as change if actually different
191
- if (newHref !== href) {
192
- changes.push({ from: href, to: newHref });
193
- return `[${linkText}](${newHref})`;
194
- }
195
-
196
- return match;
197
- });
198
-
199
- // Restore code blocks
200
- const updated = contentWithPlaceholders.replaceAll(
201
- new RegExp(`${CODE_PLACEHOLDER}(\\d+)\u0000`, 'g'),
202
- (match, index) => codeBlocks[parseInt(index, 10)],
203
- );
204
-
205
- return {
206
- changed: changes.length > 0,
207
- original,
208
- updated,
209
- changes,
210
- };
211
- }
212
-
213
- /**
214
- * Validate that a repo-relative link points to an existing file
215
- */
216
- function validateLink(repoRelativePath) {
217
- // Strip anchor/query
218
- const checkPath = repoRelativePath.split('#')[0].split('?')[0];
219
-
220
- // Remove /docs/ prefix to get path relative to DOCS_ROOT
221
- const relativePath = checkPath.startsWith('/docs/') ? checkPath.slice(6) : checkPath.slice(1);
222
-
223
- return fs.existsSync(path.join(DOCS_ROOT, relativePath));
224
- }
225
-
226
- // Main execution
227
- console.log(`\nScanning docs in: ${DOCS_ROOT}`);
228
- console.log(`Mode: ${DRY_RUN ? 'DRY RUN (use --write to apply changes)' : 'WRITE MODE'}\n`);
229
-
230
- const files = getMarkdownFiles(DOCS_ROOT);
231
- console.log(`Found ${files.length} markdown files (excluding _* paths)\n`);
232
-
233
- let totalChanges = 0;
234
- let filesChanged = 0;
235
- const brokenLinks = [];
236
-
237
- for (const filePath of files) {
238
- const relativePath = path.relative(DOCS_ROOT, filePath);
239
- const result = processFile(filePath);
240
-
241
- if (result.changed) {
242
- filesChanged++;
243
- totalChanges += result.changes.length;
244
-
245
- console.log(`\n${relativePath}`);
246
- for (const change of result.changes) {
247
- const isValid = validateLink(change.to);
248
- const status = isValid ? ' ' : '! ';
249
-
250
- console.log(`${status} ${change.from}`);
251
- console.log(` -> ${change.to}`);
252
-
253
- if (!isValid) {
254
- brokenLinks.push({
255
- file: relativePath,
256
- link: change.to,
257
- original: change.from,
258
- });
259
- }
260
- }
261
-
262
- if (!DRY_RUN) {
263
- fs.writeFileSync(filePath, result.updated, 'utf-8');
264
- }
265
- }
266
- }
267
-
268
- console.log(`\n${'─'.repeat(60)}`);
269
- console.log(`\nSummary:`);
270
- console.log(` Files scanned: ${files.length}`);
271
- console.log(` Files with changes: ${filesChanged}`);
272
- console.log(` Total link updates: ${totalChanges}`);
273
-
274
- if (brokenLinks.length > 0) {
275
- console.log(`\n! Potential broken links (${brokenLinks.length}):`);
276
- for (const bl of brokenLinks) {
277
- console.log(` ${bl.file}: ${bl.link}`);
278
- }
279
- }
280
-
281
- if (DRY_RUN && totalChanges > 0) {
282
- console.log(`\nRun with --write to apply these changes`);
283
- }
284
-
285
- console.log('');
@@ -1,110 +0,0 @@
1
- /**
2
- * Agent Schema Validator CLI
3
- *
4
- * Scans all *.agent.yaml files in src/{core,modules/*}/agents/
5
- * and validates them against the Zod schema.
6
- *
7
- * Usage: node tools/validate-agent-schema.js [project_root]
8
- * Exit codes: 0 = success, 1 = validation failures
9
- *
10
- * Optional argument:
11
- * project_root - Directory to scan (defaults to BMAD repo root)
12
- */
13
-
14
- const { glob } = require('glob');
15
- const yaml = require('yaml');
16
- const fs = require('node:fs');
17
- const path = require('node:path');
18
- const { validateAgentFile } = require('./schema/agent.js');
19
-
20
- /**
21
- * Main validation routine
22
- * @param {string} [customProjectRoot] - Optional project root to scan (for testing)
23
- */
24
- async function main(customProjectRoot) {
25
- console.log('🔍 Scanning for agent files...\n');
26
-
27
- // Determine project root: use custom path if provided, otherwise default to repo root
28
- const project_root = customProjectRoot || path.join(__dirname, '..');
29
-
30
- // Find all agent files
31
- const agentFiles = await glob('src/{core,bmm}/agents/**/*.agent.yaml', {
32
- cwd: project_root,
33
- absolute: true,
34
- });
35
-
36
- if (agentFiles.length === 0) {
37
- console.log('❌ No agent files found. This likely indicates a configuration error.');
38
- console.log(' Expected to find *.agent.yaml files in src/{core,modules/*}/agents/');
39
- process.exit(1);
40
- }
41
-
42
- console.log(`Found ${agentFiles.length} agent file(s)\n`);
43
-
44
- const errors = [];
45
-
46
- // Validate each file
47
- for (const filePath of agentFiles) {
48
- const relativePath = path.relative(process.cwd(), filePath);
49
-
50
- try {
51
- const fileContent = fs.readFileSync(filePath, 'utf8');
52
- const agentData = yaml.parse(fileContent);
53
-
54
- // Convert absolute path to relative src/ path for module detection
55
- const srcRelativePath = relativePath.startsWith('src/') ? relativePath : path.relative(project_root, filePath).replaceAll('\\', '/');
56
-
57
- const result = validateAgentFile(srcRelativePath, agentData);
58
-
59
- if (result.success) {
60
- console.log(`✅ ${relativePath}`);
61
- } else {
62
- errors.push({
63
- file: relativePath,
64
- issues: result.error.issues,
65
- });
66
- }
67
- } catch (error) {
68
- errors.push({
69
- file: relativePath,
70
- issues: [
71
- {
72
- code: 'parse_error',
73
- message: `Failed to parse YAML: ${error.message}`,
74
- path: [],
75
- },
76
- ],
77
- });
78
- }
79
- }
80
-
81
- // Report errors
82
- if (errors.length > 0) {
83
- console.log('\n❌ Validation failed for the following files:\n');
84
-
85
- for (const { file, issues } of errors) {
86
- console.log(`\n📄 ${file}`);
87
- for (const issue of issues) {
88
- const pathString = issue.path.length > 0 ? issue.path.join('.') : '(root)';
89
- console.log(` Path: ${pathString}`);
90
- console.log(` Error: ${issue.message}`);
91
- if (issue.code) {
92
- console.log(` Code: ${issue.code}`);
93
- }
94
- }
95
- }
96
-
97
- console.log(`\n\n💥 ${errors.length} file(s) failed validation`);
98
- process.exit(1);
99
- }
100
-
101
- console.log(`\n✨ All ${agentFiles.length} agent file(s) passed validation!\n`);
102
- process.exit(0);
103
- }
104
-
105
- // Run with optional command-line argument for project root
106
- const customProjectRoot = process.argv[2];
107
- main(customProjectRoot).catch((error) => {
108
- console.error('Fatal error:', error);
109
- process.exit(1);
110
- });