ma-agents 3.12.3 → 3.13.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 (254) hide show
  1. package/docs/architecture.md +18 -0
  2. package/lib/bmad-cache/bmb/.claude-plugin/marketplace.json +1 -1
  3. package/lib/bmad-cache/bmb/_git_preserved/hooks/commit-msg.sample +52 -2
  4. package/lib/bmad-cache/bmb/_git_preserved/hooks/fsmonitor-watchman.sample +2 -8
  5. package/lib/bmad-cache/bmb/_git_preserved/index +0 -0
  6. package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-8f8b045fef5af6911495cf3b2a89f1ed75e120f7.idx +0 -0
  7. package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-8f8b045fef5af6911495cf3b2a89f1ed75e120f7.pack +0 -0
  8. package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-8f8b045fef5af6911495cf3b2a89f1ed75e120f7.rev +0 -0
  9. package/lib/bmad-cache/bmb/_git_preserved/packed-refs +1 -1
  10. package/lib/bmad-cache/bmb/_git_preserved/refs/heads/main +1 -1
  11. package/lib/bmad-cache/bmb/_git_preserved/shallow +1 -1
  12. package/lib/bmad-cache/bmb/package-lock.json +2 -2
  13. package/lib/bmad-cache/bmb/package.json +1 -1
  14. package/lib/bmad-cache/bmb/samples/bmad-agent-dream-weaver/assets/module-help.csv +1 -1
  15. package/lib/bmad-cache/bmb/samples/bmad-agent-dream-weaver/scripts/merge-config.py +33 -0
  16. package/lib/bmad-cache/bmb/samples/bmad-agent-dream-weaver/scripts/merge-help-csv.py +28 -0
  17. package/lib/bmad-cache/bmb/samples/sample-module-setup/assets/module-help.csv +1 -1
  18. package/lib/bmad-cache/bmb/samples/sample-module-setup/scripts/cleanup-legacy.py +28 -0
  19. package/lib/bmad-cache/bmb/samples/sample-module-setup/scripts/merge-config.py +33 -0
  20. package/lib/bmad-cache/bmb/samples/sample-module-setup/scripts/merge-help-csv.py +28 -0
  21. package/lib/bmad-cache/bmb/skills/bmad-bmb-setup/assets/module-help.csv +1 -1
  22. package/lib/bmad-cache/bmb/skills/bmad-bmb-setup/scripts/cleanup-legacy.py +28 -0
  23. package/lib/bmad-cache/bmb/skills/bmad-bmb-setup/scripts/merge-config.py +33 -0
  24. package/lib/bmad-cache/bmb/skills/bmad-bmb-setup/scripts/merge-help-csv.py +28 -0
  25. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/assets/Dockerfile +29 -0
  26. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/docker_setup.py +115 -0
  27. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/generate_report.py +184 -0
  28. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/pty_runner.py +171 -0
  29. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/run_evals.py +492 -0
  30. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/run_triggers.py +366 -0
  31. package/lib/bmad-cache/bmb/skills/bmad-eval-runner/scripts/utils.py +260 -0
  32. package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/setup-skill-template/assets/module-help.csv +1 -1
  33. package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/setup-skill-template/scripts/cleanup-legacy.py +28 -0
  34. package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/setup-skill-template/scripts/merge-config.py +33 -0
  35. package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/setup-skill-template/scripts/merge-help-csv.py +28 -0
  36. package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/standalone-module-template/merge-config.py +33 -0
  37. package/lib/bmad-cache/bmb/skills/bmad-module-builder/assets/standalone-module-template/merge-help-csv.py +28 -0
  38. package/lib/bmad-cache/bmb/skills/bmad-module-builder/scripts/tests/test-validate-module.py +74 -1
  39. package/lib/bmad-cache/bmb/skills/bmad-module-builder/scripts/validate-module.py +24 -13
  40. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/assets/sample-customize-product-brief.toml +48 -33
  41. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/extract-report-json.py +287 -0
  42. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/generate-html-report.py +57 -8
  43. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/prepass-prompt-metrics.py +7 -7
  44. package/lib/bmad-cache/bmb/skills/module-help.csv +1 -1
  45. package/lib/bmad-cache/bmb/website/public/img/eval-test-types.png +0 -0
  46. package/lib/bmad-cache/cache-manifest.json +17 -18
  47. package/lib/bmad-cache/cis/_git_preserved/hooks/commit-msg.sample +52 -2
  48. package/lib/bmad-cache/cis/_git_preserved/hooks/fsmonitor-watchman.sample +2 -8
  49. package/lib/bmad-cache/cis/_git_preserved/index +0 -0
  50. package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-18c8290560a98bcb7bf0676e6cc9b2ac5ca2823e.idx +0 -0
  51. package/lib/bmad-cache/cis/_git_preserved/objects/pack/{pack-42ffc048f54e58ce94c6331bc6be97ebbb7936f2.pack → pack-18c8290560a98bcb7bf0676e6cc9b2ac5ca2823e.pack} +0 -0
  52. package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-18c8290560a98bcb7bf0676e6cc9b2ac5ca2823e.rev +0 -0
  53. package/lib/bmad-cache/cis/_git_preserved/packed-refs +1 -1
  54. package/lib/bmad-cache/cis/_git_preserved/refs/heads/main +1 -1
  55. package/lib/bmad-cache/cis/_git_preserved/refs/tags/v0.2.1 +1 -0
  56. package/lib/bmad-cache/cis/_git_preserved/shallow +1 -1
  57. package/lib/bmad-cache/cis/package-lock.json +2 -2
  58. package/lib/bmad-cache/cis/package.json +1 -1
  59. package/lib/bmad-cache/cis/src/module-help.csv +1 -1
  60. package/lib/bmad-cache/gds/.claude-plugin/marketplace.json +4 -7
  61. package/lib/bmad-cache/gds/README.md +3 -1
  62. package/lib/bmad-cache/gds/_git_preserved/hooks/commit-msg.sample +52 -2
  63. package/lib/bmad-cache/gds/_git_preserved/hooks/fsmonitor-watchman.sample +2 -8
  64. package/lib/bmad-cache/gds/_git_preserved/index +0 -0
  65. package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-dcb7c556d9bb6b6b70d2301e094eaac6d7300552.idx +0 -0
  66. package/lib/bmad-cache/gds/_git_preserved/objects/pack/{pack-9427a146a90c00bb542cba038874bf9671ba4dc0.pack → pack-dcb7c556d9bb6b6b70d2301e094eaac6d7300552.pack} +0 -0
  67. package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-dcb7c556d9bb6b6b70d2301e094eaac6d7300552.rev +0 -0
  68. package/lib/bmad-cache/gds/_git_preserved/packed-refs +1 -1
  69. package/lib/bmad-cache/gds/_git_preserved/refs/heads/main +1 -1
  70. package/lib/bmad-cache/gds/_git_preserved/shallow +1 -1
  71. package/lib/bmad-cache/gds/package.json +1 -1
  72. package/lib/bmad-cache/gds/src/agents/gds-agent-game-designer/customize.toml +5 -5
  73. package/lib/bmad-cache/gds/src/agents/gds-agent-game-dev/customize.toml +5 -5
  74. package/lib/bmad-cache/gds/src/agents/gds-agent-game-solo-dev/customize.toml +0 -5
  75. package/lib/bmad-cache/gds/src/module-help.csv +6 -12
  76. package/lib/bmad-cache/gds/src/module.yaml +1 -1
  77. package/lib/bmad-cache/gds/src/workflows/1-preproduction/gds-create-game-brief/customize.toml +97 -22
  78. package/lib/bmad-cache/gds/src/workflows/2-design/gds-gdd/assets/validation-report-template.html +190 -0
  79. package/lib/bmad-cache/gds/src/workflows/2-design/gds-gdd/customize.toml +99 -0
  80. package/lib/bmad-cache/gds/src/workflows/2-design/gds-gdd/scripts/render-validation-html.py +290 -0
  81. package/lib/bmad-cache/gds/src/workflows/2-design/gds-prd/assets/validation-report-template.html +190 -0
  82. package/lib/bmad-cache/gds/src/workflows/2-design/gds-prd/customize.toml +84 -0
  83. package/lib/bmad-cache/gds/src/workflows/2-design/gds-ux/assets/validation-report-template.html +319 -0
  84. package/lib/bmad-cache/gds/src/workflows/2-design/gds-ux/customize.toml +101 -0
  85. package/lib/bmad-cache/gds/src/workflows/3-technical/gds-game-architecture/architecture-patterns.yaml +1 -0
  86. package/lib/bmad-cache/gds/src/workflows/3-technical/gds-game-architecture/decision-catalog.yaml +88 -0
  87. package/lib/bmad-cache/gds/src/workflows/3-technical/gds-game-architecture/engine-mcps.yaml +124 -2
  88. package/lib/bmad-cache/gds/src/workflows/4-production/gds-investigate/customize.toml +62 -0
  89. package/lib/bmad-cache/tea/.claude-plugin/marketplace.json +1 -1
  90. package/lib/bmad-cache/tea/.github/workflows/docs.yaml +3 -3
  91. package/lib/bmad-cache/tea/.github/workflows/quality.yaml +10 -10
  92. package/lib/bmad-cache/tea/AGENTS.md +31 -0
  93. package/lib/bmad-cache/tea/CHANGELOG.md +42 -1
  94. package/lib/bmad-cache/tea/README.md +8 -5
  95. package/lib/bmad-cache/tea/_git_preserved/hooks/commit-msg.sample +52 -2
  96. package/lib/bmad-cache/tea/_git_preserved/hooks/fsmonitor-watchman.sample +2 -8
  97. package/lib/bmad-cache/tea/_git_preserved/index +0 -0
  98. package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-9e4197e37df7763dd7a05c2965ee921dfd2eb617.idx +0 -0
  99. package/lib/bmad-cache/tea/_git_preserved/objects/pack/{pack-f0df537f2649464ff6c5aee241165eb9c8664227.pack → pack-9e4197e37df7763dd7a05c2965ee921dfd2eb617.pack} +0 -0
  100. package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-9e4197e37df7763dd7a05c2965ee921dfd2eb617.rev +0 -0
  101. package/lib/bmad-cache/tea/_git_preserved/packed-refs +1 -1
  102. package/lib/bmad-cache/tea/_git_preserved/refs/heads/main +1 -1
  103. package/lib/bmad-cache/tea/_git_preserved/refs/tags/v1.19.0 +1 -0
  104. package/lib/bmad-cache/tea/_git_preserved/shallow +1 -1
  105. package/lib/bmad-cache/tea/docs/explanation/engagement-models.md +15 -16
  106. package/lib/bmad-cache/tea/docs/explanation/knowledge-base-system.md +2 -0
  107. package/lib/bmad-cache/tea/docs/explanation/risk-based-testing.md +1 -1
  108. package/lib/bmad-cache/tea/docs/explanation/tea-overview.md +88 -52
  109. package/lib/bmad-cache/tea/docs/explanation/testing-as-engineering.md +13 -12
  110. package/lib/bmad-cache/tea/docs/glossary/index.md +2 -2
  111. package/lib/bmad-cache/tea/docs/how-to/brownfield/use-tea-for-enterprise.md +19 -18
  112. package/lib/bmad-cache/tea/docs/how-to/brownfield/use-tea-with-existing-tests.md +1 -1
  113. package/lib/bmad-cache/tea/docs/how-to/workflows/run-nfr-assess.md +32 -26
  114. package/lib/bmad-cache/tea/docs/how-to/workflows/run-test-design.md +20 -14
  115. package/lib/bmad-cache/tea/docs/how-to/workflows/run-trace.md +3 -3
  116. package/lib/bmad-cache/tea/docs/index.md +13 -11
  117. package/lib/bmad-cache/tea/docs/reference/commands.md +37 -13
  118. package/lib/bmad-cache/tea/docs/reference/knowledge-base.md +2 -2
  119. package/lib/bmad-cache/tea/package-lock.json +2 -2
  120. package/lib/bmad-cache/tea/package.json +1 -1
  121. package/lib/bmad-cache/tea/src/agents/bmad-tea/customize.toml +20 -15
  122. package/lib/bmad-cache/tea/src/agents/bmad-tea/resources/knowledge/confidence-gate.md +73 -0
  123. package/lib/bmad-cache/tea/src/agents/bmad-tea/resources/knowledge/test-quality.md +1 -0
  124. package/lib/bmad-cache/tea/src/agents/bmad-tea/resources/tea-index.csv +2 -1
  125. package/lib/bmad-cache/tea/src/module-help.csv +2 -2
  126. package/lib/bmad-cache/tea/src/workflows/testarch/README.md +5 -4
  127. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-teach-me-testing/data/role-paths.yaml +1 -1
  128. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-teach-me-testing/data/tea-resources-index.yaml +1 -1
  129. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-teach-me-testing/steps-c/step-04-session-01.md +2 -2
  130. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-teach-me-testing/steps-c/step-04-session-07.md +1 -1
  131. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-teach-me-testing/templates/certificate-template.md +1 -1
  132. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-atdd/resources/tea-index.csv +1 -1
  133. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-automate/resources/tea-index.csv +1 -1
  134. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-ci/resources/tea-index.csv +1 -1
  135. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-framework/resources/tea-index.csv +1 -1
  136. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/SKILL.md +3 -3
  137. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/checklist.md +11 -11
  138. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/instructions.md +4 -2
  139. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/nfr-report-template.md +5 -5
  140. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/resources/tea-index.csv +1 -1
  141. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-01-load-context.md +1 -1
  142. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-01b-resume.md +1 -1
  143. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-02-define-thresholds.md +14 -3
  144. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04-evaluate-and-score.md +7 -7
  145. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04a-subagent-security.md +4 -4
  146. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04b-subagent-performance.md +4 -4
  147. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04c-subagent-reliability.md +4 -4
  148. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04d-subagent-scalability.md +4 -4
  149. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-04e-aggregate-nfr.md +4 -4
  150. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/steps-c/step-05-generate-report.md +1 -1
  151. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/workflow-plan.md +1 -1
  152. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-nfr/workflow.yaml +3 -3
  153. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/checklist.md +23 -3
  154. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/resources/tea-index.csv +1 -1
  155. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/steps-c/step-02-load-context.md +7 -0
  156. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/steps-c/step-03-risk-and-testability.md +16 -2
  157. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/steps-c/step-04-coverage-plan.md +20 -4
  158. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/steps-c/step-05-generate-output.md +2 -0
  159. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/test-design-architecture-template.md +17 -0
  160. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/test-design-qa-template.md +15 -0
  161. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-design/test-design-template.md +16 -0
  162. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-test-review/resources/tea-index.csv +1 -1
  163. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-trace/checklist.md +1 -1
  164. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-trace/resources/tea-index.csv +1 -1
  165. package/lib/bmad-cache/tea/src/workflows/testarch/bmad-testarch-trace/trace-template.md +1 -1
  166. package/lib/bmad-cache/tea/test/test-installation-components.js +49 -0
  167. package/lib/bmad-cache/tea/website/astro.config.mjs +2 -2
  168. package/lib/bmad-cache/wds/README.md +1 -1
  169. package/lib/bmad-cache/wds/_git_preserved/hooks/commit-msg.sample +52 -2
  170. package/lib/bmad-cache/wds/_git_preserved/hooks/fsmonitor-watchman.sample +2 -8
  171. package/lib/bmad-cache/wds/_git_preserved/index +0 -0
  172. package/lib/bmad-cache/wds/_git_preserved/objects/pack/pack-656c3d8d5426e73043b6a7f45eedaab74e3c419e.idx +0 -0
  173. package/lib/bmad-cache/wds/_git_preserved/objects/pack/{pack-96877c1c09123cccb1f91c1412184b11d2b492ad.pack → pack-656c3d8d5426e73043b6a7f45eedaab74e3c419e.pack} +0 -0
  174. package/lib/bmad-cache/wds/_git_preserved/objects/pack/pack-656c3d8d5426e73043b6a7f45eedaab74e3c419e.rev +0 -0
  175. package/lib/bmad-cache/wds/_git_preserved/packed-refs +1 -1
  176. package/lib/bmad-cache/wds/_git_preserved/refs/heads/main +1 -1
  177. package/lib/bmad-cache/wds/_git_preserved/refs/tags/v0.4.3 +1 -0
  178. package/lib/bmad-cache/wds/_git_preserved/shallow +1 -1
  179. package/lib/bmad-cache/wds/eslint.config.mjs +1 -1
  180. package/lib/bmad-cache/wds/package.json +1 -1
  181. package/lib/bmad-cache/wds/src/agents/wds-agent-freya-ux/customize.toml +80 -0
  182. package/lib/bmad-cache/wds/src/agents/wds-agent-mimir-builder/customize.toml +52 -0
  183. package/lib/bmad-cache/wds/src/agents/wds-agent-saga-analyst/customize.toml +70 -0
  184. package/lib/bmad-cache/wds/src/module-help.csv +19 -19
  185. package/lib/bmad-cache/wds/src/module.yaml +28 -0
  186. package/lib/bmad-cache/wds/src/scripts/README.md +155 -0
  187. package/lib/bmad-cache/wds/src/scripts/wds-add-object.js +202 -0
  188. package/lib/bmad-cache/wds/src/scripts/wds-add-spacing.js +158 -0
  189. package/lib/bmad-cache/wds/src/scripts/wds-init-page.js +229 -0
  190. package/lib/bmad-cache/wds/src/scripts/wds-init-scenario.js +120 -0
  191. package/lib/bmad-cache/wds/src/scripts/wds-nav.js +201 -0
  192. package/lib/bmad-cache/wds/src/scripts/wds-validate.js +301 -0
  193. package/lib/bmad-cache/wds/src/workflows/wds-3-scenarios/workflow.xml +450 -0
  194. package/lib/bmad-cache/wds/src/workflows/wds-4-ux-design/workflow-specify.xml +387 -0
  195. package/lib/bmad-extension/.claude-plugin/marketplace.json.template +1 -1
  196. package/lib/bmad-extension-plugin/.claude-plugin/marketplace.json +2 -2
  197. package/lib/bmad.js +91 -7
  198. package/lib/installer.js +28 -6
  199. package/lib/mil498-templates/OCD.md +169 -169
  200. package/lib/mil498-templates/README.md +4 -4
  201. package/lib/mil498-templates/SDD.md +163 -163
  202. package/lib/mil498-templates/SDP.md +307 -307
  203. package/lib/mil498-templates/SRS.md +219 -219
  204. package/lib/mil498-templates/SSDD.md +154 -154
  205. package/lib/mil498-templates/SSS.md +225 -225
  206. package/lib/mil498-templates/STD.md +188 -188
  207. package/lib/templates/instruction-block-git.template.md +25 -0
  208. package/package.json +5 -4
  209. package/scripts/build-bmad-cache.js +143 -42
  210. package/skills/git-workflow-skill/skill.json +21 -21
  211. package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-6ecd9fc6445b1281449c5ec49a6c5794708e662e.idx +0 -0
  212. package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-6ecd9fc6445b1281449c5ec49a6c5794708e662e.pack +0 -0
  213. package/lib/bmad-cache/bmb/_git_preserved/objects/pack/pack-6ecd9fc6445b1281449c5ec49a6c5794708e662e.rev +0 -0
  214. package/lib/bmad-cache/bmb/_git_preserved/refs/remotes/origin/HEAD +0 -1
  215. package/lib/bmad-cache/bmb/_git_preserved/refs/tags/v1.7.0 +0 -1
  216. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/generate-convert-report.py +0 -406
  217. package/lib/bmad-cache/bmb/skills/bmad-workflow-builder/scripts/tests/test_generate_convert_report.py +0 -243
  218. package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-42ffc048f54e58ce94c6331bc6be97ebbb7936f2.idx +0 -0
  219. package/lib/bmad-cache/cis/_git_preserved/objects/pack/pack-42ffc048f54e58ce94c6331bc6be97ebbb7936f2.rev +0 -0
  220. package/lib/bmad-cache/cis/_git_preserved/refs/remotes/origin/HEAD +0 -1
  221. package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-9427a146a90c00bb542cba038874bf9671ba4dc0.idx +0 -0
  222. package/lib/bmad-cache/gds/_git_preserved/objects/pack/pack-9427a146a90c00bb542cba038874bf9671ba4dc0.rev +0 -0
  223. package/lib/bmad-cache/gds/_git_preserved/refs/remotes/origin/HEAD +0 -1
  224. package/lib/bmad-cache/gds/src/workflows/2-design/gds-create-gdd/customize.toml +0 -41
  225. package/lib/bmad-cache/gds/src/workflows/2-design/gds-create-prd/customize.toml +0 -41
  226. package/lib/bmad-cache/gds/src/workflows/2-design/gds-create-prd/data/domain-complexity.csv +0 -15
  227. package/lib/bmad-cache/gds/src/workflows/2-design/gds-create-prd/data/project-types.csv +0 -11
  228. package/lib/bmad-cache/gds/src/workflows/2-design/gds-create-ux-design/customize.toml +0 -41
  229. package/lib/bmad-cache/gds/src/workflows/2-design/gds-edit-gdd/customize.toml +0 -41
  230. package/lib/bmad-cache/gds/src/workflows/2-design/gds-edit-prd/customize.toml +0 -41
  231. package/lib/bmad-cache/gds/src/workflows/2-design/gds-validate-gdd/customize.toml +0 -41
  232. package/lib/bmad-cache/gds/src/workflows/2-design/gds-validate-prd/customize.toml +0 -41
  233. package/lib/bmad-cache/gds/src/workflows/2-design/gds-validate-prd/data/domain-complexity.csv +0 -15
  234. package/lib/bmad-cache/gds/src/workflows/2-design/gds-validate-prd/data/project-types.csv +0 -11
  235. package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-f0df537f2649464ff6c5aee241165eb9c8664227.idx +0 -0
  236. package/lib/bmad-cache/tea/_git_preserved/objects/pack/pack-f0df537f2649464ff6c5aee241165eb9c8664227.rev +0 -0
  237. package/lib/bmad-cache/tea/_git_preserved/refs/remotes/origin/HEAD +0 -1
  238. package/lib/bmad-cache/wds/_git_preserved/objects/pack/pack-96877c1c09123cccb1f91c1412184b11d2b492ad.idx +0 -0
  239. package/lib/bmad-cache/wds/_git_preserved/objects/pack/pack-96877c1c09123cccb1f91c1412184b11d2b492ad.rev +0 -0
  240. package/lib/bmad-cache/wds/_git_preserved/refs/remotes/origin/HEAD +0 -1
  241. package/lib/bmad-cache/wds/src/agents/wds-agent-freya-ux/bmad-skill-manifest.yaml +0 -12
  242. package/lib/bmad-cache/wds/src/agents/wds-agent-saga-analyst/bmad-skill-manifest.yaml +0 -12
  243. package/lib/bmad-cache/wds/src/workflows/wds-0-alignment-signoff/bmad-skill-manifest.yaml +0 -1
  244. package/lib/bmad-cache/wds/src/workflows/wds-0-project-setup/bmad-skill-manifest.yaml +0 -1
  245. package/lib/bmad-cache/wds/src/workflows/wds-1-project-brief/bmad-skill-manifest.yaml +0 -1
  246. package/lib/bmad-cache/wds/src/workflows/wds-2-trigger-mapping/bmad-skill-manifest.yaml +0 -1
  247. package/lib/bmad-cache/wds/src/workflows/wds-3-scenarios/bmad-skill-manifest.yaml +0 -1
  248. package/lib/bmad-cache/wds/src/workflows/wds-4-ux-design/bmad-skill-manifest.yaml +0 -1
  249. package/lib/bmad-cache/wds/src/workflows/wds-5-agentic-development/bmad-skill-manifest.yaml +0 -1
  250. package/lib/bmad-cache/wds/src/workflows/wds-6-asset-generation/bmad-skill-manifest.yaml +0 -1
  251. package/lib/bmad-cache/wds/src/workflows/wds-7-design-system/bmad-skill-manifest.yaml +0 -1
  252. package/lib/bmad-cache/wds/src/workflows/wds-8-product-evolution/bmad-skill-manifest.yaml +0 -1
  253. /package/lib/bmad-cache/gds/src/workflows/2-design/{gds-create-gdd → gds-gdd/assets}/game-types.csv +0 -0
  254. /package/lib/bmad-cache/gds/src/workflows/2-design/{gds-validate-gdd/data → gds-gdd/assets}/genre-complexity.csv +0 -0
@@ -195,6 +195,24 @@ skills/<skill-name>/
195
195
  - **Modern C++** (6): cpp-memory-handling, cpp-robust-interfaces, cpp-modern-composition, cpp-const-correctness, cpp-concurrency-safety, cmake-best-practices
196
196
  - **Architecture** (5): logging-best-practices, opentelemetry-best-practices, vercel-react-best-practices, git-workflow-skill, self-signed-cert
197
197
 
198
+ ### 3.6 BMAD Cache & Offline Self-Containment (build-time)
199
+
200
+ **Responsibility**: Pre-vendor BMAD's external modules so installs never touch the network.
201
+
202
+ ma-agents bundles bmad-method as an npm dependency **and** pre-clones BMAD's external modules (`tea`, `bmb`, `cis`, `gds`) into `lib/bmad-cache/` at build time via `npm run build:bmad-cache` ([scripts/build-bmad-cache.js](../scripts/build-bmad-cache.js)). This is what lets `npx ma-agents install` run fully offline in air-gapped environments (NFR2/NFR50/NFR54) — the npm tarball already contains every module bmad-method would otherwise `git clone` from GitHub at install time.
203
+
204
+ **Module discovery**: the builder reads BMAD's bundled module registry to learn which external modules to clone. **The registry source has moved across BMAD versions** and the reader must track it:
205
+
206
+ | BMAD version | Module registry source | Format |
207
+ |--------------|------------------------|--------|
208
+ | ≤ 6.2.x | `tools/cli/external-official-modules.yaml` | YAML |
209
+ | 6.3.0 – 6.6.x | `tools/installer/modules/registry-fallback.yaml` | YAML |
210
+ | 6.8.0+ | `bmad-modules.yaml` (bmad-method **package root**) | YAML (`modules:` map; the in-package `registry-fallback.yaml` was retired in 6.7.0) |
211
+
212
+ The registry has stayed **YAML** throughout — only its path has moved. (`tools/installer/modules/official-modules.js` is unchanged loader code that reads this YAML; it does not contain the module list.) Modules are classified by a `type` field: `type: bmad-org` modules are bundled (**tea, bmb, cis, gds, wds**) and `type: experimental` modules are excluded (currently `automator`). `bmm`/`core` are built-in (loaded from bmad-method's local `module.yaml`, absent from the registry) and are never cloned. The reader for the current pin and its fail-loud contract are defined by Architecture Decision **P5-5** (Epic 27) in `_bmad-output/planning-artifacts/architecture.md`. A companion build step, `npm run build:plugin` ([scripts/build-plugin.js](../scripts/build-plugin.js)), assembles the ma-agents extension plugin bundle (`lib/bmad-extension-plugin/`) deterministically; a CI Bundle Drift Guard enforces that the committed bundle matches a fresh build.
213
+
214
+ > **Maintenance note:** because the registry path has now moved twice (YAML→YAML→YAML at three locations), the cache builder fails loud — if the resolved `type: bmad-org` set is smaller than the known bundled set, or no module source is found, it exits non-zero rather than producing a thin/empty cache, so a future BMAD registry move surfaces at build time, not as a broken air-gapped install.
215
+
198
216
  ## 4. Data Flow
199
217
 
200
218
  ### 4.1 Install Flow
@@ -12,7 +12,7 @@
12
12
  "name": "bmad-builder",
13
13
  "source": "./",
14
14
  "description": "Build AI agents, workflows, and modules from a conversation. Four skills — Agent Builder, Workflow Builder, Module Builder, and Setup — guide you from idea to production-ready skill structure with built-in quality optimization. Part of the BMad Method ecosystem.",
15
- "version": "1.6.0",
15
+ "version": "1.8.0",
16
16
  "author": {
17
17
  "name": "Brian (BMad) Madison"
18
18
  },
@@ -15,10 +15,60 @@
15
15
  # SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
16
16
  # grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
17
17
 
18
- # This example catches duplicate Signed-off-by lines.
18
+ # This example catches duplicate Signed-off-by lines and messages that
19
+ # would confuse 'git am'.
20
+
21
+ ret=0
19
22
 
20
23
  test "" = "$(grep '^Signed-off-by: ' "$1" |
21
24
  sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
22
25
  echo >&2 Duplicate Signed-off-by lines.
23
- exit 1
26
+ ret=1
24
27
  }
28
+
29
+ comment_re="$(
30
+ {
31
+ git config --get-regexp "^core\.comment(char|string)\$" ||
32
+ echo '#'
33
+ } | sed -n -e '
34
+ ${
35
+ s/^[^ ]* //
36
+ s|[][*./\]|\\&|g
37
+ s/^auto$/[#;@!$%^&|:]/
38
+ p
39
+ }'
40
+ )"
41
+ scissors_line="^${comment_re} -\{8,\} >8 -\{8,\}\$"
42
+ comment_line="^${comment_re}.*"
43
+ blank_line='^[ ]*$'
44
+ # Disallow lines starting with "diff -" or "Index: " in the body of the
45
+ # message. Stop looking if we see a scissors line.
46
+ line="$(sed -n -e "
47
+ # Skip comments and blank lines at the start of the file.
48
+ /${scissors_line}/q
49
+ /${comment_line}/d
50
+ /${blank_line}/d
51
+ # The first paragraph will become the subject header so
52
+ # does not need to be checked.
53
+ : subject
54
+ n
55
+ /${scissors_line}/q
56
+ /${blank_line}/!b subject
57
+ # Check the body of the message for problematic
58
+ # prefixes.
59
+ : body
60
+ n
61
+ /${scissors_line}/q
62
+ /${comment_line}/b body
63
+ /^diff -/{p;q;}
64
+ /^Index: /{p;q;}
65
+ b body
66
+ " "$1")"
67
+ if test -n "$line"
68
+ then
69
+ echo >&2 "Message contains a diff that will confuse 'git am'."
70
+ echo >&2 "To fix this indent the diff."
71
+ ret=1
72
+ fi
73
+
74
+ exit $ret
@@ -29,8 +29,6 @@ if ($version ne 2) {
29
29
 
30
30
  my $git_work_tree = get_working_dir();
31
31
 
32
- my $retry = 1;
33
-
34
32
  my $json_pkg;
35
33
  eval {
36
34
  require JSON::XS;
@@ -123,8 +121,7 @@ sub watchman_query {
123
121
  sub is_work_tree_watched {
124
122
  my ($output) = @_;
125
123
  my $error = $output->{error};
126
- if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
127
- $retry--;
124
+ if ($error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
128
125
  my $response = qx/watchman watch "$git_work_tree"/;
129
126
  die "Failed to make watchman watch '$git_work_tree'.\n" .
130
127
  "Falling back to scanning...\n" if $? != 0;
@@ -142,15 +139,12 @@ sub is_work_tree_watched {
142
139
  # Watchman query just to get it over with now so we won't pay
143
140
  # the cost in git to look up each individual file.
144
141
  my $o = watchman_clock();
145
- $error = $output->{error};
142
+ $error = $o->{error};
146
143
 
147
144
  die "Watchman: $error.\n" .
148
145
  "Falling back to scanning...\n" if $error;
149
146
 
150
147
  output_result($o->{clock}, ("/"));
151
- $last_update_token = $o->{clock};
152
-
153
- eval { launch_watchman() };
154
148
  return 0;
155
149
  }
156
150
 
@@ -1,2 +1,2 @@
1
1
  # pack-refs with: peeled fully-peeled sorted
2
- 86033fc9aeae2ca6d52c7cdb675c1f4bf17fc1c1 refs/remotes/origin/main
2
+ 7cfa7711778f04c5df56f7ae895fabc942fd920c refs/remotes/origin/main
@@ -1 +1 @@
1
- 86033fc9aeae2ca6d52c7cdb675c1f4bf17fc1c1
1
+ 7cfa7711778f04c5df56f7ae895fabc942fd920c
@@ -1 +1 @@
1
- 86033fc9aeae2ca6d52c7cdb675c1f4bf17fc1c1
1
+ 7cfa7711778f04c5df56f7ae895fabc942fd920c
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "bmad-builder",
3
- "version": "1.7.0",
3
+ "version": "1.8.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "bmad-builder",
9
- "version": "1.7.0",
9
+ "version": "1.8.1",
10
10
  "license": "MIT",
11
11
  "devDependencies": {
12
12
  "@astrojs/sitemap": "^3.6.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "bmad-builder",
4
- "version": "1.7.0",
4
+ "version": "1.8.1",
5
5
  "private": true,
6
6
  "description": "A BMad Core expansion module that guides users through the creation of Modules Workflow and Agents",
7
7
  "keywords": [
@@ -1,4 +1,4 @@
1
- module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs
1
+ module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs
2
2
  Dream Weaver,bmad-agent-dream-weaver,Dream Capture,DL,"Capture and log a dream through guided conversation.",dream-log,,anytime,,,false,,journal entry
3
3
  Dream Weaver,bmad-agent-dream-weaver,Dream Interpretation,DI,"Analyze a dream for symbolism, meaning, and personal connections.",dream-interpret,,anytime,dw:dream-log,,false,,interpretation
4
4
  Dream Weaver,bmad-agent-dream-weaver,Recall Training,RT,"Dream recall exercises and progress tracking.",recall-training,,anytime,,,false,,coaching updates
@@ -339,9 +339,42 @@ def write_config(config: dict, config_path: str, verbose: bool = False) -> None:
339
339
  )
340
340
 
341
341
 
342
+ def reject_unresolved_paths(named_paths: list[tuple[str, str]]) -> None:
343
+ """Exit with a clear error if any path argument still contains the literal
344
+ ``{project-root}`` token. That token is meaningful only inside config
345
+ values; filesystem path arguments must be resolved by the caller. Failing
346
+ loudly here prevents silently creating a junk ``{project-root}/`` directory.
347
+ """
348
+ for name, value in named_paths:
349
+ if value and "{project-root}" in value:
350
+ print(
351
+ json.dumps(
352
+ {
353
+ "status": "error",
354
+ "error": (
355
+ f"Unresolved '{{project-root}}' token in {name} path: {value!r}. "
356
+ "Resolve '{project-root}' to the actual project root before running "
357
+ "this script — it is a filesystem path, not a config value."
358
+ ),
359
+ },
360
+ indent=2,
361
+ ),
362
+ file=sys.stderr,
363
+ )
364
+ sys.exit(1)
365
+
366
+
342
367
  def main():
343
368
  args = parse_args()
344
369
 
370
+ reject_unresolved_paths(
371
+ [
372
+ ("--config-path", args.config_path),
373
+ ("--user-config-path", args.user_config_path),
374
+ ("--legacy-dir", args.legacy_dir),
375
+ ]
376
+ )
377
+
345
378
  # Load inputs
346
379
  module_yaml = load_yaml_file(args.module_yaml)
347
380
  if not module_yaml:
@@ -139,9 +139,37 @@ def cleanup_legacy_csvs(
139
139
  return deleted
140
140
 
141
141
 
142
+ def reject_unresolved_paths(named_paths: list[tuple[str, str]]) -> None:
143
+ """Exit with a clear error if any path argument still contains the literal
144
+ ``{project-root}`` token. That token is meaningful only inside config
145
+ values; filesystem path arguments must be resolved by the caller. Failing
146
+ loudly here prevents silently creating a junk ``{project-root}/`` directory.
147
+ """
148
+ for name, value in named_paths:
149
+ if value and "{project-root}" in value:
150
+ print(
151
+ json.dumps(
152
+ {
153
+ "status": "error",
154
+ "error": (
155
+ f"Unresolved '{{project-root}}' token in {name} path: {value!r}. "
156
+ "Resolve '{project-root}' to the actual project root before running "
157
+ "this script — it is a filesystem path, not a config value."
158
+ ),
159
+ },
160
+ indent=2,
161
+ )
162
+ )
163
+ sys.exit(1)
164
+
165
+
142
166
  def main():
143
167
  args = parse_args()
144
168
 
169
+ reject_unresolved_paths(
170
+ [("--target", args.target), ("--legacy-dir", args.legacy_dir)]
171
+ )
172
+
145
173
  # Read source entries
146
174
  source_header, source_rows = read_csv_rows(args.source)
147
175
  if not source_rows:
@@ -1,4 +1,4 @@
1
- module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs
1
+ module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs
2
2
  BMad Samples,sample-module-setup,Setup Samples Module,SS,"Install or update BMad Samples module config and help entries.",configure,"{-H: headless mode}|{inline values: skip prompts with provided values}",anytime,,,false,{project-root}/_bmad,config.yaml and config.user.yaml
3
3
  BMad Samples,bmad-agent-code-coach,Code Coaching,TC,"Personal coding coaching and mentoring — code review, pair programming, and learning paths.",activate,,anytime,,,false,,coaching session
4
4
  BMad Samples,bmad-agent-creative-muse,Creative Muse,TM,"Creative brainstorming, problem-solving, and storytelling companion.",activate,,anytime,,,false,,creative session
@@ -197,9 +197,37 @@ def cleanup_directories(
197
197
  return removed, not_found, total_files
198
198
 
199
199
 
200
+ def reject_unresolved_paths(named_paths: list[tuple[str, str]]) -> None:
201
+ """Exit with a clear error if any path argument still contains the literal
202
+ ``{project-root}`` token. That token is meaningful only inside config
203
+ values; filesystem path arguments must be resolved by the caller. Failing
204
+ loudly here prevents silently operating on a junk ``{project-root}/`` directory.
205
+ """
206
+ for name, value in named_paths:
207
+ if value and "{project-root}" in value:
208
+ print(
209
+ json.dumps(
210
+ {
211
+ "status": "error",
212
+ "error": (
213
+ f"Unresolved '{{project-root}}' token in {name} path: {value!r}. "
214
+ "Resolve '{project-root}' to the actual project root before running "
215
+ "this script — it is a filesystem path, not a config value."
216
+ ),
217
+ },
218
+ indent=2,
219
+ )
220
+ )
221
+ sys.exit(1)
222
+
223
+
200
224
  def main():
201
225
  args = parse_args()
202
226
 
227
+ reject_unresolved_paths(
228
+ [("--bmad-dir", args.bmad_dir), ("--skills-dir", args.skills_dir)]
229
+ )
230
+
203
231
  bmad_dir = args.bmad_dir
204
232
  module_code = args.module_code
205
233
 
@@ -339,9 +339,42 @@ def write_config(config: dict, config_path: str, verbose: bool = False) -> None:
339
339
  )
340
340
 
341
341
 
342
+ def reject_unresolved_paths(named_paths: list[tuple[str, str]]) -> None:
343
+ """Exit with a clear error if any path argument still contains the literal
344
+ ``{project-root}`` token. That token is meaningful only inside config
345
+ values; filesystem path arguments must be resolved by the caller. Failing
346
+ loudly here prevents silently creating a junk ``{project-root}/`` directory.
347
+ """
348
+ for name, value in named_paths:
349
+ if value and "{project-root}" in value:
350
+ print(
351
+ json.dumps(
352
+ {
353
+ "status": "error",
354
+ "error": (
355
+ f"Unresolved '{{project-root}}' token in {name} path: {value!r}. "
356
+ "Resolve '{project-root}' to the actual project root before running "
357
+ "this script — it is a filesystem path, not a config value."
358
+ ),
359
+ },
360
+ indent=2,
361
+ ),
362
+ file=sys.stderr,
363
+ )
364
+ sys.exit(1)
365
+
366
+
342
367
  def main():
343
368
  args = parse_args()
344
369
 
370
+ reject_unresolved_paths(
371
+ [
372
+ ("--config-path", args.config_path),
373
+ ("--user-config-path", args.user_config_path),
374
+ ("--legacy-dir", args.legacy_dir),
375
+ ]
376
+ )
377
+
345
378
  # Load inputs
346
379
  module_yaml = load_yaml_file(args.module_yaml)
347
380
  if not module_yaml:
@@ -139,9 +139,37 @@ def cleanup_legacy_csvs(
139
139
  return deleted
140
140
 
141
141
 
142
+ def reject_unresolved_paths(named_paths: list[tuple[str, str]]) -> None:
143
+ """Exit with a clear error if any path argument still contains the literal
144
+ ``{project-root}`` token. That token is meaningful only inside config
145
+ values; filesystem path arguments must be resolved by the caller. Failing
146
+ loudly here prevents silently creating a junk ``{project-root}/`` directory.
147
+ """
148
+ for name, value in named_paths:
149
+ if value and "{project-root}" in value:
150
+ print(
151
+ json.dumps(
152
+ {
153
+ "status": "error",
154
+ "error": (
155
+ f"Unresolved '{{project-root}}' token in {name} path: {value!r}. "
156
+ "Resolve '{project-root}' to the actual project root before running "
157
+ "this script — it is a filesystem path, not a config value."
158
+ ),
159
+ },
160
+ indent=2,
161
+ )
162
+ )
163
+ sys.exit(1)
164
+
165
+
142
166
  def main():
143
167
  args = parse_args()
144
168
 
169
+ reject_unresolved_paths(
170
+ [("--target", args.target), ("--legacy-dir", args.legacy_dir)]
171
+ )
172
+
145
173
  # Read source entries
146
174
  source_header, source_rows = read_csv_rows(args.source)
147
175
  if not source_rows:
@@ -1,4 +1,4 @@
1
- module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs
1
+ module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs
2
2
  BMad Builder,bmad-bmb-setup,Setup Builder Module,SB,"Install or update BMad Builder module config and help entries.",configure,"{-H: headless mode}|{inline values: skip prompts with provided values}",anytime,,,false,{project-root}/_bmad,config.yaml and config.user.yaml
3
3
  BMad Builder,bmad-agent-builder,Build an Agent,BA,"Create, edit, or rebuild an agent skill through conversational discovery.",build-process,"{-H: headless mode}|{description: initial agent concept}|{path: existing agent to edit or rebuild}",anytime,,bmad-agent-builder:quality-analysis,false,bmad_builder_output_folder,agent skill
4
4
  BMad Builder,bmad-agent-builder,Analyze an Agent,AA,"Run quality analysis on an existing agent — structure, cohesion, prompt craft, and enhancement opportunities.",quality-analysis,"{-H: headless mode}|{path: agent to analyze}",anytime,bmad-agent-builder:build-process,,false,bmad_builder_reports,quality report
@@ -197,9 +197,37 @@ def cleanup_directories(
197
197
  return removed, not_found, total_files
198
198
 
199
199
 
200
+ def reject_unresolved_paths(named_paths: list[tuple[str, str]]) -> None:
201
+ """Exit with a clear error if any path argument still contains the literal
202
+ ``{project-root}`` token. That token is meaningful only inside config
203
+ values; filesystem path arguments must be resolved by the caller. Failing
204
+ loudly here prevents silently operating on a junk ``{project-root}/`` directory.
205
+ """
206
+ for name, value in named_paths:
207
+ if value and "{project-root}" in value:
208
+ print(
209
+ json.dumps(
210
+ {
211
+ "status": "error",
212
+ "error": (
213
+ f"Unresolved '{{project-root}}' token in {name} path: {value!r}. "
214
+ "Resolve '{project-root}' to the actual project root before running "
215
+ "this script — it is a filesystem path, not a config value."
216
+ ),
217
+ },
218
+ indent=2,
219
+ )
220
+ )
221
+ sys.exit(1)
222
+
223
+
200
224
  def main():
201
225
  args = parse_args()
202
226
 
227
+ reject_unresolved_paths(
228
+ [("--bmad-dir", args.bmad_dir), ("--skills-dir", args.skills_dir)]
229
+ )
230
+
203
231
  bmad_dir = args.bmad_dir
204
232
  module_code = args.module_code
205
233
 
@@ -339,9 +339,42 @@ def write_config(config: dict, config_path: str, verbose: bool = False) -> None:
339
339
  )
340
340
 
341
341
 
342
+ def reject_unresolved_paths(named_paths: list[tuple[str, str]]) -> None:
343
+ """Exit with a clear error if any path argument still contains the literal
344
+ ``{project-root}`` token. That token is meaningful only inside config
345
+ values; filesystem path arguments must be resolved by the caller. Failing
346
+ loudly here prevents silently creating a junk ``{project-root}/`` directory.
347
+ """
348
+ for name, value in named_paths:
349
+ if value and "{project-root}" in value:
350
+ print(
351
+ json.dumps(
352
+ {
353
+ "status": "error",
354
+ "error": (
355
+ f"Unresolved '{{project-root}}' token in {name} path: {value!r}. "
356
+ "Resolve '{project-root}' to the actual project root before running "
357
+ "this script — it is a filesystem path, not a config value."
358
+ ),
359
+ },
360
+ indent=2,
361
+ ),
362
+ file=sys.stderr,
363
+ )
364
+ sys.exit(1)
365
+
366
+
342
367
  def main():
343
368
  args = parse_args()
344
369
 
370
+ reject_unresolved_paths(
371
+ [
372
+ ("--config-path", args.config_path),
373
+ ("--user-config-path", args.user_config_path),
374
+ ("--legacy-dir", args.legacy_dir),
375
+ ]
376
+ )
377
+
345
378
  # Load inputs
346
379
  module_yaml = load_yaml_file(args.module_yaml)
347
380
  if not module_yaml:
@@ -139,9 +139,37 @@ def cleanup_legacy_csvs(
139
139
  return deleted
140
140
 
141
141
 
142
+ def reject_unresolved_paths(named_paths: list[tuple[str, str]]) -> None:
143
+ """Exit with a clear error if any path argument still contains the literal
144
+ ``{project-root}`` token. That token is meaningful only inside config
145
+ values; filesystem path arguments must be resolved by the caller. Failing
146
+ loudly here prevents silently creating a junk ``{project-root}/`` directory.
147
+ """
148
+ for name, value in named_paths:
149
+ if value and "{project-root}" in value:
150
+ print(
151
+ json.dumps(
152
+ {
153
+ "status": "error",
154
+ "error": (
155
+ f"Unresolved '{{project-root}}' token in {name} path: {value!r}. "
156
+ "Resolve '{project-root}' to the actual project root before running "
157
+ "this script — it is a filesystem path, not a config value."
158
+ ),
159
+ },
160
+ indent=2,
161
+ )
162
+ )
163
+ sys.exit(1)
164
+
165
+
142
166
  def main():
143
167
  args = parse_args()
144
168
 
169
+ reject_unresolved_paths(
170
+ [("--target", args.target), ("--legacy-dir", args.legacy_dir)]
171
+ )
172
+
145
173
  # Read source entries
146
174
  source_header, source_rows = read_csv_rows(args.source)
147
175
  if not source_rows:
@@ -0,0 +1,29 @@
1
+ FROM node:20-bookworm-slim
2
+
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+
5
+ RUN apt-get update \
6
+ && apt-get install -y --no-install-recommends \
7
+ git \
8
+ python3 \
9
+ python3-pip \
10
+ ca-certificates \
11
+ curl \
12
+ jq \
13
+ rsync \
14
+ && rm -rf /var/lib/apt/lists/*
15
+
16
+ RUN npm install -g @anthropic-ai/claude-code
17
+
18
+ RUN useradd -ms /bin/bash evaluator \
19
+ && mkdir -p /workspace /project /output /home/evaluator/.claude \
20
+ && chown -R evaluator:evaluator /workspace /output /home/evaluator
21
+
22
+ USER evaluator
23
+ WORKDIR /workspace
24
+
25
+ ENV HOME=/home/evaluator
26
+ ENV CLAUDE_CONFIG_DIR=/home/evaluator/.claude
27
+ ENV PATH=/home/evaluator/.local/bin:$PATH
28
+
29
+ CMD ["bash"]