bmad-method 6.0.5-next.9 → 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 (261) 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/bmad-quick-flow/bmad-quick-dev-new-preview/workflow.md +0 -4
  46. package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +1 -1
  47. package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +1 -1
  48. package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +1 -1
  49. package/src/core/module-help.csv +2 -2
  50. package/src/core/workflows/bmad-brainstorming/SKILL.md +6 -0
  51. package/src/core/workflows/bmad-brainstorming/bmad-skill-manifest.yaml +1 -0
  52. package/src/core/workflows/{brainstorming → bmad-brainstorming}/workflow.md +2 -5
  53. package/src/core/workflows/bmad-party-mode/SKILL.md +6 -0
  54. package/src/core/workflows/bmad-party-mode/bmad-skill-manifest.yaml +1 -0
  55. package/src/core/workflows/{party-mode → bmad-party-mode}/steps/step-03-graceful-exit.md +0 -1
  56. package/src/core/workflows/{party-mode → bmad-party-mode}/workflow.md +0 -4
  57. package/tools/cli/external-official-modules.yaml +18 -18
  58. package/tools/cli/installers/lib/core/installer.js +25 -8
  59. package/tools/cli/installers/lib/ide/_base-ide.js +0 -1
  60. package/tools/cli/installers/lib/ide/_config-driven.js +9 -4
  61. package/tools/cli/installers/lib/ide/manager.js +3 -3
  62. package/tools/cli/lib/agent/compiler.js +1 -1
  63. package/.augment/code_review_guidelines.yaml +0 -231
  64. package/.coderabbit.yaml +0 -85
  65. package/.github/CODE_OF_CONDUCT.md +0 -128
  66. package/.github/FUNDING.yaml +0 -15
  67. package/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -124
  68. package/.github/ISSUE_TEMPLATE/config.yaml +0 -8
  69. package/.github/ISSUE_TEMPLATE/documentation.yaml +0 -55
  70. package/.github/ISSUE_TEMPLATE/feature-request.md +0 -22
  71. package/.github/ISSUE_TEMPLATE/issue.md +0 -32
  72. package/.github/PULL_REQUEST_TEMPLATE.md +0 -13
  73. package/.github/scripts/discord-helpers.sh +0 -34
  74. package/.github/workflows/coderabbit-review.yaml +0 -22
  75. package/.github/workflows/discord.yaml +0 -90
  76. package/.github/workflows/docs.yaml +0 -64
  77. package/.github/workflows/publish.yaml +0 -133
  78. package/.github/workflows/quality.yaml +0 -116
  79. package/.husky/pre-commit +0 -20
  80. package/.markdownlint-cli2.yaml +0 -41
  81. package/.nvmrc +0 -1
  82. package/.prettierignore +0 -12
  83. package/.vscode/settings.json +0 -96
  84. package/CHANGELOG.md +0 -1785
  85. package/CNAME +0 -1
  86. package/CONTRIBUTING.md +0 -176
  87. package/CONTRIBUTORS.md +0 -32
  88. package/SECURITY.md +0 -85
  89. package/TRADEMARK.md +0 -55
  90. package/Wordmark.png +0 -0
  91. package/banner-bmad-method.png +0 -0
  92. package/docs/404.md +0 -9
  93. package/docs/_STYLE_GUIDE.md +0 -370
  94. package/docs/explanation/advanced-elicitation.md +0 -49
  95. package/docs/explanation/adversarial-review.md +0 -59
  96. package/docs/explanation/brainstorming.md +0 -33
  97. package/docs/explanation/established-projects-faq.md +0 -50
  98. package/docs/explanation/party-mode.md +0 -59
  99. package/docs/explanation/preventing-agent-conflicts.md +0 -112
  100. package/docs/explanation/project-context.md +0 -157
  101. package/docs/explanation/quick-dev-new-preview.md +0 -73
  102. package/docs/explanation/quick-flow.md +0 -77
  103. package/docs/explanation/why-solutioning-matters.md +0 -77
  104. package/docs/how-to/customize-bmad.md +0 -172
  105. package/docs/how-to/established-projects.md +0 -117
  106. package/docs/how-to/get-answers-about-bmad.md +0 -138
  107. package/docs/how-to/install-bmad.md +0 -116
  108. package/docs/how-to/non-interactive-installation.md +0 -171
  109. package/docs/how-to/project-context.md +0 -136
  110. package/docs/how-to/quick-fixes.md +0 -123
  111. package/docs/how-to/shard-large-documents.md +0 -78
  112. package/docs/how-to/upgrade-to-v6.md +0 -100
  113. package/docs/index.md +0 -60
  114. package/docs/reference/agents.md +0 -28
  115. package/docs/reference/commands.md +0 -145
  116. package/docs/reference/modules.md +0 -76
  117. package/docs/reference/testing.md +0 -106
  118. package/docs/reference/workflow-map.md +0 -89
  119. package/docs/roadmap.mdx +0 -136
  120. package/docs/tutorials/getting-started.md +0 -275
  121. package/docs/zh-cn/404.md +0 -9
  122. package/docs/zh-cn/_STYLE_GUIDE.md +0 -370
  123. package/docs/zh-cn/explanation/advanced-elicitation.md +0 -62
  124. package/docs/zh-cn/explanation/adversarial-review.md +0 -71
  125. package/docs/zh-cn/explanation/brainstorming.md +0 -43
  126. package/docs/zh-cn/explanation/established-projects-faq.md +0 -60
  127. package/docs/zh-cn/explanation/party-mode.md +0 -79
  128. package/docs/zh-cn/explanation/preventing-agent-conflicts.md +0 -137
  129. package/docs/zh-cn/explanation/project-context.md +0 -176
  130. package/docs/zh-cn/explanation/quick-flow.md +0 -93
  131. package/docs/zh-cn/explanation/why-solutioning-matters.md +0 -90
  132. package/docs/zh-cn/how-to/customize-bmad.md +0 -182
  133. package/docs/zh-cn/how-to/established-projects.md +0 -134
  134. package/docs/zh-cn/how-to/get-answers-about-bmad.md +0 -144
  135. package/docs/zh-cn/how-to/install-bmad.md +0 -105
  136. package/docs/zh-cn/how-to/non-interactive-installation.md +0 -181
  137. package/docs/zh-cn/how-to/project-context.md +0 -152
  138. package/docs/zh-cn/how-to/quick-fixes.md +0 -140
  139. package/docs/zh-cn/how-to/shard-large-documents.md +0 -86
  140. package/docs/zh-cn/how-to/upgrade-to-v6.md +0 -120
  141. package/docs/zh-cn/index.md +0 -69
  142. package/docs/zh-cn/reference/agents.md +0 -41
  143. package/docs/zh-cn/reference/commands.md +0 -166
  144. package/docs/zh-cn/reference/modules.md +0 -94
  145. package/docs/zh-cn/reference/testing.md +0 -122
  146. package/docs/zh-cn/reference/workflow-map.md +0 -104
  147. package/docs/zh-cn/roadmap.mdx +0 -152
  148. package/docs/zh-cn/tutorials/getting-started.md +0 -300
  149. package/eslint.config.mjs +0 -141
  150. package/prettier.config.mjs +0 -32
  151. package/src/core/workflows/brainstorming/bmad-skill-manifest.yaml +0 -3
  152. package/src/core/workflows/party-mode/bmad-skill-manifest.yaml +0 -3
  153. package/test/README.md +0 -295
  154. package/test/adversarial-review-tests/README.md +0 -56
  155. package/test/adversarial-review-tests/sample-content.md +0 -46
  156. package/test/adversarial-review-tests/test-cases.yaml +0 -103
  157. package/test/fixtures/agent-schema/invalid/critical-actions/actions-as-string.agent.yaml +0 -27
  158. package/test/fixtures/agent-schema/invalid/critical-actions/empty-string-in-actions.agent.yaml +0 -30
  159. package/test/fixtures/agent-schema/invalid/menu/empty-menu.agent.yaml +0 -22
  160. package/test/fixtures/agent-schema/invalid/menu/missing-menu.agent.yaml +0 -20
  161. package/test/fixtures/agent-schema/invalid/menu-commands/empty-command-target.agent.yaml +0 -25
  162. package/test/fixtures/agent-schema/invalid/menu-commands/no-command-target.agent.yaml +0 -24
  163. package/test/fixtures/agent-schema/invalid/menu-triggers/camel-case.agent.yaml +0 -25
  164. package/test/fixtures/agent-schema/invalid/menu-triggers/compound-invalid-format.agent.yaml +0 -25
  165. package/test/fixtures/agent-schema/invalid/menu-triggers/compound-mismatched-kebab.agent.yaml +0 -25
  166. package/test/fixtures/agent-schema/invalid/menu-triggers/duplicate-triggers.agent.yaml +0 -31
  167. package/test/fixtures/agent-schema/invalid/menu-triggers/empty-trigger.agent.yaml +0 -25
  168. package/test/fixtures/agent-schema/invalid/menu-triggers/leading-asterisk.agent.yaml +0 -25
  169. package/test/fixtures/agent-schema/invalid/menu-triggers/snake-case.agent.yaml +0 -25
  170. package/test/fixtures/agent-schema/invalid/menu-triggers/trigger-with-spaces.agent.yaml +0 -25
  171. package/test/fixtures/agent-schema/invalid/metadata/empty-module-string.agent.yaml +0 -26
  172. package/test/fixtures/agent-schema/invalid/metadata/empty-name.agent.yaml +0 -24
  173. package/test/fixtures/agent-schema/invalid/metadata/extra-metadata-fields.agent.yaml +0 -27
  174. package/test/fixtures/agent-schema/invalid/metadata/missing-id.agent.yaml +0 -23
  175. package/test/fixtures/agent-schema/invalid/persona/empty-principles-array.agent.yaml +0 -24
  176. package/test/fixtures/agent-schema/invalid/persona/empty-string-in-principles.agent.yaml +0 -27
  177. package/test/fixtures/agent-schema/invalid/persona/extra-persona-fields.agent.yaml +0 -27
  178. package/test/fixtures/agent-schema/invalid/persona/missing-role.agent.yaml +0 -24
  179. package/test/fixtures/agent-schema/invalid/prompts/empty-content.agent.yaml +0 -29
  180. package/test/fixtures/agent-schema/invalid/prompts/extra-prompt-fields.agent.yaml +0 -31
  181. package/test/fixtures/agent-schema/invalid/prompts/missing-content.agent.yaml +0 -28
  182. package/test/fixtures/agent-schema/invalid/prompts/missing-id.agent.yaml +0 -28
  183. package/test/fixtures/agent-schema/invalid/top-level/empty-file.agent.yaml +0 -5
  184. package/test/fixtures/agent-schema/invalid/top-level/extra-top-level-keys.agent.yaml +0 -28
  185. package/test/fixtures/agent-schema/invalid/top-level/missing-agent-key.agent.yaml +0 -11
  186. package/test/fixtures/agent-schema/invalid/yaml-errors/invalid-indentation.agent.yaml +0 -19
  187. package/test/fixtures/agent-schema/invalid/yaml-errors/malformed-yaml.agent.yaml +0 -18
  188. package/test/fixtures/agent-schema/valid/critical-actions/empty-critical-actions.agent.yaml +0 -24
  189. package/test/fixtures/agent-schema/valid/critical-actions/no-critical-actions.agent.yaml +0 -22
  190. package/test/fixtures/agent-schema/valid/critical-actions/valid-critical-actions.agent.yaml +0 -27
  191. package/test/fixtures/agent-schema/valid/menu/multiple-menu-items.agent.yaml +0 -31
  192. package/test/fixtures/agent-schema/valid/menu/single-menu-item.agent.yaml +0 -22
  193. package/test/fixtures/agent-schema/valid/menu-commands/all-command-types.agent.yaml +0 -38
  194. package/test/fixtures/agent-schema/valid/menu-commands/multiple-commands.agent.yaml +0 -23
  195. package/test/fixtures/agent-schema/valid/menu-triggers/compound-triggers.agent.yaml +0 -31
  196. package/test/fixtures/agent-schema/valid/menu-triggers/kebab-case-triggers.agent.yaml +0 -34
  197. package/test/fixtures/agent-schema/valid/metadata/core-agent-with-module.agent.yaml +0 -24
  198. package/test/fixtures/agent-schema/valid/metadata/empty-module-name-in-path.agent.yaml +0 -24
  199. package/test/fixtures/agent-schema/valid/metadata/malformed-path-treated-as-core.agent.yaml +0 -24
  200. package/test/fixtures/agent-schema/valid/metadata/module-agent-correct.agent.yaml +0 -24
  201. package/test/fixtures/agent-schema/valid/metadata/module-agent-missing-module.agent.yaml +0 -23
  202. package/test/fixtures/agent-schema/valid/metadata/wrong-module-value.agent.yaml +0 -24
  203. package/test/fixtures/agent-schema/valid/persona/complete-persona.agent.yaml +0 -24
  204. package/test/fixtures/agent-schema/valid/prompts/empty-prompts.agent.yaml +0 -24
  205. package/test/fixtures/agent-schema/valid/prompts/no-prompts.agent.yaml +0 -22
  206. package/test/fixtures/agent-schema/valid/prompts/valid-prompts-minimal.agent.yaml +0 -28
  207. package/test/fixtures/agent-schema/valid/prompts/valid-prompts-with-description.agent.yaml +0 -30
  208. package/test/fixtures/agent-schema/valid/top-level/minimal-core-agent.agent.yaml +0 -24
  209. package/test/fixtures/file-refs-csv/invalid/all-empty-workflow.csv +0 -3
  210. package/test/fixtures/file-refs-csv/invalid/empty-data.csv +0 -1
  211. package/test/fixtures/file-refs-csv/invalid/no-workflow-column.csv +0 -3
  212. package/test/fixtures/file-refs-csv/invalid/unresolvable-vars.csv +0 -3
  213. package/test/fixtures/file-refs-csv/valid/bmm-style.csv +0 -3
  214. package/test/fixtures/file-refs-csv/valid/core-style.csv +0 -3
  215. package/test/fixtures/file-refs-csv/valid/minimal.csv +0 -2
  216. package/test/test-agent-schema.js +0 -387
  217. package/test/test-cli-integration.sh +0 -159
  218. package/test/test-file-refs-csv.js +0 -133
  219. package/test/test-install-to-bmad.js +0 -154
  220. package/test/test-installation-components.js +0 -1796
  221. package/test/test-rehype-plugins.mjs +0 -1050
  222. package/test/test-workflow-path-regex.js +0 -88
  223. package/test/unit-test-schema.js +0 -133
  224. package/tools/build-docs.mjs +0 -464
  225. package/tools/docs/_prompt-external-modules-page.md +0 -59
  226. package/tools/docs/fix-refs.md +0 -91
  227. package/tools/docs/native-skills-migration-checklist.md +0 -281
  228. package/tools/fix-doc-links.js +0 -285
  229. package/tools/validate-agent-schema.js +0 -110
  230. package/tools/validate-doc-links.js +0 -407
  231. package/tools/validate-file-refs.js +0 -556
  232. package/website/README.md +0 -75
  233. package/website/astro.config.mjs +0 -157
  234. package/website/public/diagrams/quick-dev-diagram.png +0 -0
  235. package/website/public/favicon.ico +0 -0
  236. package/website/public/img/bmad-dark.png +0 -0
  237. package/website/public/img/bmad-light.png +0 -0
  238. package/website/public/workflow-map-diagram.html +0 -361
  239. package/website/src/components/Banner.astro +0 -62
  240. package/website/src/components/Header.astro +0 -96
  241. package/website/src/components/MobileMenuFooter.astro +0 -33
  242. package/website/src/content/config.ts +0 -7
  243. package/website/src/content/i18n/zh-CN.json +0 -28
  244. package/website/src/lib/site-url.mjs +0 -25
  245. package/website/src/pages/404.astro +0 -11
  246. package/website/src/pages/robots.txt.ts +0 -48
  247. package/website/src/rehype-base-paths.js +0 -112
  248. package/website/src/rehype-markdown-links.js +0 -119
  249. package/website/src/styles/custom.css +0 -805
  250. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/brain-methods.csv +0 -0
  251. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-01-session-setup.md +0 -0
  252. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-01b-continue.md +0 -0
  253. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02a-user-selected.md +0 -0
  254. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02b-ai-recommended.md +0 -0
  255. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02c-random-selection.md +0 -0
  256. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-02d-progressive-flow.md +0 -0
  257. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-03-technique-execution.md +0 -0
  258. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/steps/step-04-idea-organization.md +0 -0
  259. /package/src/core/workflows/{brainstorming → bmad-brainstorming}/template.md +0 -0
  260. /package/src/core/workflows/{party-mode → bmad-party-mode}/steps/step-01-agent-loading.md +0 -0
  261. /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
- });