bmad-method 5.1.3 → 6.0.0-Beta.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 (739) hide show
  1. package/.coderabbit.yaml +40 -0
  2. package/.github/CODE_OF_CONDUCT.md +128 -0
  3. package/.github/FUNDING.yaml +2 -2
  4. package/.github/ISSUE_TEMPLATE/config.yaml +8 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.md +11 -11
  6. package/.github/ISSUE_TEMPLATE/issue.md +32 -0
  7. package/.github/scripts/discord-helpers.sh +34 -0
  8. package/.github/workflows/discord.yaml +82 -17
  9. package/.github/workflows/docs.yaml +63 -0
  10. package/.github/workflows/manual-release.yaml +40 -20
  11. package/.github/workflows/quality.yaml +115 -0
  12. package/.husky/pre-commit +17 -0
  13. package/.markdownlint-cli2.yaml +41 -0
  14. package/.nvmrc +1 -0
  15. package/.prettierignore +9 -0
  16. package/.vscode/settings.json +38 -10
  17. package/CHANGELOG.md +1167 -372
  18. package/CNAME +1 -0
  19. package/CONTRIBUTING.md +100 -142
  20. package/CONTRIBUTORS.md +32 -0
  21. package/LICENSE +10 -1
  22. package/README.md +67 -170
  23. package/SECURITY.md +85 -0
  24. package/TRADEMARK.md +55 -0
  25. package/Wordmark.png +0 -0
  26. package/banner-bmad-method.png +0 -0
  27. package/docs/404.md +9 -0
  28. package/docs/_STYLE_GUIDE.md +367 -0
  29. package/docs/downloads.md +74 -0
  30. package/docs/explanation/advanced-elicitation.md +24 -0
  31. package/docs/explanation/adversarial-review.md +57 -0
  32. package/docs/explanation/brainstorming.md +31 -0
  33. package/docs/explanation/brownfield-faq.md +55 -0
  34. package/docs/explanation/party-mode.md +57 -0
  35. package/docs/explanation/preventing-agent-conflicts.md +110 -0
  36. package/docs/explanation/quick-flow.md +27 -0
  37. package/docs/explanation/why-solutioning-matters.md +75 -0
  38. package/docs/how-to/brownfield/index.md +84 -0
  39. package/docs/how-to/brownfield/quick-fix-in-brownfield.md +76 -0
  40. package/docs/how-to/customize-bmad.md +158 -0
  41. package/docs/how-to/get-answers-about-bmad.md +102 -0
  42. package/docs/how-to/install-bmad.md +82 -0
  43. package/docs/how-to/shard-large-documents.md +101 -0
  44. package/docs/how-to/upgrade-to-v6.md +131 -0
  45. package/docs/index.md +56 -0
  46. package/docs/reference/workflow-map.md +83 -0
  47. package/docs/tea/explanation/engagement-models.md +710 -0
  48. package/docs/tea/explanation/fixture-architecture.md +457 -0
  49. package/docs/tea/explanation/knowledge-base-system.md +554 -0
  50. package/docs/tea/explanation/network-first-patterns.md +853 -0
  51. package/docs/tea/explanation/risk-based-testing.md +586 -0
  52. package/docs/tea/explanation/tea-overview.md +410 -0
  53. package/docs/tea/explanation/test-quality-standards.md +907 -0
  54. package/docs/tea/explanation/testing-as-engineering.md +112 -0
  55. package/docs/tea/glossary/index.md +159 -0
  56. package/docs/tea/how-to/brownfield/use-tea-for-enterprise.md +525 -0
  57. package/docs/tea/how-to/brownfield/use-tea-with-existing-tests.md +577 -0
  58. package/docs/tea/how-to/customization/enable-tea-mcp-enhancements.md +424 -0
  59. package/docs/tea/how-to/customization/integrate-playwright-utils.md +813 -0
  60. package/docs/tea/how-to/workflows/run-atdd.md +436 -0
  61. package/docs/tea/how-to/workflows/run-automate.md +653 -0
  62. package/docs/tea/how-to/workflows/run-nfr-assess.md +679 -0
  63. package/docs/tea/how-to/workflows/run-test-design.md +135 -0
  64. package/docs/tea/how-to/workflows/run-test-review.md +605 -0
  65. package/docs/tea/how-to/workflows/run-trace.md +883 -0
  66. package/docs/tea/how-to/workflows/setup-ci.md +712 -0
  67. package/docs/tea/how-to/workflows/setup-test-framework.md +98 -0
  68. package/docs/tea/reference/commands.md +276 -0
  69. package/docs/tea/reference/configuration.md +678 -0
  70. package/docs/tea/reference/knowledge-base.md +340 -0
  71. package/docs/tea/tutorials/tea-lite-quickstart.md +444 -0
  72. package/docs/tutorials/getting-started.md +205 -0
  73. package/eslint.config.mjs +42 -9
  74. package/package.json +50 -38
  75. package/prettier.config.mjs +1 -1
  76. package/src/bmm/_module-installer/installer.js +48 -0
  77. package/src/bmm/agents/analyst.agent.yaml +36 -0
  78. package/src/bmm/agents/architect.agent.yaml +28 -0
  79. package/src/bmm/agents/dev.agent.yaml +38 -0
  80. package/src/bmm/agents/pm.agent.yaml +46 -0
  81. package/src/bmm/agents/quick-flow-solo-dev.agent.yaml +32 -0
  82. package/src/bmm/agents/sm.agent.yaml +36 -0
  83. package/src/bmm/agents/tea.agent.yaml +63 -0
  84. package/src/bmm/agents/tech-writer/tech-writer-sidecar/documentation-standards.md +224 -0
  85. package/src/bmm/agents/tech-writer/tech-writer.agent.yaml +45 -0
  86. package/src/bmm/agents/ux-designer.agent.yaml +26 -0
  87. package/src/bmm/data/project-context-template.md +26 -0
  88. package/src/bmm/module-help.csv +32 -0
  89. package/src/bmm/module.yaml +44 -0
  90. package/src/bmm/teams/default-party.csv +21 -0
  91. package/src/bmm/teams/team-fullstack.yaml +12 -0
  92. package/src/bmm/testarch/knowledge/adr-quality-readiness-checklist.md +350 -0
  93. package/src/bmm/testarch/knowledge/api-request.md +442 -0
  94. package/src/bmm/testarch/knowledge/api-testing-patterns.md +843 -0
  95. package/src/bmm/testarch/knowledge/auth-session.md +552 -0
  96. package/src/bmm/testarch/knowledge/burn-in.md +273 -0
  97. package/src/bmm/testarch/knowledge/ci-burn-in.md +675 -0
  98. package/src/bmm/testarch/knowledge/component-tdd.md +486 -0
  99. package/src/bmm/testarch/knowledge/contract-testing.md +957 -0
  100. package/src/bmm/testarch/knowledge/data-factories.md +500 -0
  101. package/src/bmm/testarch/knowledge/email-auth.md +721 -0
  102. package/src/bmm/testarch/knowledge/error-handling.md +725 -0
  103. package/src/bmm/testarch/knowledge/feature-flags.md +750 -0
  104. package/src/bmm/testarch/knowledge/file-utils.md +463 -0
  105. package/src/bmm/testarch/knowledge/fixture-architecture.md +401 -0
  106. package/src/bmm/testarch/knowledge/fixtures-composition.md +382 -0
  107. package/src/bmm/testarch/knowledge/intercept-network-call.md +430 -0
  108. package/src/bmm/testarch/knowledge/log.md +429 -0
  109. package/src/bmm/testarch/knowledge/network-error-monitor.md +405 -0
  110. package/src/bmm/testarch/knowledge/network-first.md +486 -0
  111. package/src/bmm/testarch/knowledge/network-recorder.md +527 -0
  112. package/src/bmm/testarch/knowledge/nfr-criteria.md +670 -0
  113. package/src/bmm/testarch/knowledge/overview.md +286 -0
  114. package/src/bmm/testarch/knowledge/playwright-config.md +730 -0
  115. package/src/bmm/testarch/knowledge/probability-impact.md +601 -0
  116. package/src/bmm/testarch/knowledge/recurse.md +421 -0
  117. package/src/bmm/testarch/knowledge/risk-governance.md +615 -0
  118. package/src/bmm/testarch/knowledge/selective-testing.md +732 -0
  119. package/src/bmm/testarch/knowledge/selector-resilience.md +527 -0
  120. package/src/bmm/testarch/knowledge/test-healing-patterns.md +644 -0
  121. package/src/bmm/testarch/knowledge/test-levels-framework.md +473 -0
  122. package/src/bmm/testarch/knowledge/test-priorities-matrix.md +373 -0
  123. package/src/bmm/testarch/knowledge/test-quality.md +664 -0
  124. package/src/bmm/testarch/knowledge/timing-debugging.md +372 -0
  125. package/src/bmm/testarch/knowledge/visual-debugging.md +524 -0
  126. package/src/bmm/testarch/tea-index.csv +35 -0
  127. package/src/bmm/workflows/1-analysis/create-product-brief/product-brief.template.md +10 -0
  128. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +177 -0
  129. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +161 -0
  130. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +199 -0
  131. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +202 -0
  132. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +205 -0
  133. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +219 -0
  134. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +162 -0
  135. package/src/bmm/workflows/1-analysis/create-product-brief/workflow.md +58 -0
  136. package/src/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +137 -0
  137. package/src/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +229 -0
  138. package/src/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +238 -0
  139. package/src/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +206 -0
  140. package/src/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +234 -0
  141. package/src/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +443 -0
  142. package/src/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +182 -0
  143. package/src/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +237 -0
  144. package/src/bmm/workflows/1-analysis/research/market-steps/step-02-customer-insights.md +200 -0
  145. package/src/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +249 -0
  146. package/src/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +259 -0
  147. package/src/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +177 -0
  148. package/src/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +475 -0
  149. package/src/bmm/workflows/1-analysis/research/research.template.md +29 -0
  150. package/src/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +137 -0
  151. package/src/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +239 -0
  152. package/src/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +248 -0
  153. package/src/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +202 -0
  154. package/src/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +239 -0
  155. package/src/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +486 -0
  156. package/src/bmm/workflows/1-analysis/research/workflow.md +173 -0
  157. package/src/bmm/workflows/2-plan-workflows/create-prd/data/domain-complexity.csv +13 -0
  158. package/src/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md +197 -0
  159. package/src/bmm/workflows/2-plan-workflows/create-prd/data/project-types.csv +11 -0
  160. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01-init.md +191 -0
  161. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01b-continue.md +153 -0
  162. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +224 -0
  163. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +226 -0
  164. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +213 -0
  165. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +207 -0
  166. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +226 -0
  167. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +237 -0
  168. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +228 -0
  169. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +231 -0
  170. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +242 -0
  171. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +217 -0
  172. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +124 -0
  173. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +247 -0
  174. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +208 -0
  175. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +249 -0
  176. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +253 -0
  177. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-04-complete.md +168 -0
  178. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +218 -0
  179. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +191 -0
  180. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +209 -0
  181. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +174 -0
  182. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +214 -0
  183. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +228 -0
  184. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +217 -0
  185. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +205 -0
  186. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +243 -0
  187. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +263 -0
  188. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +209 -0
  189. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +264 -0
  190. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +242 -0
  191. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +231 -0
  192. package/src/bmm/workflows/2-plan-workflows/create-prd/templates/prd-template.md +10 -0
  193. package/src/bmm/workflows/2-plan-workflows/create-prd/validation-report-prd-workflow.md +433 -0
  194. package/src/bmm/workflows/2-plan-workflows/create-prd/workflow.md +150 -0
  195. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01-init.md +135 -0
  196. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +127 -0
  197. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +190 -0
  198. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +216 -0
  199. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +219 -0
  200. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +234 -0
  201. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +252 -0
  202. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +254 -0
  203. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +224 -0
  204. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +224 -0
  205. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +241 -0
  206. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +248 -0
  207. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +237 -0
  208. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +264 -0
  209. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +171 -0
  210. package/src/bmm/workflows/2-plan-workflows/create-ux-design/ux-design-template.md +13 -0
  211. package/src/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +43 -0
  212. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +190 -0
  213. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +178 -0
  214. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +179 -0
  215. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +139 -0
  216. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +252 -0
  217. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +135 -0
  218. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/templates/readiness-report-template.md +4 -0
  219. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +55 -0
  220. package/src/bmm/workflows/3-solutioning/create-architecture/architecture-decision-template.md +12 -0
  221. package/src/bmm/workflows/3-solutioning/create-architecture/data/domain-complexity.csv +11 -0
  222. package/src/bmm/workflows/3-solutioning/create-architecture/data/project-types.csv +7 -0
  223. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01-init.md +153 -0
  224. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +164 -0
  225. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +224 -0
  226. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +331 -0
  227. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +318 -0
  228. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +359 -0
  229. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +379 -0
  230. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +359 -0
  231. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +76 -0
  232. package/src/bmm/workflows/3-solutioning/create-architecture/workflow.md +50 -0
  233. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md +259 -0
  234. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +233 -0
  235. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +272 -0
  236. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +149 -0
  237. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/templates/epics-template.md +57 -0
  238. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +59 -0
  239. package/src/bmm/workflows/4-implementation/code-review/checklist.md +23 -0
  240. package/src/bmm/workflows/4-implementation/code-review/instructions.xml +227 -0
  241. package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +51 -0
  242. package/src/bmm/workflows/4-implementation/correct-course/checklist.md +288 -0
  243. package/src/bmm/workflows/4-implementation/correct-course/instructions.md +206 -0
  244. package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +60 -0
  245. package/src/bmm/workflows/4-implementation/create-story/checklist.md +358 -0
  246. package/src/bmm/workflows/4-implementation/create-story/instructions.xml +345 -0
  247. package/src/bmm/workflows/4-implementation/create-story/template.md +49 -0
  248. package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +61 -0
  249. package/src/bmm/workflows/4-implementation/dev-story/checklist.md +80 -0
  250. package/src/bmm/workflows/4-implementation/dev-story/instructions.xml +410 -0
  251. package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +27 -0
  252. package/src/bmm/workflows/4-implementation/retrospective/instructions.md +1443 -0
  253. package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +58 -0
  254. package/src/bmm/workflows/4-implementation/sprint-planning/checklist.md +33 -0
  255. package/src/bmm/workflows/4-implementation/sprint-planning/instructions.md +225 -0
  256. package/src/bmm/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +55 -0
  257. package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +54 -0
  258. package/src/bmm/workflows/4-implementation/sprint-status/instructions.md +229 -0
  259. package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +36 -0
  260. package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +176 -0
  261. package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +120 -0
  262. package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +113 -0
  263. package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +113 -0
  264. package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +106 -0
  265. package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-06-resolve-findings.md +149 -0
  266. package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +50 -0
  267. package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-01-understand.md +192 -0
  268. package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +145 -0
  269. package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +128 -0
  270. package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +201 -0
  271. package/src/bmm/workflows/bmad-quick-flow/quick-spec/tech-spec-template.md +74 -0
  272. package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +79 -0
  273. package/src/bmm/workflows/document-project/checklist.md +245 -0
  274. package/src/bmm/workflows/document-project/documentation-requirements.csv +12 -0
  275. package/src/bmm/workflows/document-project/instructions.md +221 -0
  276. package/src/bmm/workflows/document-project/templates/deep-dive-template.md +345 -0
  277. package/src/bmm/workflows/document-project/templates/index-template.md +169 -0
  278. package/src/bmm/workflows/document-project/templates/project-overview-template.md +103 -0
  279. package/src/bmm/workflows/document-project/templates/project-scan-report-schema.json +160 -0
  280. package/src/bmm/workflows/document-project/templates/source-tree-template.md +135 -0
  281. package/src/bmm/workflows/document-project/workflow.yaml +30 -0
  282. package/src/bmm/workflows/document-project/workflows/deep-dive-instructions.md +298 -0
  283. package/src/bmm/workflows/document-project/workflows/deep-dive.yaml +31 -0
  284. package/src/bmm/workflows/document-project/workflows/full-scan-instructions.md +1106 -0
  285. package/src/bmm/workflows/document-project/workflows/full-scan.yaml +31 -0
  286. package/src/bmm/workflows/excalidraw-diagrams/_shared/excalidraw-library.json +90 -0
  287. package/src/bmm/workflows/excalidraw-diagrams/_shared/excalidraw-templates.yaml +127 -0
  288. package/src/bmm/workflows/excalidraw-diagrams/create-dataflow/checklist.md +39 -0
  289. package/src/bmm/workflows/excalidraw-diagrams/create-dataflow/instructions.md +130 -0
  290. package/src/bmm/workflows/excalidraw-diagrams/create-dataflow/workflow.yaml +27 -0
  291. package/src/bmm/workflows/excalidraw-diagrams/create-diagram/checklist.md +43 -0
  292. package/src/bmm/workflows/excalidraw-diagrams/create-diagram/instructions.md +141 -0
  293. package/src/bmm/workflows/excalidraw-diagrams/create-diagram/workflow.yaml +27 -0
  294. package/src/bmm/workflows/excalidraw-diagrams/create-flowchart/checklist.md +49 -0
  295. package/src/bmm/workflows/excalidraw-diagrams/create-flowchart/instructions.md +241 -0
  296. package/src/bmm/workflows/excalidraw-diagrams/create-flowchart/workflow.yaml +27 -0
  297. package/src/bmm/workflows/excalidraw-diagrams/create-wireframe/checklist.md +38 -0
  298. package/src/bmm/workflows/excalidraw-diagrams/create-wireframe/instructions.md +133 -0
  299. package/src/bmm/workflows/excalidraw-diagrams/create-wireframe/workflow.yaml +27 -0
  300. package/src/bmm/workflows/testarch/atdd/atdd-checklist-template.md +363 -0
  301. package/src/bmm/workflows/testarch/atdd/checklist.md +374 -0
  302. package/src/bmm/workflows/testarch/atdd/instructions.md +806 -0
  303. package/src/bmm/workflows/testarch/atdd/workflow.yaml +47 -0
  304. package/src/bmm/workflows/testarch/automate/checklist.md +582 -0
  305. package/src/bmm/workflows/testarch/automate/instructions.md +1324 -0
  306. package/src/bmm/workflows/testarch/automate/workflow.yaml +54 -0
  307. package/src/bmm/workflows/testarch/ci/checklist.md +247 -0
  308. package/src/bmm/workflows/testarch/ci/github-actions-template.yaml +198 -0
  309. package/src/bmm/workflows/testarch/ci/gitlab-ci-template.yaml +149 -0
  310. package/src/bmm/workflows/testarch/ci/instructions.md +536 -0
  311. package/src/bmm/workflows/testarch/ci/workflow.yaml +47 -0
  312. package/src/bmm/workflows/testarch/framework/checklist.md +320 -0
  313. package/src/bmm/workflows/testarch/framework/instructions.md +481 -0
  314. package/src/bmm/workflows/testarch/framework/workflow.yaml +49 -0
  315. package/src/bmm/workflows/testarch/nfr-assess/checklist.md +407 -0
  316. package/src/bmm/workflows/testarch/nfr-assess/instructions.md +726 -0
  317. package/src/bmm/workflows/testarch/nfr-assess/nfr-report-template.md +461 -0
  318. package/src/bmm/workflows/testarch/nfr-assess/workflow.yaml +49 -0
  319. package/src/bmm/workflows/testarch/test-design/checklist.md +407 -0
  320. package/src/bmm/workflows/testarch/test-design/instructions.md +1158 -0
  321. package/src/bmm/workflows/testarch/test-design/test-design-architecture-template.md +213 -0
  322. package/src/bmm/workflows/testarch/test-design/test-design-qa-template.md +286 -0
  323. package/src/bmm/workflows/testarch/test-design/test-design-template.md +294 -0
  324. package/src/bmm/workflows/testarch/test-design/workflow.yaml +71 -0
  325. package/src/bmm/workflows/testarch/test-review/checklist.md +472 -0
  326. package/src/bmm/workflows/testarch/test-review/instructions.md +628 -0
  327. package/src/bmm/workflows/testarch/test-review/test-review-template.md +390 -0
  328. package/src/bmm/workflows/testarch/test-review/workflow.yaml +48 -0
  329. package/src/bmm/workflows/testarch/trace/checklist.md +642 -0
  330. package/src/bmm/workflows/testarch/trace/instructions.md +1030 -0
  331. package/src/bmm/workflows/testarch/trace/trace-template.md +675 -0
  332. package/src/bmm/workflows/testarch/trace/workflow.yaml +57 -0
  333. package/src/core/_module-installer/installer.js +60 -0
  334. package/src/core/agents/bmad-master.agent.yaml +29 -0
  335. package/src/core/module-help.csv +9 -0
  336. package/src/core/module.yaml +25 -0
  337. package/src/core/resources/excalidraw/README.md +160 -0
  338. package/src/core/resources/excalidraw/excalidraw-helpers.md +127 -0
  339. package/src/core/resources/excalidraw/library-loader.md +50 -0
  340. package/src/core/resources/excalidraw/validate-json-instructions.md +79 -0
  341. package/src/core/tasks/editorial-review-prose.xml +100 -0
  342. package/src/core/tasks/editorial-review-structure.xml +209 -0
  343. package/src/core/tasks/help.md +62 -0
  344. package/src/core/tasks/index-docs.xml +65 -0
  345. package/src/core/tasks/review-adversarial-general.xml +48 -0
  346. package/src/core/tasks/shard-doc.xml +109 -0
  347. package/src/core/tasks/workflow.xml +235 -0
  348. package/src/core/workflows/advanced-elicitation/methods.csv +51 -0
  349. package/src/core/workflows/advanced-elicitation/workflow.xml +117 -0
  350. package/src/core/workflows/brainstorming/brain-methods.csv +62 -0
  351. package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +197 -0
  352. package/src/core/workflows/brainstorming/steps/step-01b-continue.md +122 -0
  353. package/src/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -0
  354. package/src/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -0
  355. package/src/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -0
  356. package/src/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -0
  357. package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +399 -0
  358. package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -0
  359. package/src/core/workflows/brainstorming/template.md +15 -0
  360. package/src/core/workflows/brainstorming/workflow.md +58 -0
  361. package/src/core/workflows/party-mode/steps/step-01-agent-loading.md +138 -0
  362. package/src/core/workflows/party-mode/steps/step-02-discussion-orchestration.md +187 -0
  363. package/src/core/workflows/party-mode/steps/step-03-graceful-exit.md +157 -0
  364. package/src/core/workflows/party-mode/workflow.md +194 -0
  365. package/src/utility/agent-components/activation-rules.txt +6 -0
  366. package/src/utility/agent-components/activation-steps.txt +14 -0
  367. package/src/utility/agent-components/agent-command-header.md +1 -0
  368. package/src/utility/agent-components/agent.customize.template.yaml +41 -0
  369. package/src/utility/agent-components/handler-action.txt +4 -0
  370. package/src/utility/agent-components/handler-data.txt +5 -0
  371. package/src/utility/agent-components/handler-exec.txt +6 -0
  372. package/src/utility/agent-components/handler-multi.txt +14 -0
  373. package/src/utility/agent-components/handler-tmpl.txt +5 -0
  374. package/src/utility/agent-components/handler-validate-workflow.txt +7 -0
  375. package/src/utility/agent-components/handler-workflow.txt +10 -0
  376. package/src/utility/agent-components/menu-handlers.txt +6 -0
  377. package/test/README.md +295 -0
  378. package/test/adversarial-review-tests/README.md +56 -0
  379. package/test/adversarial-review-tests/sample-content.md +46 -0
  380. package/test/adversarial-review-tests/test-cases.yaml +103 -0
  381. package/test/fixtures/agent-schema/invalid/critical-actions/actions-as-string.agent.yaml +27 -0
  382. package/test/fixtures/agent-schema/invalid/critical-actions/empty-string-in-actions.agent.yaml +30 -0
  383. package/test/fixtures/agent-schema/invalid/menu/empty-menu.agent.yaml +22 -0
  384. package/test/fixtures/agent-schema/invalid/menu/missing-menu.agent.yaml +20 -0
  385. package/test/fixtures/agent-schema/invalid/menu-commands/empty-command-target.agent.yaml +25 -0
  386. package/test/fixtures/agent-schema/invalid/menu-commands/no-command-target.agent.yaml +24 -0
  387. package/test/fixtures/agent-schema/invalid/menu-triggers/camel-case.agent.yaml +25 -0
  388. package/test/fixtures/agent-schema/invalid/menu-triggers/compound-invalid-format.agent.yaml +25 -0
  389. package/test/fixtures/agent-schema/invalid/menu-triggers/compound-mismatched-kebab.agent.yaml +25 -0
  390. package/test/fixtures/agent-schema/invalid/menu-triggers/duplicate-triggers.agent.yaml +31 -0
  391. package/test/fixtures/agent-schema/invalid/menu-triggers/empty-trigger.agent.yaml +25 -0
  392. package/test/fixtures/agent-schema/invalid/menu-triggers/leading-asterisk.agent.yaml +25 -0
  393. package/test/fixtures/agent-schema/invalid/menu-triggers/snake-case.agent.yaml +25 -0
  394. package/test/fixtures/agent-schema/invalid/menu-triggers/trigger-with-spaces.agent.yaml +25 -0
  395. package/test/fixtures/agent-schema/invalid/metadata/empty-module-string.agent.yaml +26 -0
  396. package/test/fixtures/agent-schema/invalid/metadata/empty-name.agent.yaml +24 -0
  397. package/test/fixtures/agent-schema/invalid/metadata/extra-metadata-fields.agent.yaml +27 -0
  398. package/test/fixtures/agent-schema/invalid/metadata/missing-id.agent.yaml +23 -0
  399. package/test/fixtures/agent-schema/invalid/persona/empty-principles-array.agent.yaml +24 -0
  400. package/test/fixtures/agent-schema/invalid/persona/empty-string-in-principles.agent.yaml +27 -0
  401. package/test/fixtures/agent-schema/invalid/persona/extra-persona-fields.agent.yaml +27 -0
  402. package/test/fixtures/agent-schema/invalid/persona/missing-role.agent.yaml +24 -0
  403. package/test/fixtures/agent-schema/invalid/prompts/empty-content.agent.yaml +29 -0
  404. package/test/fixtures/agent-schema/invalid/prompts/extra-prompt-fields.agent.yaml +31 -0
  405. package/test/fixtures/agent-schema/invalid/prompts/missing-content.agent.yaml +28 -0
  406. package/test/fixtures/agent-schema/invalid/prompts/missing-id.agent.yaml +28 -0
  407. package/test/fixtures/agent-schema/invalid/top-level/empty-file.agent.yaml +5 -0
  408. package/test/fixtures/agent-schema/invalid/top-level/extra-top-level-keys.agent.yaml +28 -0
  409. package/test/fixtures/agent-schema/invalid/top-level/missing-agent-key.agent.yaml +11 -0
  410. package/test/fixtures/agent-schema/invalid/yaml-errors/invalid-indentation.agent.yaml +19 -0
  411. package/test/fixtures/agent-schema/invalid/yaml-errors/malformed-yaml.agent.yaml +18 -0
  412. package/test/fixtures/agent-schema/valid/critical-actions/empty-critical-actions.agent.yaml +24 -0
  413. package/test/fixtures/agent-schema/valid/critical-actions/no-critical-actions.agent.yaml +22 -0
  414. package/test/fixtures/agent-schema/valid/critical-actions/valid-critical-actions.agent.yaml +27 -0
  415. package/test/fixtures/agent-schema/valid/menu/multiple-menu-items.agent.yaml +31 -0
  416. package/test/fixtures/agent-schema/valid/menu/single-menu-item.agent.yaml +22 -0
  417. package/test/fixtures/agent-schema/valid/menu-commands/all-command-types.agent.yaml +38 -0
  418. package/test/fixtures/agent-schema/valid/menu-commands/multiple-commands.agent.yaml +24 -0
  419. package/test/fixtures/agent-schema/valid/menu-triggers/compound-triggers.agent.yaml +31 -0
  420. package/test/fixtures/agent-schema/valid/menu-triggers/kebab-case-triggers.agent.yaml +34 -0
  421. package/test/fixtures/agent-schema/valid/metadata/core-agent-with-module.agent.yaml +24 -0
  422. package/test/fixtures/agent-schema/valid/metadata/empty-module-name-in-path.agent.yaml +24 -0
  423. package/test/fixtures/agent-schema/valid/metadata/malformed-path-treated-as-core.agent.yaml +24 -0
  424. package/test/fixtures/agent-schema/valid/metadata/module-agent-correct.agent.yaml +24 -0
  425. package/test/fixtures/agent-schema/valid/metadata/module-agent-missing-module.agent.yaml +23 -0
  426. package/test/fixtures/agent-schema/valid/metadata/wrong-module-value.agent.yaml +24 -0
  427. package/test/fixtures/agent-schema/valid/persona/complete-persona.agent.yaml +24 -0
  428. package/test/fixtures/agent-schema/valid/prompts/empty-prompts.agent.yaml +24 -0
  429. package/test/fixtures/agent-schema/valid/prompts/no-prompts.agent.yaml +22 -0
  430. package/test/fixtures/agent-schema/valid/prompts/valid-prompts-minimal.agent.yaml +28 -0
  431. package/test/fixtures/agent-schema/valid/prompts/valid-prompts-with-description.agent.yaml +30 -0
  432. package/test/fixtures/agent-schema/valid/top-level/minimal-core-agent.agent.yaml +24 -0
  433. package/test/test-agent-schema.js +387 -0
  434. package/test/test-cli-integration.sh +159 -0
  435. package/test/test-installation-components.js +214 -0
  436. package/test/unit-test-schema.js +133 -0
  437. package/tools/bmad-npx-wrapper.js +11 -12
  438. package/tools/build-docs.js +577 -0
  439. package/tools/cli/README.md +7 -0
  440. package/tools/cli/bmad-cli.js +58 -0
  441. package/tools/cli/commands/install.js +87 -0
  442. package/tools/cli/commands/status.js +65 -0
  443. package/tools/cli/external-official-modules.yaml +44 -0
  444. package/tools/cli/installers/install-messages.yaml +58 -0
  445. package/tools/cli/installers/lib/core/config-collector.js +1079 -0
  446. package/tools/cli/installers/lib/core/custom-module-cache.js +259 -0
  447. package/tools/cli/installers/lib/core/dependency-resolver.js +739 -0
  448. package/tools/cli/installers/lib/core/detector.js +223 -0
  449. package/tools/cli/installers/lib/core/ide-config-manager.js +156 -0
  450. package/tools/cli/installers/lib/core/installer.js +2826 -0
  451. package/tools/cli/installers/lib/core/manifest-generator.js +1054 -0
  452. package/tools/cli/installers/lib/core/manifest.js +1036 -0
  453. package/tools/cli/installers/lib/custom/handler.js +363 -0
  454. package/tools/cli/installers/lib/ide/STANDARDIZATION_PLAN.md +208 -0
  455. package/tools/cli/installers/lib/ide/_base-ide.js +655 -0
  456. package/tools/cli/installers/lib/ide/antigravity.js +474 -0
  457. package/tools/cli/installers/lib/ide/auggie.js +244 -0
  458. package/tools/cli/installers/lib/ide/claude-code.js +506 -0
  459. package/tools/cli/installers/lib/ide/cline.js +272 -0
  460. package/tools/cli/installers/lib/ide/codex.js +412 -0
  461. package/tools/cli/installers/lib/ide/crush.js +149 -0
  462. package/tools/cli/installers/lib/ide/cursor.js +160 -0
  463. package/tools/cli/installers/lib/ide/gemini.js +301 -0
  464. package/tools/cli/installers/lib/ide/github-copilot.js +383 -0
  465. package/tools/cli/installers/lib/ide/iflow.js +191 -0
  466. package/tools/cli/installers/lib/ide/kilo.js +250 -0
  467. package/tools/cli/installers/lib/ide/kiro-cli.js +326 -0
  468. package/tools/cli/installers/lib/ide/manager.js +244 -0
  469. package/tools/cli/installers/lib/ide/opencode.js +257 -0
  470. package/tools/cli/installers/lib/ide/qwen.js +372 -0
  471. package/tools/cli/installers/lib/ide/roo.js +273 -0
  472. package/tools/cli/installers/lib/ide/rovo-dev.js +290 -0
  473. package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +165 -0
  474. package/tools/cli/installers/lib/ide/shared/bmad-artifacts.js +158 -0
  475. package/tools/cli/installers/lib/ide/shared/module-injections.js +136 -0
  476. package/tools/cli/installers/lib/ide/shared/path-utils.js +165 -0
  477. package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +268 -0
  478. package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +293 -0
  479. package/tools/cli/installers/lib/ide/templates/agent-command-template.md +14 -0
  480. package/tools/cli/installers/lib/ide/templates/gemini-agent-command.toml +14 -0
  481. package/tools/cli/installers/lib/ide/templates/gemini-task-command.toml +12 -0
  482. package/tools/cli/installers/lib/ide/templates/workflow-command-template.md +13 -0
  483. package/tools/cli/installers/lib/ide/templates/workflow-commander.md +5 -0
  484. package/tools/cli/installers/lib/ide/trae.js +313 -0
  485. package/tools/cli/installers/lib/ide/windsurf.js +258 -0
  486. package/tools/cli/installers/lib/message-loader.js +85 -0
  487. package/tools/cli/installers/lib/modules/external-manager.js +135 -0
  488. package/tools/cli/installers/lib/modules/manager.js +1375 -0
  489. package/tools/cli/lib/activation-builder.js +163 -0
  490. package/tools/cli/lib/agent/compiler.js +522 -0
  491. package/tools/cli/lib/agent/installer.js +716 -0
  492. package/tools/cli/lib/agent/template-engine.js +152 -0
  493. package/tools/cli/lib/agent-analyzer.js +109 -0
  494. package/tools/cli/lib/agent-party-generator.js +194 -0
  495. package/tools/cli/lib/cli-utils.js +227 -0
  496. package/tools/cli/lib/config.js +213 -0
  497. package/tools/cli/lib/file-ops.js +204 -0
  498. package/tools/cli/lib/platform-codes.js +116 -0
  499. package/tools/cli/lib/project-root.js +77 -0
  500. package/tools/cli/lib/prompts.js +433 -0
  501. package/tools/cli/lib/ui.js +1716 -0
  502. package/tools/cli/lib/xml-handler.js +177 -0
  503. package/tools/cli/lib/xml-to-markdown.js +82 -0
  504. package/tools/{yaml-format.js → cli/lib/yaml-format.js} +9 -17
  505. package/tools/cli/lib/yaml-xml-builder.js +587 -0
  506. package/tools/docs/BUNDLE_DISTRIBUTION_SETUP.md +95 -0
  507. package/tools/docs/fix-refs.md +91 -0
  508. package/tools/docs/index.md +2 -0
  509. package/tools/fix-doc-links.js +288 -0
  510. package/tools/flattener/ignoreRules.js +2 -6
  511. package/tools/flattener/main.js +31 -121
  512. package/tools/flattener/projectRoot.js +3 -8
  513. package/tools/flattener/stats.helpers.js +8 -35
  514. package/tools/flattener/stats.js +1 -6
  515. package/tools/flattener/test-matrix.js +1 -5
  516. package/tools/flattener/xml.js +1 -7
  517. package/tools/format-workflow-md.js +263 -0
  518. package/tools/lib/xml-utils.js +13 -0
  519. package/tools/maintainer/review-pr-README.md +55 -0
  520. package/tools/maintainer/review-pr.md +242 -0
  521. package/tools/migrate-custom-module-paths.js +124 -0
  522. package/tools/platform-codes.yaml +157 -0
  523. package/tools/schema/agent.js +491 -0
  524. package/tools/validate-agent-schema.js +110 -0
  525. package/tools/validate-doc-links.js +371 -0
  526. package/tools/validate-svg-changes.sh +356 -0
  527. package/website/README.md +76 -0
  528. package/website/_basement/components/WorkflowGuide.astro +444 -0
  529. package/website/_basement/pages/workflow-guide.astro +17 -0
  530. package/website/astro.config.mjs +169 -0
  531. package/website/public/favicon.ico +0 -0
  532. package/website/public/img/bmad-dark.png +0 -0
  533. package/website/public/img/bmad-light.png +0 -0
  534. package/website/public/img/logo.svg +4 -0
  535. package/website/public/img/workflow-map.png +0 -0
  536. package/website/public/robots.txt +37 -0
  537. package/website/public/workflow-map-diagram.html +361 -0
  538. package/website/src/components/Banner.astro +59 -0
  539. package/website/src/components/Header.astro +121 -0
  540. package/website/src/components/MobileMenuFooter.astro +53 -0
  541. package/website/src/content/config.ts +6 -0
  542. package/website/src/lib/site-url.js +25 -0
  543. package/website/src/pages/404.astro +11 -0
  544. package/website/src/rehype-base-paths.js +89 -0
  545. package/website/src/rehype-markdown-links.js +117 -0
  546. package/website/src/styles/custom.css +500 -0
  547. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
  548. package/.github/workflows/format-check.yaml +0 -42
  549. package/bmad-core/agent-teams/team-all.yaml +0 -14
  550. package/bmad-core/agent-teams/team-fullstack.yaml +0 -18
  551. package/bmad-core/agent-teams/team-ide-minimal.yaml +0 -10
  552. package/bmad-core/agent-teams/team-no-ui.yaml +0 -13
  553. package/bmad-core/agents/analyst.md +0 -81
  554. package/bmad-core/agents/architect.md +0 -83
  555. package/bmad-core/agents/bmad-master.md +0 -107
  556. package/bmad-core/agents/bmad-orchestrator.md +0 -149
  557. package/bmad-core/agents/dev.md +0 -75
  558. package/bmad-core/agents/pm.md +0 -81
  559. package/bmad-core/agents/po.md +0 -76
  560. package/bmad-core/agents/qa.md +0 -88
  561. package/bmad-core/agents/sm.md +0 -62
  562. package/bmad-core/agents/ux-expert.md +0 -66
  563. package/bmad-core/checklists/architect-checklist.md +0 -438
  564. package/bmad-core/checklists/change-checklist.md +0 -182
  565. package/bmad-core/checklists/pm-checklist.md +0 -370
  566. package/bmad-core/checklists/po-master-checklist.md +0 -432
  567. package/bmad-core/checklists/story-dod-checklist.md +0 -94
  568. package/bmad-core/checklists/story-draft-checklist.md +0 -153
  569. package/bmad-core/core-config.yaml +0 -20
  570. package/bmad-core/data/bmad-kb.md +0 -806
  571. package/bmad-core/data/brainstorming-techniques.md +0 -36
  572. package/bmad-core/data/elicitation-methods.md +0 -154
  573. package/bmad-core/data/technical-preferences.md +0 -3
  574. package/bmad-core/data/test-levels-framework.md +0 -146
  575. package/bmad-core/data/test-priorities-matrix.md +0 -172
  576. package/bmad-core/tasks/advanced-elicitation.md +0 -117
  577. package/bmad-core/tasks/brownfield-create-epic.md +0 -160
  578. package/bmad-core/tasks/brownfield-create-story.md +0 -147
  579. package/bmad-core/tasks/correct-course.md +0 -70
  580. package/bmad-core/tasks/create-brownfield-story.md +0 -312
  581. package/bmad-core/tasks/create-deep-research-prompt.md +0 -278
  582. package/bmad-core/tasks/create-next-story.md +0 -112
  583. package/bmad-core/tasks/document-project.md +0 -343
  584. package/bmad-core/tasks/facilitate-brainstorming-session.md +0 -136
  585. package/bmad-core/tasks/generate-ai-frontend-prompt.md +0 -51
  586. package/bmad-core/tasks/index-docs.md +0 -173
  587. package/bmad-core/tasks/kb-mode-interaction.md +0 -75
  588. package/bmad-core/tasks/nfr-assess.md +0 -343
  589. package/bmad-core/tasks/qa-gate.md +0 -159
  590. package/bmad-core/tasks/review-story.md +0 -314
  591. package/bmad-core/tasks/risk-profile.md +0 -353
  592. package/bmad-core/tasks/shard-doc.md +0 -185
  593. package/bmad-core/tasks/test-design.md +0 -174
  594. package/bmad-core/tasks/trace-requirements.md +0 -264
  595. package/bmad-core/tasks/validate-next-story.md +0 -134
  596. package/bmad-core/templates/architecture-tmpl.yaml +0 -650
  597. package/bmad-core/templates/brainstorming-output-tmpl.yaml +0 -156
  598. package/bmad-core/templates/brownfield-architecture-tmpl.yaml +0 -476
  599. package/bmad-core/templates/brownfield-prd-tmpl.yaml +0 -280
  600. package/bmad-core/templates/competitor-analysis-tmpl.yaml +0 -306
  601. package/bmad-core/templates/front-end-architecture-tmpl.yaml +0 -218
  602. package/bmad-core/templates/front-end-spec-tmpl.yaml +0 -349
  603. package/bmad-core/templates/fullstack-architecture-tmpl.yaml +0 -823
  604. package/bmad-core/templates/market-research-tmpl.yaml +0 -252
  605. package/bmad-core/templates/prd-tmpl.yaml +0 -202
  606. package/bmad-core/templates/project-brief-tmpl.yaml +0 -221
  607. package/bmad-core/templates/qa-gate-tmpl.yaml +0 -102
  608. package/bmad-core/templates/story-tmpl.yaml +0 -137
  609. package/bmad-core/workflows/brownfield-fullstack.yaml +0 -297
  610. package/bmad-core/workflows/brownfield-service.yaml +0 -187
  611. package/bmad-core/workflows/brownfield-ui.yaml +0 -197
  612. package/bmad-core/workflows/greenfield-fullstack.yaml +0 -240
  613. package/bmad-core/workflows/greenfield-service.yaml +0 -206
  614. package/bmad-core/workflows/greenfield-ui.yaml +0 -235
  615. package/common/tasks/create-doc.md +0 -101
  616. package/common/tasks/execute-checklist.md +0 -86
  617. package/common/utils/bmad-doc-template.md +0 -325
  618. package/common/utils/workflow-management.md +0 -69
  619. package/dist/agents/analyst.txt +0 -2889
  620. package/dist/agents/architect.txt +0 -3552
  621. package/dist/agents/bmad-master.txt +0 -8769
  622. package/dist/agents/bmad-orchestrator.txt +0 -1513
  623. package/dist/agents/dev.txt +0 -414
  624. package/dist/agents/pm.txt +0 -2204
  625. package/dist/agents/po.txt +0 -1346
  626. package/dist/agents/qa.txt +0 -1987
  627. package/dist/agents/sm.txt +0 -658
  628. package/dist/agents/ux-expert.txt +0 -694
  629. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +0 -2371
  630. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.txt +0 -1620
  631. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.txt +0 -815
  632. package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +0 -10952
  633. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.txt +0 -4012
  634. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.txt +0 -3698
  635. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.txt +0 -450
  636. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.txt +0 -973
  637. package/dist/expansion-packs/bmad-2d-unity-game-dev/teams/unity-2d-game-team.txt +0 -15376
  638. package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +0 -2075
  639. package/dist/teams/team-all.txt +0 -12682
  640. package/dist/teams/team-fullstack.txt +0 -10421
  641. package/dist/teams/team-ide-minimal.txt +0 -5103
  642. package/dist/teams/team-no-ui.txt +0 -8980
  643. package/docs/GUIDING-PRINCIPLES.md +0 -91
  644. package/docs/core-architecture.md +0 -219
  645. package/docs/enhanced-ide-development-workflow.md +0 -248
  646. package/docs/expansion-packs.md +0 -280
  647. package/docs/how-to-contribute-with-pull-requests.md +0 -158
  648. package/docs/user-guide.md +0 -504
  649. package/docs/versioning-and-releases.md +0 -147
  650. package/docs/versions.md +0 -48
  651. package/docs/working-in-the-brownfield.md +0 -597
  652. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/Complete AI Agent System - Flowchart.svg +0 -102
  653. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.1 Google Cloud Project Setup/1.1.1 - Initial Project Configuration - bash copy.txt +0 -13
  654. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.1 Google Cloud Project Setup/1.1.1 - Initial Project Configuration - bash.txt +0 -13
  655. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.2 Agent Development Kit Installation/1.2.2 - Basic Project Structure - txt.txt +0 -25
  656. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.3 Core Configuration Files/1.3.1 - settings.py +0 -34
  657. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.3 Core Configuration Files/1.3.2 - main.py - Base Application.py +0 -70
  658. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.4 Deployment Configuration/1.4.2 - cloudbuild.yaml +0 -26
  659. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/README.md +0 -109
  660. package/expansion-packs/README.md +0 -3
  661. package/expansion-packs/bmad-2d-phaser-game-dev/agent-teams/phaser-2d-nodejs-game-team.yaml +0 -13
  662. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.md +0 -71
  663. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.md +0 -78
  664. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.md +0 -64
  665. package/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-design-checklist.md +0 -201
  666. package/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-story-dod-checklist.md +0 -160
  667. package/expansion-packs/bmad-2d-phaser-game-dev/config.yaml +0 -8
  668. package/expansion-packs/bmad-2d-phaser-game-dev/data/bmad-kb.md +0 -250
  669. package/expansion-packs/bmad-2d-phaser-game-dev/data/development-guidelines.md +0 -647
  670. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/advanced-elicitation.md +0 -110
  671. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/create-game-story.md +0 -216
  672. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/game-design-brainstorming.md +0 -290
  673. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-architecture-tmpl.yaml +0 -613
  674. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-brief-tmpl.yaml +0 -356
  675. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-design-doc-tmpl.yaml +0 -343
  676. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-story-tmpl.yaml +0 -253
  677. package/expansion-packs/bmad-2d-phaser-game-dev/templates/level-design-doc-tmpl.yaml +0 -484
  678. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-dev-greenfield.yaml +0 -183
  679. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-prototype.yaml +0 -175
  680. package/expansion-packs/bmad-2d-unity-game-dev/agent-teams/unity-2d-game-team.yaml +0 -14
  681. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.md +0 -80
  682. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.md +0 -77
  683. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.md +0 -78
  684. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.md +0 -65
  685. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-architect-checklist.md +0 -391
  686. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-change-checklist.md +0 -203
  687. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-design-checklist.md +0 -201
  688. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-story-dod-checklist.md +0 -124
  689. package/expansion-packs/bmad-2d-unity-game-dev/config.yaml +0 -6
  690. package/expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md +0 -769
  691. package/expansion-packs/bmad-2d-unity-game-dev/data/development-guidelines.md +0 -586
  692. package/expansion-packs/bmad-2d-unity-game-dev/tasks/advanced-elicitation.md +0 -110
  693. package/expansion-packs/bmad-2d-unity-game-dev/tasks/correct-course-game.md +0 -141
  694. package/expansion-packs/bmad-2d-unity-game-dev/tasks/create-game-story.md +0 -184
  695. package/expansion-packs/bmad-2d-unity-game-dev/tasks/game-design-brainstorming.md +0 -290
  696. package/expansion-packs/bmad-2d-unity-game-dev/tasks/validate-game-story.md +0 -200
  697. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-architecture-tmpl.yaml +0 -1030
  698. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-brief-tmpl.yaml +0 -356
  699. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml +0 -705
  700. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-story-tmpl.yaml +0 -256
  701. package/expansion-packs/bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml +0 -484
  702. package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-dev-greenfield.yaml +0 -183
  703. package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-prototype.yaml +0 -175
  704. package/expansion-packs/bmad-infrastructure-devops/README.md +0 -147
  705. package/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.md +0 -71
  706. package/expansion-packs/bmad-infrastructure-devops/checklists/infrastructure-checklist.md +0 -484
  707. package/expansion-packs/bmad-infrastructure-devops/config.yaml +0 -9
  708. package/expansion-packs/bmad-infrastructure-devops/data/bmad-kb.md +0 -305
  709. package/expansion-packs/bmad-infrastructure-devops/tasks/review-infrastructure.md +0 -159
  710. package/expansion-packs/bmad-infrastructure-devops/tasks/validate-infrastructure.md +0 -153
  711. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-architecture-tmpl.yaml +0 -424
  712. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.yaml +0 -629
  713. package/release_notes.md +0 -33
  714. package/tools/builders/web-builder.js +0 -675
  715. package/tools/bump-all-versions.js +0 -115
  716. package/tools/bump-expansion-version.js +0 -90
  717. package/tools/cli.js +0 -152
  718. package/tools/installer/README.md +0 -8
  719. package/tools/installer/bin/bmad.js +0 -585
  720. package/tools/installer/config/ide-agent-config.yaml +0 -58
  721. package/tools/installer/config/install.config.yaml +0 -123
  722. package/tools/installer/lib/config-loader.js +0 -257
  723. package/tools/installer/lib/file-manager.js +0 -389
  724. package/tools/installer/lib/ide-base-setup.js +0 -228
  725. package/tools/installer/lib/ide-setup.js +0 -1441
  726. package/tools/installer/lib/installer.js +0 -1995
  727. package/tools/installer/lib/memory-profiler.js +0 -225
  728. package/tools/installer/lib/module-manager.js +0 -114
  729. package/tools/installer/lib/resource-locator.js +0 -308
  730. package/tools/installer/package.json +0 -44
  731. package/tools/lib/dependency-resolver.js +0 -175
  732. package/tools/lib/yaml-utils.js +0 -29
  733. package/tools/md-assets/web-agent-startup-instructions.md +0 -39
  734. package/tools/preview-release-notes.js +0 -66
  735. package/tools/shared/bannerArt.js +0 -105
  736. package/tools/sync-installer-version.js +0 -32
  737. package/tools/update-expansion-version.js +0 -53
  738. package/tools/upgraders/v3-to-v4-upgrader.js +0 -672
  739. package/tools/version-bump.js +0 -94
@@ -0,0 +1,1375 @@
1
+ const path = require('node:path');
2
+ const fs = require('fs-extra');
3
+ const yaml = require('yaml');
4
+ const chalk = require('chalk');
5
+ const ora = require('ora');
6
+ const { XmlHandler } = require('../../../lib/xml-handler');
7
+ const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root');
8
+ const { filterCustomizationData } = require('../../../lib/agent/compiler');
9
+ const { ExternalModuleManager } = require('./external-manager');
10
+
11
+ /**
12
+ * Manages the installation, updating, and removal of BMAD modules.
13
+ * Handles module discovery, dependency resolution, configuration processing,
14
+ * and agent file management including XML activation block injection.
15
+ *
16
+ * @class ModuleManager
17
+ * @requires fs-extra
18
+ * @requires yaml
19
+ * @requires chalk
20
+ * @requires XmlHandler
21
+ *
22
+ * @example
23
+ * const manager = new ModuleManager();
24
+ * const modules = await manager.listAvailable();
25
+ * await manager.install('core-module', '/path/to/bmad');
26
+ */
27
+ class ModuleManager {
28
+ constructor(options = {}) {
29
+ this.xmlHandler = new XmlHandler();
30
+ this.bmadFolderName = 'bmad'; // Default, can be overridden
31
+ this.customModulePaths = new Map(); // Initialize custom module paths
32
+ this.externalModuleManager = new ExternalModuleManager(); // For external official modules
33
+ }
34
+
35
+ /**
36
+ * Set the bmad folder name for placeholder replacement
37
+ * @param {string} bmadFolderName - The bmad folder name
38
+ */
39
+ setBmadFolderName(bmadFolderName) {
40
+ this.bmadFolderName = bmadFolderName;
41
+ }
42
+
43
+ /**
44
+ * Set the core configuration for access during module installation
45
+ * @param {Object} coreConfig - Core configuration object
46
+ */
47
+ setCoreConfig(coreConfig) {
48
+ this.coreConfig = coreConfig;
49
+ }
50
+
51
+ /**
52
+ * Set custom module paths for priority lookup
53
+ * @param {Map<string, string>} customModulePaths - Map of module ID to source path
54
+ */
55
+ setCustomModulePaths(customModulePaths) {
56
+ this.customModulePaths = customModulePaths;
57
+ }
58
+
59
+ /**
60
+ * Copy a file to the target location
61
+ * @param {string} sourcePath - Source file path
62
+ * @param {string} targetPath - Target file path
63
+ * @param {boolean} overwrite - Whether to overwrite existing files (default: true)
64
+ */
65
+ async copyFileWithPlaceholderReplacement(sourcePath, targetPath, overwrite = true) {
66
+ await fs.copy(sourcePath, targetPath, { overwrite });
67
+ }
68
+
69
+ /**
70
+ * Copy a directory recursively
71
+ * @param {string} sourceDir - Source directory path
72
+ * @param {string} targetDir - Target directory path
73
+ * @param {boolean} overwrite - Whether to overwrite existing files (default: true)
74
+ */
75
+ async copyDirectoryWithPlaceholderReplacement(sourceDir, targetDir, overwrite = true) {
76
+ await fs.ensureDir(targetDir);
77
+ const entries = await fs.readdir(sourceDir, { withFileTypes: true });
78
+
79
+ for (const entry of entries) {
80
+ const sourcePath = path.join(sourceDir, entry.name);
81
+ const targetPath = path.join(targetDir, entry.name);
82
+
83
+ if (entry.isDirectory()) {
84
+ await this.copyDirectoryWithPlaceholderReplacement(sourcePath, targetPath, overwrite);
85
+ } else {
86
+ await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath, overwrite);
87
+ }
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Copy sidecar directory to _bmad/_memory location with update-safe handling
93
+ * @param {string} sourceSidecarPath - Source sidecar directory path
94
+ * @param {string} agentName - Name of the agent (for naming)
95
+ * @param {string} bmadMemoryPath - This should ALWAYS be _bmad/_memory
96
+ * @param {boolean} isUpdate - Whether this is an update (default: false)
97
+ * @param {string} bmadDir - BMAD installation directory
98
+ * @param {Object} installer - Installer instance for file tracking
99
+ */
100
+ async copySidecarToMemory(sourceSidecarPath, agentName, bmadMemoryPath, isUpdate = false, bmadDir = null, installer = null) {
101
+ const crypto = require('node:crypto');
102
+ const sidecarTargetDir = path.join(bmadMemoryPath, `${agentName}-sidecar`);
103
+
104
+ // Ensure target directory exists
105
+ await fs.ensureDir(bmadMemoryPath);
106
+ await fs.ensureDir(sidecarTargetDir);
107
+
108
+ // Get existing files manifest for update checking
109
+ let existingFilesManifest = [];
110
+ if (isUpdate && installer) {
111
+ existingFilesManifest = await installer.readFilesManifest(bmadDir);
112
+ }
113
+
114
+ // Build map of existing sidecar files with their hashes
115
+ const existingSidecarFiles = new Map();
116
+ for (const fileEntry of existingFilesManifest) {
117
+ if (fileEntry.path && fileEntry.path.includes(`${agentName}-sidecar/`)) {
118
+ existingSidecarFiles.set(fileEntry.path, fileEntry.hash);
119
+ }
120
+ }
121
+
122
+ // Get all files in source sidecar
123
+ const sourceFiles = await this.getFileList(sourceSidecarPath);
124
+
125
+ for (const file of sourceFiles) {
126
+ const sourceFilePath = path.join(sourceSidecarPath, file);
127
+ const targetFilePath = path.join(sidecarTargetDir, file);
128
+
129
+ // Calculate current source file hash
130
+ const sourceHash = crypto
131
+ .createHash('sha256')
132
+ .update(await fs.readFile(sourceFilePath))
133
+ .digest('hex');
134
+
135
+ // Path relative to bmad directory
136
+ const relativeToBmad = path.join('_memory', `${agentName}-sidecar`, file);
137
+
138
+ if (isUpdate && (await fs.pathExists(targetFilePath))) {
139
+ // Calculate current target file hash
140
+ const currentTargetHash = crypto
141
+ .createHash('sha256')
142
+ .update(await fs.readFile(targetFilePath))
143
+ .digest('hex');
144
+
145
+ // Get the last known hash from files-manifest
146
+ const lastKnownHash = existingSidecarFiles.get(relativeToBmad);
147
+
148
+ if (lastKnownHash) {
149
+ // We have a record of this file
150
+ if (currentTargetHash === lastKnownHash) {
151
+ // File hasn't been modified by user, safe to update
152
+ await this.copyFileWithPlaceholderReplacement(sourceFilePath, targetFilePath, true);
153
+ if (process.env.BMAD_VERBOSE_INSTALL === 'true') {
154
+ console.log(chalk.dim(` Updated sidecar file: ${relativeToBmad}`));
155
+ }
156
+ } else {
157
+ // User has modified the file, preserve it
158
+ if (process.env.BMAD_VERBOSE_INSTALL === 'true') {
159
+ console.log(chalk.dim(` Preserving user-modified file: ${relativeToBmad}`));
160
+ }
161
+ }
162
+ } else {
163
+ // First time seeing this file in manifest, copy it
164
+ await this.copyFileWithPlaceholderReplacement(sourceFilePath, targetFilePath, true);
165
+ if (process.env.BMAD_VERBOSE_INSTALL === 'true') {
166
+ console.log(chalk.dim(` Added new sidecar file: ${relativeToBmad}`));
167
+ }
168
+ }
169
+ } else {
170
+ // New installation
171
+ await this.copyFileWithPlaceholderReplacement(sourceFilePath, targetFilePath, true);
172
+ if (process.env.BMAD_VERBOSE_INSTALL === 'true') {
173
+ console.log(chalk.dim(` Copied sidecar file: ${relativeToBmad}`));
174
+ }
175
+ }
176
+
177
+ // Track the file in the installer's file tracking system
178
+ if (installer && installer.installedFiles) {
179
+ installer.installedFiles.add(targetFilePath);
180
+ }
181
+ }
182
+
183
+ // Return list of files that were processed
184
+ const processedFiles = sourceFiles.map((file) => path.join('_memory', `${agentName}-sidecar`, file));
185
+ return processedFiles;
186
+ }
187
+
188
+ /**
189
+ * List all available modules (excluding core which is always installed)
190
+ * bmm is the only built-in module, directly under src/bmm
191
+ * All other modules come from external-official-modules.yaml
192
+ * @returns {Object} Object with modules array and customModules array
193
+ */
194
+ async listAvailable() {
195
+ const modules = [];
196
+ const customModules = [];
197
+
198
+ // Add built-in bmm module (directly under src/bmm)
199
+ const bmmPath = getSourcePath('bmm');
200
+ if (await fs.pathExists(bmmPath)) {
201
+ const bmmInfo = await this.getModuleInfo(bmmPath, 'bmm', 'src/bmm');
202
+ if (bmmInfo) {
203
+ modules.push(bmmInfo);
204
+ }
205
+ }
206
+
207
+ // Check for cached custom modules in _config/custom/
208
+ if (this.bmadDir) {
209
+ const customCacheDir = path.join(this.bmadDir, '_config', 'custom');
210
+ if (await fs.pathExists(customCacheDir)) {
211
+ const cacheEntries = await fs.readdir(customCacheDir, { withFileTypes: true });
212
+ for (const entry of cacheEntries) {
213
+ if (entry.isDirectory()) {
214
+ const cachePath = path.join(customCacheDir, entry.name);
215
+ const moduleInfo = await this.getModuleInfo(cachePath, entry.name, '_config/custom');
216
+ if (moduleInfo && !modules.some((m) => m.id === moduleInfo.id) && !customModules.some((m) => m.id === moduleInfo.id)) {
217
+ moduleInfo.isCustom = true;
218
+ moduleInfo.fromCache = true;
219
+ customModules.push(moduleInfo);
220
+ }
221
+ }
222
+ }
223
+ }
224
+ }
225
+
226
+ return { modules, customModules };
227
+ }
228
+
229
+ /**
230
+ * Get module information from a module path
231
+ * @param {string} modulePath - Path to the module directory
232
+ * @param {string} defaultName - Default name for the module
233
+ * @param {string} sourceDescription - Description of where the module was found
234
+ * @returns {Object|null} Module info or null if not a valid module
235
+ */
236
+ async getModuleInfo(modulePath, defaultName, sourceDescription) {
237
+ // Check for module structure (module.yaml OR custom.yaml)
238
+ const moduleConfigPath = path.join(modulePath, 'module.yaml');
239
+ const installerConfigPath = path.join(modulePath, '_module-installer', 'module.yaml');
240
+ const customConfigPath = path.join(modulePath, '_module-installer', 'custom.yaml');
241
+ const rootCustomConfigPath = path.join(modulePath, 'custom.yaml');
242
+ let configPath = null;
243
+
244
+ if (await fs.pathExists(moduleConfigPath)) {
245
+ configPath = moduleConfigPath;
246
+ } else if (await fs.pathExists(installerConfigPath)) {
247
+ configPath = installerConfigPath;
248
+ } else if (await fs.pathExists(customConfigPath)) {
249
+ configPath = customConfigPath;
250
+ } else if (await fs.pathExists(rootCustomConfigPath)) {
251
+ configPath = rootCustomConfigPath;
252
+ }
253
+
254
+ // Skip if this doesn't look like a module
255
+ if (!configPath) {
256
+ return null;
257
+ }
258
+
259
+ // Mark as custom if it's using custom.yaml OR if it's outside src/bmm or src/core
260
+ const isCustomSource = sourceDescription !== 'src/bmm' && sourceDescription !== 'src/core' && sourceDescription !== 'src/modules';
261
+ const moduleInfo = {
262
+ id: defaultName,
263
+ path: modulePath,
264
+ name: defaultName
265
+ .split('-')
266
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
267
+ .join(' '),
268
+ description: 'BMAD Module',
269
+ version: '5.0.0',
270
+ source: sourceDescription,
271
+ isCustom: configPath === customConfigPath || configPath === rootCustomConfigPath || isCustomSource,
272
+ };
273
+
274
+ // Read module config for metadata
275
+ try {
276
+ const configContent = await fs.readFile(configPath, 'utf8');
277
+ const config = yaml.parse(configContent);
278
+
279
+ // Use the code property as the id if available
280
+ if (config.code) {
281
+ moduleInfo.id = config.code;
282
+ }
283
+
284
+ moduleInfo.name = config.name || moduleInfo.name;
285
+ moduleInfo.description = config.description || moduleInfo.description;
286
+ moduleInfo.version = config.version || moduleInfo.version;
287
+ moduleInfo.dependencies = config.dependencies || [];
288
+ moduleInfo.defaultSelected = config.default_selected === undefined ? false : config.default_selected;
289
+ } catch (error) {
290
+ console.warn(`Failed to read config for ${defaultName}:`, error.message);
291
+ }
292
+
293
+ return moduleInfo;
294
+ }
295
+
296
+ /**
297
+ * Find the source path for a module by searching all possible locations
298
+ * @param {string} moduleCode - Code of the module to find (from module.yaml)
299
+ * @returns {string|null} Path to the module source or null if not found
300
+ */
301
+ async findModuleSource(moduleCode) {
302
+ const projectRoot = getProjectRoot();
303
+
304
+ // First check custom module paths if they exist
305
+ if (this.customModulePaths && this.customModulePaths.has(moduleCode)) {
306
+ return this.customModulePaths.get(moduleCode);
307
+ }
308
+
309
+ // Check for built-in bmm module (directly under src/bmm)
310
+ if (moduleCode === 'bmm') {
311
+ const bmmPath = getSourcePath('bmm');
312
+ if (await fs.pathExists(bmmPath)) {
313
+ return bmmPath;
314
+ }
315
+ }
316
+
317
+ // Check external official modules
318
+ const externalSource = await this.findExternalModuleSource(moduleCode);
319
+ if (externalSource) {
320
+ return externalSource;
321
+ }
322
+
323
+ return null;
324
+ }
325
+
326
+ /**
327
+ * Check if a module is an external official module
328
+ * @param {string} moduleCode - Code of the module to check
329
+ * @returns {boolean} True if the module is external
330
+ */
331
+ async isExternalModule(moduleCode) {
332
+ return await this.externalModuleManager.hasModule(moduleCode);
333
+ }
334
+
335
+ /**
336
+ * Get the cache directory for external modules
337
+ * @returns {string} Path to the external modules cache directory
338
+ */
339
+ getExternalCacheDir() {
340
+ const os = require('node:os');
341
+ const cacheDir = path.join(os.homedir(), '.bmad', 'cache', 'external-modules');
342
+ return cacheDir;
343
+ }
344
+
345
+ /**
346
+ * Clone an external module repository to cache
347
+ * @param {string} moduleCode - Code of the external module
348
+ * @returns {string} Path to the cloned repository
349
+ */
350
+ async cloneExternalModule(moduleCode) {
351
+ const { execSync } = require('node:child_process');
352
+ const moduleInfo = await this.externalModuleManager.getModuleByCode(moduleCode);
353
+
354
+ if (!moduleInfo) {
355
+ throw new Error(`External module '${moduleCode}' not found in external-official-modules.yaml`);
356
+ }
357
+
358
+ const cacheDir = this.getExternalCacheDir();
359
+ const moduleCacheDir = path.join(cacheDir, moduleCode);
360
+
361
+ // Create cache directory if it doesn't exist
362
+ await fs.ensureDir(cacheDir);
363
+
364
+ // Track if we need to install dependencies
365
+ let needsDependencyInstall = false;
366
+ let wasNewClone = false;
367
+
368
+ // Check if already cloned
369
+ if (await fs.pathExists(moduleCacheDir)) {
370
+ // Try to update if it's a git repo
371
+ const fetchSpinner = ora(`Fetching ${moduleInfo.name}...`).start();
372
+ try {
373
+ const currentRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
374
+ // Fetch and reset to remote - works better with shallow clones than pull
375
+ execSync('git fetch origin --depth 1', { cwd: moduleCacheDir, stdio: 'pipe' });
376
+ execSync('git reset --hard origin/HEAD', { cwd: moduleCacheDir, stdio: 'pipe' });
377
+ const newRef = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe' }).toString().trim();
378
+
379
+ fetchSpinner.succeed(`Fetched ${moduleInfo.name}`);
380
+ // Force dependency install if we got new code
381
+ if (currentRef !== newRef) {
382
+ needsDependencyInstall = true;
383
+ }
384
+ } catch {
385
+ fetchSpinner.warn(`Fetch failed, re-downloading ${moduleInfo.name}`);
386
+ // If update fails, remove and re-clone
387
+ await fs.remove(moduleCacheDir);
388
+ wasNewClone = true;
389
+ }
390
+ } else {
391
+ wasNewClone = true;
392
+ }
393
+
394
+ // Clone if not exists or was removed
395
+ if (wasNewClone) {
396
+ const fetchSpinner = ora(`Fetching ${moduleInfo.name}...`).start();
397
+ try {
398
+ execSync(`git clone --depth 1 "${moduleInfo.url}" "${moduleCacheDir}"`, {
399
+ stdio: 'pipe',
400
+ });
401
+ fetchSpinner.succeed(`Fetched ${moduleInfo.name}`);
402
+ } catch (error) {
403
+ fetchSpinner.fail(`Failed to fetch ${moduleInfo.name}`);
404
+ throw new Error(`Failed to clone external module '${moduleCode}': ${error.message}`);
405
+ }
406
+ }
407
+
408
+ // Install dependencies if package.json exists
409
+ const packageJsonPath = path.join(moduleCacheDir, 'package.json');
410
+ const nodeModulesPath = path.join(moduleCacheDir, 'node_modules');
411
+ if (await fs.pathExists(packageJsonPath)) {
412
+ // Install if node_modules doesn't exist, or if package.json is newer (dependencies changed)
413
+ const nodeModulesMissing = !(await fs.pathExists(nodeModulesPath));
414
+
415
+ // Force install if we updated or cloned new
416
+ if (needsDependencyInstall || wasNewClone || nodeModulesMissing) {
417
+ const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
418
+ try {
419
+ execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress', {
420
+ cwd: moduleCacheDir,
421
+ stdio: 'pipe',
422
+ timeout: 120_000, // 2 minute timeout
423
+ });
424
+ installSpinner.succeed(`Installed dependencies for ${moduleInfo.name}`);
425
+ } catch (error) {
426
+ installSpinner.warn(`Failed to install dependencies for ${moduleInfo.name}`);
427
+ console.warn(chalk.yellow(` Warning: ${error.message}`));
428
+ }
429
+ } else {
430
+ // Check if package.json is newer than node_modules
431
+ let packageJsonNewer = false;
432
+ try {
433
+ const packageStats = await fs.stat(packageJsonPath);
434
+ const nodeModulesStats = await fs.stat(nodeModulesPath);
435
+ packageJsonNewer = packageStats.mtime > nodeModulesStats.mtime;
436
+ } catch {
437
+ // If stat fails, assume we need to install
438
+ packageJsonNewer = true;
439
+ }
440
+
441
+ if (packageJsonNewer) {
442
+ const installSpinner = ora(`Installing dependencies for ${moduleInfo.name}...`).start();
443
+ try {
444
+ execSync('npm install --production --no-audit --no-fund --prefer-offline --no-progress', {
445
+ cwd: moduleCacheDir,
446
+ stdio: 'pipe',
447
+ timeout: 120_000, // 2 minute timeout
448
+ });
449
+ installSpinner.succeed(`Installed dependencies for ${moduleInfo.name}`);
450
+ } catch (error) {
451
+ installSpinner.warn(`Failed to install dependencies for ${moduleInfo.name}`);
452
+ console.warn(chalk.yellow(` Warning: ${error.message}`));
453
+ }
454
+ }
455
+ }
456
+ }
457
+
458
+ return moduleCacheDir;
459
+ }
460
+
461
+ /**
462
+ * Find the source path for an external module
463
+ * @param {string} moduleCode - Code of the external module
464
+ * @returns {string|null} Path to the module source or null if not found
465
+ */
466
+ async findExternalModuleSource(moduleCode) {
467
+ const moduleInfo = await this.externalModuleManager.getModuleByCode(moduleCode);
468
+
469
+ if (!moduleInfo) {
470
+ return null;
471
+ }
472
+
473
+ // Clone the external module repo
474
+ const cloneDir = await this.cloneExternalModule(moduleCode);
475
+
476
+ // The module-definition specifies the path to module.yaml relative to repo root
477
+ // We need to return the directory containing module.yaml
478
+ const moduleDefinitionPath = moduleInfo.moduleDefinition; // e.g., 'src/module.yaml'
479
+ const moduleDir = path.dirname(path.join(cloneDir, moduleDefinitionPath));
480
+
481
+ return moduleDir;
482
+ }
483
+
484
+ /**
485
+ * Install a module
486
+ * @param {string} moduleName - Code of the module to install (from module.yaml)
487
+ * @param {string} bmadDir - Target bmad directory
488
+ * @param {Function} fileTrackingCallback - Optional callback to track installed files
489
+ * @param {Object} options - Additional installation options
490
+ * @param {Array<string>} options.installedIDEs - Array of IDE codes that were installed
491
+ * @param {Object} options.moduleConfig - Module configuration from config collector
492
+ * @param {Object} options.logger - Logger instance for output
493
+ */
494
+ async install(moduleName, bmadDir, fileTrackingCallback = null, options = {}) {
495
+ const sourcePath = await this.findModuleSource(moduleName);
496
+ const targetPath = path.join(bmadDir, moduleName);
497
+
498
+ // Check if source module exists
499
+ if (!sourcePath) {
500
+ // Provide a more user-friendly error message
501
+ throw new Error(
502
+ `Source for module '${moduleName}' is not available. It will be retained but cannot be updated without its source files.`,
503
+ );
504
+ }
505
+
506
+ // Check if this is a custom module and read its custom.yaml values
507
+ let customConfig = null;
508
+ const rootCustomConfigPath = path.join(sourcePath, 'custom.yaml');
509
+ const moduleInstallerCustomPath = path.join(sourcePath, '_module-installer', 'custom.yaml');
510
+
511
+ if (await fs.pathExists(rootCustomConfigPath)) {
512
+ try {
513
+ const customContent = await fs.readFile(rootCustomConfigPath, 'utf8');
514
+ customConfig = yaml.parse(customContent);
515
+ } catch (error) {
516
+ console.warn(chalk.yellow(`Warning: Failed to read custom.yaml for ${moduleName}:`, error.message));
517
+ }
518
+ } else if (await fs.pathExists(moduleInstallerCustomPath)) {
519
+ try {
520
+ const customContent = await fs.readFile(moduleInstallerCustomPath, 'utf8');
521
+ customConfig = yaml.parse(customContent);
522
+ } catch (error) {
523
+ console.warn(chalk.yellow(`Warning: Failed to read custom.yaml for ${moduleName}:`, error.message));
524
+ }
525
+ }
526
+
527
+ // If this is a custom module, merge its values into the module config
528
+ if (customConfig) {
529
+ options.moduleConfig = { ...options.moduleConfig, ...customConfig };
530
+ if (options.logger) {
531
+ options.logger.log(chalk.cyan(` Merged custom configuration for ${moduleName}`));
532
+ }
533
+ }
534
+
535
+ // Check if already installed
536
+ if (await fs.pathExists(targetPath)) {
537
+ await fs.remove(targetPath);
538
+ }
539
+
540
+ // Vendor cross-module workflows BEFORE copying
541
+ // This reads source agent.yaml files and copies referenced workflows
542
+ await this.vendorCrossModuleWorkflows(sourcePath, targetPath, moduleName);
543
+
544
+ // Copy module files with filtering
545
+ await this.copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback, options.moduleConfig);
546
+
547
+ // Compile any .agent.yaml files to .md format
548
+ await this.compileModuleAgents(sourcePath, targetPath, moduleName, bmadDir, options.installer);
549
+
550
+ // Process agent files to inject activation block
551
+ await this.processAgentFiles(targetPath, moduleName);
552
+
553
+ // Call module-specific installer if it exists (unless explicitly skipped)
554
+ if (!options.skipModuleInstaller) {
555
+ await this.runModuleInstaller(moduleName, bmadDir, options);
556
+ }
557
+
558
+ // Capture version info for manifest
559
+ const { Manifest } = require('../core/manifest');
560
+ const manifestObj = new Manifest();
561
+ const versionInfo = await manifestObj.getModuleVersionInfo(moduleName, bmadDir, sourcePath);
562
+
563
+ await manifestObj.addModule(bmadDir, moduleName, {
564
+ version: versionInfo.version,
565
+ source: versionInfo.source,
566
+ npmPackage: versionInfo.npmPackage,
567
+ repoUrl: versionInfo.repoUrl,
568
+ });
569
+
570
+ return {
571
+ success: true,
572
+ module: moduleName,
573
+ path: targetPath,
574
+ versionInfo,
575
+ };
576
+ }
577
+
578
+ /**
579
+ * Update an existing module
580
+ * @param {string} moduleName - Name of the module to update
581
+ * @param {string} bmadDir - Target bmad directory
582
+ * @param {boolean} force - Force update (overwrite modifications)
583
+ */
584
+ async update(moduleName, bmadDir, force = false) {
585
+ const sourcePath = await this.findModuleSource(moduleName);
586
+ const targetPath = path.join(bmadDir, moduleName);
587
+
588
+ // Check if source module exists
589
+ if (!sourcePath) {
590
+ throw new Error(`Module '${moduleName}' not found in any source location`);
591
+ }
592
+
593
+ // Check if module is installed
594
+ if (!(await fs.pathExists(targetPath))) {
595
+ throw new Error(`Module '${moduleName}' is not installed`);
596
+ }
597
+
598
+ if (force) {
599
+ // Force update - remove and reinstall
600
+ await fs.remove(targetPath);
601
+ return await this.install(moduleName, bmadDir);
602
+ } else {
603
+ // Selective update - preserve user modifications
604
+ await this.syncModule(sourcePath, targetPath);
605
+
606
+ // Recompile agents (#1133)
607
+ await this.compileModuleAgents(sourcePath, targetPath, moduleName, bmadDir, options.installer);
608
+ await this.processAgentFiles(targetPath, moduleName);
609
+ }
610
+
611
+ return {
612
+ success: true,
613
+ module: moduleName,
614
+ path: targetPath,
615
+ };
616
+ }
617
+
618
+ /**
619
+ * Remove a module
620
+ * @param {string} moduleName - Name of the module to remove
621
+ * @param {string} bmadDir - Target bmad directory
622
+ */
623
+ async remove(moduleName, bmadDir) {
624
+ const targetPath = path.join(bmadDir, moduleName);
625
+
626
+ if (!(await fs.pathExists(targetPath))) {
627
+ throw new Error(`Module '${moduleName}' is not installed`);
628
+ }
629
+
630
+ await fs.remove(targetPath);
631
+
632
+ return {
633
+ success: true,
634
+ module: moduleName,
635
+ };
636
+ }
637
+
638
+ /**
639
+ * Check if a module is installed
640
+ * @param {string} moduleName - Name of the module
641
+ * @param {string} bmadDir - Target bmad directory
642
+ * @returns {boolean} True if module is installed
643
+ */
644
+ async isInstalled(moduleName, bmadDir) {
645
+ const targetPath = path.join(bmadDir, moduleName);
646
+ return await fs.pathExists(targetPath);
647
+ }
648
+
649
+ /**
650
+ * Get installed module info
651
+ * @param {string} moduleName - Name of the module
652
+ * @param {string} bmadDir - Target bmad directory
653
+ * @returns {Object|null} Module info or null if not installed
654
+ */
655
+ async getInstalledInfo(moduleName, bmadDir) {
656
+ const targetPath = path.join(bmadDir, moduleName);
657
+
658
+ if (!(await fs.pathExists(targetPath))) {
659
+ return null;
660
+ }
661
+
662
+ const configPath = path.join(targetPath, 'config.yaml');
663
+ const moduleInfo = {
664
+ id: moduleName,
665
+ path: targetPath,
666
+ installed: true,
667
+ };
668
+
669
+ if (await fs.pathExists(configPath)) {
670
+ try {
671
+ const configContent = await fs.readFile(configPath, 'utf8');
672
+ const config = yaml.parse(configContent);
673
+ Object.assign(moduleInfo, config);
674
+ } catch (error) {
675
+ console.warn(`Failed to read installed module config:`, error.message);
676
+ }
677
+ }
678
+
679
+ return moduleInfo;
680
+ }
681
+
682
+ /**
683
+ * Copy module with filtering for localskip agents and conditional content
684
+ * @param {string} sourcePath - Source module path
685
+ * @param {string} targetPath - Target module path
686
+ * @param {Function} fileTrackingCallback - Optional callback to track installed files
687
+ * @param {Object} moduleConfig - Module configuration with conditional flags
688
+ */
689
+ async copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback = null, moduleConfig = {}) {
690
+ // Get all files in source
691
+ const sourceFiles = await this.getFileList(sourcePath);
692
+
693
+ for (const file of sourceFiles) {
694
+ // Skip sub-modules directory - these are IDE-specific and handled separately
695
+ if (file.startsWith('sub-modules/')) {
696
+ continue;
697
+ }
698
+
699
+ // Only skip sidecar directories - they are handled separately during agent compilation
700
+ // But still allow other files in agent directories
701
+ const isInAgentDirectory = file.startsWith('agents/');
702
+ const isInSidecarDirectory = path
703
+ .dirname(file)
704
+ .split('/')
705
+ .some((dir) => dir.toLowerCase().endsWith('-sidecar'));
706
+
707
+ if (isInSidecarDirectory) {
708
+ continue;
709
+ }
710
+
711
+ // Skip _module-installer directory - it's only needed at install time
712
+ if (file.startsWith('_module-installer/') || file === 'module.yaml') {
713
+ continue;
714
+ }
715
+
716
+ // Skip config.yaml templates - we'll generate clean ones with actual values
717
+ if (file === 'config.yaml' || file.endsWith('/config.yaml')) {
718
+ continue;
719
+ }
720
+
721
+ // Skip .agent.yaml files - they will be compiled separately
722
+ if (file.endsWith('.agent.yaml')) {
723
+ continue;
724
+ }
725
+
726
+ const sourceFile = path.join(sourcePath, file);
727
+ const targetFile = path.join(targetPath, file);
728
+
729
+ // Check if this is an agent file
730
+ if (file.startsWith('agents/') && file.endsWith('.md')) {
731
+ // Read the file to check for localskip
732
+ const content = await fs.readFile(sourceFile, 'utf8');
733
+
734
+ // Check for localskip="true" in the agent tag
735
+ const agentMatch = content.match(/<agent[^>]*\slocalskip="true"[^>]*>/);
736
+ if (agentMatch) {
737
+ console.log(chalk.dim(` Skipping web-only agent: ${path.basename(file)}`));
738
+ continue; // Skip this agent
739
+ }
740
+ }
741
+
742
+ // Check if this is a workflow.yaml file
743
+ if (file.endsWith('workflow.yaml')) {
744
+ await fs.ensureDir(path.dirname(targetFile));
745
+ await this.copyWorkflowYamlStripped(sourceFile, targetFile);
746
+ } else {
747
+ // Copy the file with placeholder replacement
748
+ await this.copyFileWithPlaceholderReplacement(sourceFile, targetFile);
749
+ }
750
+
751
+ // Track the file if callback provided
752
+ if (fileTrackingCallback) {
753
+ fileTrackingCallback(targetFile);
754
+ }
755
+ }
756
+ }
757
+
758
+ /**
759
+ * Copy workflow.yaml file with web_bundle section stripped
760
+ * Preserves comments, formatting, and line breaks
761
+ * @param {string} sourceFile - Source workflow.yaml file path
762
+ * @param {string} targetFile - Target workflow.yaml file path
763
+ */
764
+ async copyWorkflowYamlStripped(sourceFile, targetFile) {
765
+ // Read the source YAML file
766
+ let yamlContent = await fs.readFile(sourceFile, 'utf8');
767
+
768
+ // IMPORTANT: Replace escape sequence and placeholder BEFORE parsing YAML
769
+ // Otherwise parsing will fail on the placeholder
770
+ yamlContent = yamlContent.replaceAll('_bmad', '_bmad');
771
+ yamlContent = yamlContent.replaceAll('_bmad', this.bmadFolderName);
772
+
773
+ try {
774
+ // First check if web_bundle exists by parsing
775
+ const workflowConfig = yaml.parse(yamlContent);
776
+
777
+ if (workflowConfig.web_bundle === undefined) {
778
+ // No web_bundle section, just write (placeholders already replaced above)
779
+ await fs.writeFile(targetFile, yamlContent, 'utf8');
780
+ return;
781
+ }
782
+
783
+ // Remove web_bundle section using regex to preserve formatting
784
+ // Match the web_bundle key and all its content (including nested items)
785
+ // This handles both web_bundle: false and web_bundle: {...}
786
+
787
+ // Find the line that starts web_bundle
788
+ const lines = yamlContent.split('\n');
789
+ let startIdx = -1;
790
+ let endIdx = -1;
791
+ let baseIndent = 0;
792
+
793
+ // Find the start of web_bundle section
794
+ for (const [i, line] of lines.entries()) {
795
+ const match = line.match(/^(\s*)web_bundle:/);
796
+ if (match) {
797
+ startIdx = i;
798
+ baseIndent = match[1].length;
799
+ break;
800
+ }
801
+ }
802
+
803
+ if (startIdx === -1) {
804
+ // web_bundle not found in text (shouldn't happen), copy as-is
805
+ await fs.writeFile(targetFile, yamlContent, 'utf8');
806
+ return;
807
+ }
808
+
809
+ // Find the end of web_bundle section
810
+ // It ends when we find a line with same or less indentation that's not empty/comment
811
+ endIdx = startIdx;
812
+ for (let i = startIdx + 1; i < lines.length; i++) {
813
+ const line = lines[i];
814
+
815
+ // Skip empty lines and comments
816
+ if (line.trim() === '' || line.trim().startsWith('#')) {
817
+ continue;
818
+ }
819
+
820
+ // Check indentation
821
+ const indent = line.match(/^(\s*)/)[1].length;
822
+ if (indent <= baseIndent) {
823
+ // Found next section at same or lower indentation
824
+ endIdx = i - 1;
825
+ break;
826
+ }
827
+ }
828
+
829
+ // If we didn't find an end, it goes to end of file
830
+ if (endIdx === startIdx) {
831
+ endIdx = lines.length - 1;
832
+ }
833
+
834
+ // Remove the web_bundle section (including the line before if it's just a blank line)
835
+ const newLines = [...lines.slice(0, startIdx), ...lines.slice(endIdx + 1)];
836
+
837
+ // Clean up any double blank lines that might result
838
+ const strippedYaml = newLines.join('\n').replaceAll(/\n\n\n+/g, '\n\n');
839
+
840
+ // Placeholders already replaced at the beginning of this function
841
+ await fs.writeFile(targetFile, strippedYaml, 'utf8');
842
+ } catch {
843
+ // If anything fails, just copy the file as-is
844
+ console.warn(chalk.yellow(` Warning: Could not process ${path.basename(sourceFile)}, copying as-is`));
845
+ await fs.copy(sourceFile, targetFile, { overwrite: true });
846
+ }
847
+ }
848
+
849
+ /**
850
+ * Compile .agent.yaml files to .md format in modules
851
+ * @param {string} sourcePath - Source module path
852
+ * @param {string} targetPath - Target module path
853
+ * @param {string} moduleName - Module name
854
+ * @param {string} bmadDir - BMAD installation directory
855
+ * @param {Object} installer - Installer instance for file tracking
856
+ */
857
+ async compileModuleAgents(sourcePath, targetPath, moduleName, bmadDir, installer = null) {
858
+ const sourceAgentsPath = path.join(sourcePath, 'agents');
859
+ const targetAgentsPath = path.join(targetPath, 'agents');
860
+ const cfgAgentsDir = path.join(bmadDir, '_config', 'agents');
861
+
862
+ // Check if agents directory exists in source
863
+ if (!(await fs.pathExists(sourceAgentsPath))) {
864
+ return; // No agents to compile
865
+ }
866
+
867
+ // Get all agent YAML files recursively
868
+ const agentFiles = await this.findAgentFiles(sourceAgentsPath);
869
+
870
+ for (const agentFile of agentFiles) {
871
+ if (!agentFile.endsWith('.agent.yaml')) continue;
872
+
873
+ const relativePath = path.relative(sourceAgentsPath, agentFile);
874
+ const targetDir = path.join(targetAgentsPath, path.dirname(relativePath));
875
+
876
+ await fs.ensureDir(targetDir);
877
+
878
+ const agentName = path.basename(agentFile, '.agent.yaml');
879
+ const sourceYamlPath = agentFile;
880
+ const targetMdPath = path.join(targetDir, `${agentName}.md`);
881
+ const customizePath = path.join(cfgAgentsDir, `${moduleName}-${agentName}.customize.yaml`);
882
+
883
+ // Read and compile the YAML
884
+ try {
885
+ const yamlContent = await fs.readFile(sourceYamlPath, 'utf8');
886
+ const { compileAgent } = require('../../../lib/agent/compiler');
887
+
888
+ // Create customize template if it doesn't exist
889
+ if (!(await fs.pathExists(customizePath))) {
890
+ const { getSourcePath } = require('../../../lib/project-root');
891
+ const genericTemplatePath = getSourcePath('utility', 'agent-components', 'agent.customize.template.yaml');
892
+ if (await fs.pathExists(genericTemplatePath)) {
893
+ await this.copyFileWithPlaceholderReplacement(genericTemplatePath, customizePath);
894
+ // Only show customize creation in verbose mode
895
+ if (process.env.BMAD_VERBOSE_INSTALL === 'true') {
896
+ console.log(chalk.dim(` Created customize: ${moduleName}-${agentName}.customize.yaml`));
897
+ }
898
+
899
+ // Store original hash for modification detection
900
+ const crypto = require('node:crypto');
901
+ const customizeContent = await fs.readFile(customizePath, 'utf8');
902
+ const originalHash = crypto.createHash('sha256').update(customizeContent).digest('hex');
903
+
904
+ // Store in main manifest
905
+ const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml');
906
+ let manifestData = {};
907
+ if (await fs.pathExists(manifestPath)) {
908
+ const manifestContent = await fs.readFile(manifestPath, 'utf8');
909
+ const yaml = require('yaml');
910
+ manifestData = yaml.parse(manifestContent);
911
+ }
912
+ if (!manifestData.agentCustomizations) {
913
+ manifestData.agentCustomizations = {};
914
+ }
915
+ manifestData.agentCustomizations[path.relative(bmadDir, customizePath)] = originalHash;
916
+
917
+ // Write back to manifest
918
+ const yaml = require('yaml');
919
+ // Clean the manifest data to remove any non-serializable values
920
+ const cleanManifestData = structuredClone(manifestData);
921
+
922
+ const updatedContent = yaml.stringify(cleanManifestData, {
923
+ indent: 2,
924
+ lineWidth: 0,
925
+ });
926
+ await fs.writeFile(manifestPath, updatedContent, 'utf8');
927
+ }
928
+ }
929
+
930
+ // Check for customizations and build answers object
931
+ let customizedFields = [];
932
+ let answers = {};
933
+ if (await fs.pathExists(customizePath)) {
934
+ const customizeContent = await fs.readFile(customizePath, 'utf8');
935
+ const customizeData = yaml.parse(customizeContent);
936
+ customizedFields = customizeData.customized_fields || [];
937
+
938
+ // Build answers object from customizations
939
+ if (customizeData.persona) {
940
+ answers.persona = customizeData.persona;
941
+ }
942
+ if (customizeData.agent?.metadata) {
943
+ const filteredMetadata = filterCustomizationData(customizeData.agent.metadata);
944
+ if (Object.keys(filteredMetadata).length > 0) {
945
+ Object.assign(answers, { metadata: filteredMetadata });
946
+ }
947
+ }
948
+ if (customizeData.critical_actions && customizeData.critical_actions.length > 0) {
949
+ answers.critical_actions = customizeData.critical_actions;
950
+ }
951
+ if (customizeData.memories && customizeData.memories.length > 0) {
952
+ answers.memories = customizeData.memories;
953
+ }
954
+ if (customizeData.menu && customizeData.menu.length > 0) {
955
+ answers.menu = customizeData.menu;
956
+ }
957
+ if (customizeData.prompts && customizeData.prompts.length > 0) {
958
+ answers.prompts = customizeData.prompts;
959
+ }
960
+ }
961
+
962
+ // Check if agent has sidecar
963
+ let hasSidecar = false;
964
+ try {
965
+ const agentYaml = yaml.parse(yamlContent);
966
+ hasSidecar = agentYaml?.agent?.metadata?.hasSidecar === true;
967
+ } catch {
968
+ // Continue without sidecar processing
969
+ }
970
+
971
+ // Compile with customizations if any
972
+ const { xml } = await compileAgent(yamlContent, answers, agentName, relativePath, { config: this.coreConfig || {} });
973
+
974
+ // Write the compiled agent
975
+ await fs.writeFile(targetMdPath, xml, 'utf8');
976
+
977
+ // Handle sidecar copying if present
978
+ if (hasSidecar) {
979
+ // Get the agent's directory to look for sidecar
980
+ const agentDir = path.dirname(agentFile);
981
+ const sidecarDirName = `${agentName}-sidecar`;
982
+ const sourceSidecarPath = path.join(agentDir, sidecarDirName);
983
+
984
+ // Check if sidecar directory exists
985
+ if (await fs.pathExists(sourceSidecarPath)) {
986
+ // Memory is always in _bmad/_memory
987
+ const bmadMemoryPath = path.join(bmadDir, '_memory');
988
+
989
+ // Determine if this is an update (by checking if agent already exists)
990
+ const isUpdate = await fs.pathExists(targetMdPath);
991
+
992
+ // Copy sidecar to memory location with update-safe handling
993
+ const copiedFiles = await this.copySidecarToMemory(sourceSidecarPath, agentName, bmadMemoryPath, isUpdate, bmadDir, installer);
994
+
995
+ if (process.env.BMAD_VERBOSE_INSTALL === 'true' && copiedFiles.length > 0) {
996
+ console.log(chalk.dim(` Sidecar files processed: ${copiedFiles.length} files`));
997
+ }
998
+ } else if (process.env.BMAD_VERBOSE_INSTALL === 'true') {
999
+ console.log(chalk.yellow(` Warning: Agent marked as having sidecar but ${sidecarDirName} directory not found`));
1000
+ }
1001
+ }
1002
+
1003
+ // Copy any non-sidecar files from agent directory (e.g., foo.md)
1004
+ const agentDir = path.dirname(agentFile);
1005
+ const agentEntries = await fs.readdir(agentDir, { withFileTypes: true });
1006
+
1007
+ for (const entry of agentEntries) {
1008
+ if (entry.isFile() && !entry.name.endsWith('.agent.yaml') && !entry.name.endsWith('.md')) {
1009
+ // Copy additional files (like foo.md) to the agent target directory
1010
+ const sourceFile = path.join(agentDir, entry.name);
1011
+ const targetFile = path.join(targetDir, entry.name);
1012
+ await this.copyFileWithPlaceholderReplacement(sourceFile, targetFile);
1013
+ }
1014
+ }
1015
+
1016
+ // Only show compilation details in verbose mode
1017
+ if (process.env.BMAD_VERBOSE_INSTALL === 'true') {
1018
+ console.log(
1019
+ chalk.dim(
1020
+ ` Compiled agent: ${agentName} -> ${path.relative(targetPath, targetMdPath)}${hasSidecar ? ' (with sidecar)' : ''}`,
1021
+ ),
1022
+ );
1023
+ }
1024
+ } catch (error) {
1025
+ console.warn(chalk.yellow(` Failed to compile agent ${agentName}:`, error.message));
1026
+ }
1027
+ }
1028
+ }
1029
+
1030
+ /**
1031
+ * Find all .agent.yaml files recursively in a directory
1032
+ * @param {string} dir - Directory to search
1033
+ * @returns {Array} List of .agent.yaml file paths
1034
+ */
1035
+ async findAgentFiles(dir) {
1036
+ const agentFiles = [];
1037
+
1038
+ async function searchDirectory(searchDir) {
1039
+ const entries = await fs.readdir(searchDir, { withFileTypes: true });
1040
+
1041
+ for (const entry of entries) {
1042
+ const fullPath = path.join(searchDir, entry.name);
1043
+
1044
+ if (entry.isFile() && entry.name.endsWith('.agent.yaml')) {
1045
+ agentFiles.push(fullPath);
1046
+ } else if (entry.isDirectory()) {
1047
+ await searchDirectory(fullPath);
1048
+ }
1049
+ }
1050
+ }
1051
+
1052
+ await searchDirectory(dir);
1053
+ return agentFiles;
1054
+ }
1055
+
1056
+ /**
1057
+ * Process agent files to inject activation block
1058
+ * @param {string} modulePath - Path to installed module
1059
+ * @param {string} moduleName - Module name
1060
+ */
1061
+ async processAgentFiles(modulePath, moduleName) {
1062
+ // const agentsPath = path.join(modulePath, 'agents');
1063
+ // // Check if agents directory exists
1064
+ // if (!(await fs.pathExists(agentsPath))) {
1065
+ // return; // No agents to process
1066
+ // }
1067
+ // // Get all agent MD files recursively
1068
+ // const agentFiles = await this.findAgentMdFiles(agentsPath);
1069
+ // for (const agentFile of agentFiles) {
1070
+ // if (!agentFile.endsWith('.md')) continue;
1071
+ // let content = await fs.readFile(agentFile, 'utf8');
1072
+ // // Check if content has agent XML and no activation block
1073
+ // if (content.includes('<agent') && !content.includes('<activation')) {
1074
+ // // Inject the activation block using XML handler
1075
+ // content = this.xmlHandler.injectActivationSimple(content);
1076
+ // await fs.writeFile(agentFile, content, 'utf8');
1077
+ // }
1078
+ // }
1079
+ }
1080
+
1081
+ /**
1082
+ * Find all .md agent files recursively in a directory
1083
+ * @param {string} dir - Directory to search
1084
+ * @returns {Array} List of .md agent file paths
1085
+ */
1086
+ async findAgentMdFiles(dir) {
1087
+ const agentFiles = [];
1088
+
1089
+ async function searchDirectory(searchDir) {
1090
+ const entries = await fs.readdir(searchDir, { withFileTypes: true });
1091
+
1092
+ for (const entry of entries) {
1093
+ const fullPath = path.join(searchDir, entry.name);
1094
+
1095
+ if (entry.isFile() && entry.name.endsWith('.md')) {
1096
+ agentFiles.push(fullPath);
1097
+ } else if (entry.isDirectory()) {
1098
+ await searchDirectory(fullPath);
1099
+ }
1100
+ }
1101
+ }
1102
+
1103
+ await searchDirectory(dir);
1104
+ return agentFiles;
1105
+ }
1106
+
1107
+ /**
1108
+ * Vendor cross-module workflows referenced in agent files
1109
+ * Scans SOURCE agent.yaml files for workflow-install and copies workflows to destination
1110
+ * @param {string} sourcePath - Source module path
1111
+ * @param {string} targetPath - Target module path (destination)
1112
+ * @param {string} moduleName - Module name being installed
1113
+ */
1114
+ async vendorCrossModuleWorkflows(sourcePath, targetPath, moduleName) {
1115
+ const sourceAgentsPath = path.join(sourcePath, 'agents');
1116
+
1117
+ // Check if source agents directory exists
1118
+ if (!(await fs.pathExists(sourceAgentsPath))) {
1119
+ return; // No agents to process
1120
+ }
1121
+
1122
+ // Get all agent YAML files from source
1123
+ const agentFiles = await fs.readdir(sourceAgentsPath);
1124
+ const yamlFiles = agentFiles.filter((f) => f.endsWith('.agent.yaml') || f.endsWith('.yaml'));
1125
+
1126
+ if (yamlFiles.length === 0) {
1127
+ return; // No YAML agent files
1128
+ }
1129
+
1130
+ let workflowsVendored = false;
1131
+
1132
+ for (const agentFile of yamlFiles) {
1133
+ const agentPath = path.join(sourceAgentsPath, agentFile);
1134
+ const agentYaml = yaml.parse(await fs.readFile(agentPath, 'utf8'));
1135
+
1136
+ // Check if agent has menu items with workflow-install
1137
+ const menuItems = agentYaml?.agent?.menu || [];
1138
+ const workflowInstallItems = menuItems.filter((item) => item['workflow-install']);
1139
+
1140
+ if (workflowInstallItems.length === 0) {
1141
+ continue; // No workflow-install in this agent
1142
+ }
1143
+
1144
+ if (!workflowsVendored) {
1145
+ console.log(chalk.cyan(`\n Vendoring cross-module workflows for ${moduleName}...`));
1146
+ workflowsVendored = true;
1147
+ }
1148
+
1149
+ console.log(chalk.dim(` Processing: ${agentFile}`));
1150
+
1151
+ for (const item of workflowInstallItems) {
1152
+ const sourceWorkflowPath = item.workflow; // Where to copy FROM
1153
+ const installWorkflowPath = item['workflow-install']; // Where to copy TO
1154
+
1155
+ // Parse SOURCE workflow path
1156
+ // Handle both _bmad placeholder and hardcoded 'bmad'
1157
+ // Example: {project-root}/_bmad/bmm/workflows/4-implementation/create-story/workflow.yaml
1158
+ // Or: {project-root}/bmad/bmm/workflows/4-implementation/create-story/workflow.yaml
1159
+ const sourceMatch = sourceWorkflowPath.match(/\{project-root\}\/(?:_bmad)\/([^/]+)\/workflows\/(.+)/);
1160
+ if (!sourceMatch) {
1161
+ console.warn(chalk.yellow(` Could not parse workflow path: ${sourceWorkflowPath}`));
1162
+ continue;
1163
+ }
1164
+
1165
+ const [, sourceModule, sourceWorkflowSubPath] = sourceMatch;
1166
+
1167
+ // Parse INSTALL workflow path
1168
+ // Handle_bmad
1169
+ // Example: {project-root}/_bmad/bmgd/workflows/4-production/create-story/workflow.yaml
1170
+ const installMatch = installWorkflowPath.match(/\{project-root\}\/(_bmad)\/([^/]+)\/workflows\/(.+)/);
1171
+ if (!installMatch) {
1172
+ console.warn(chalk.yellow(` Could not parse workflow-install path: ${installWorkflowPath}`));
1173
+ continue;
1174
+ }
1175
+
1176
+ const installWorkflowSubPath = installMatch[2];
1177
+
1178
+ const sourceModulePath = getModulePath(sourceModule);
1179
+ const actualSourceWorkflowPath = path.join(sourceModulePath, 'workflows', sourceWorkflowSubPath.replace(/\/workflow\.yaml$/, ''));
1180
+
1181
+ const actualDestWorkflowPath = path.join(targetPath, 'workflows', installWorkflowSubPath.replace(/\/workflow\.yaml$/, ''));
1182
+
1183
+ // Check if source workflow exists
1184
+ if (!(await fs.pathExists(actualSourceWorkflowPath))) {
1185
+ console.warn(chalk.yellow(` Source workflow not found: ${actualSourceWorkflowPath}`));
1186
+ continue;
1187
+ }
1188
+
1189
+ // Copy the entire workflow folder
1190
+ console.log(
1191
+ chalk.dim(
1192
+ ` Vendoring: ${sourceModule}/workflows/${sourceWorkflowSubPath.replace(/\/workflow\.yaml$/, '')} → ${moduleName}/workflows/${installWorkflowSubPath.replace(/\/workflow\.yaml$/, '')}`,
1193
+ ),
1194
+ );
1195
+
1196
+ await fs.ensureDir(path.dirname(actualDestWorkflowPath));
1197
+ // Copy the workflow directory recursively with placeholder replacement
1198
+ await this.copyDirectoryWithPlaceholderReplacement(actualSourceWorkflowPath, actualDestWorkflowPath);
1199
+
1200
+ // Update the workflow.yaml config_source reference
1201
+ const workflowYamlPath = path.join(actualDestWorkflowPath, 'workflow.yaml');
1202
+ if (await fs.pathExists(workflowYamlPath)) {
1203
+ await this.updateWorkflowConfigSource(workflowYamlPath, moduleName);
1204
+ }
1205
+ }
1206
+ }
1207
+
1208
+ if (workflowsVendored) {
1209
+ console.log(chalk.green(` ✓ Workflow vendoring complete\n`));
1210
+ }
1211
+ }
1212
+
1213
+ /**
1214
+ * Update workflow.yaml config_source to point to new module
1215
+ * @param {string} workflowYamlPath - Path to workflow.yaml file
1216
+ * @param {string} newModuleName - New module name to reference
1217
+ */
1218
+ async updateWorkflowConfigSource(workflowYamlPath, newModuleName) {
1219
+ let yamlContent = await fs.readFile(workflowYamlPath, 'utf8');
1220
+
1221
+ // Replace config_source: "{project-root}/_bmad/OLD_MODULE/config.yaml"
1222
+ // with config_source: "{project-root}/_bmad/NEW_MODULE/config.yaml"
1223
+ // Note: At this point _bmad has already been replaced with actual folder name
1224
+ const configSourcePattern = /config_source:\s*["']?\{project-root\}\/[^/]+\/[^/]+\/config\.yaml["']?/g;
1225
+ const newConfigSource = `config_source: "{project-root}/${this.bmadFolderName}/${newModuleName}/config.yaml"`;
1226
+
1227
+ const updatedYaml = yamlContent.replaceAll(configSourcePattern, newConfigSource);
1228
+
1229
+ if (updatedYaml !== yamlContent) {
1230
+ await fs.writeFile(workflowYamlPath, updatedYaml, 'utf8');
1231
+ console.log(chalk.dim(` Updated config_source to: ${this.bmadFolderName}/${newModuleName}/config.yaml`));
1232
+ }
1233
+ }
1234
+
1235
+ /**
1236
+ * Run module-specific installer if it exists
1237
+ * @param {string} moduleName - Name of the module
1238
+ * @param {string} bmadDir - Target bmad directory
1239
+ * @param {Object} options - Installation options
1240
+ */
1241
+ async runModuleInstaller(moduleName, bmadDir, options = {}) {
1242
+ // Special handling for core module - it's in src/core not src/modules
1243
+ let sourcePath;
1244
+ if (moduleName === 'core') {
1245
+ sourcePath = getSourcePath('core');
1246
+ } else {
1247
+ sourcePath = await this.findModuleSource(moduleName);
1248
+ if (!sourcePath) {
1249
+ // No source found, skip module installer
1250
+ return;
1251
+ }
1252
+ }
1253
+
1254
+ const installerPath = path.join(sourcePath, '_module-installer', 'installer.js');
1255
+
1256
+ // Check if module has a custom installer
1257
+ if (!(await fs.pathExists(installerPath))) {
1258
+ return; // No custom installer
1259
+ }
1260
+
1261
+ try {
1262
+ // Load the module installer
1263
+ const moduleInstaller = require(installerPath);
1264
+
1265
+ if (typeof moduleInstaller.install === 'function') {
1266
+ // Get project root (parent of bmad directory)
1267
+ const projectRoot = path.dirname(bmadDir);
1268
+
1269
+ // Prepare logger (use console if not provided)
1270
+ const logger = options.logger || {
1271
+ log: console.log,
1272
+ error: console.error,
1273
+ warn: console.warn,
1274
+ };
1275
+
1276
+ // Call the module installer
1277
+ const result = await moduleInstaller.install({
1278
+ projectRoot,
1279
+ config: options.moduleConfig || {},
1280
+ coreConfig: options.coreConfig || {},
1281
+ installedIDEs: options.installedIDEs || [],
1282
+ logger,
1283
+ });
1284
+
1285
+ if (!result) {
1286
+ console.warn(chalk.yellow(`Module installer for ${moduleName} returned false`));
1287
+ }
1288
+ }
1289
+ } catch (error) {
1290
+ console.error(chalk.red(`Error running module installer for ${moduleName}: ${error.message}`));
1291
+ }
1292
+ }
1293
+
1294
+ /**
1295
+ * Private: Process module configuration
1296
+ * @param {string} modulePath - Path to installed module
1297
+ * @param {string} moduleName - Module name
1298
+ */
1299
+ async processModuleConfig(modulePath, moduleName) {
1300
+ const configPath = path.join(modulePath, 'config.yaml');
1301
+
1302
+ if (await fs.pathExists(configPath)) {
1303
+ try {
1304
+ let configContent = await fs.readFile(configPath, 'utf8');
1305
+
1306
+ // Replace path placeholders
1307
+ configContent = configContent.replaceAll('{project-root}', `bmad/${moduleName}`);
1308
+ configContent = configContent.replaceAll('{module}', moduleName);
1309
+
1310
+ await fs.writeFile(configPath, configContent, 'utf8');
1311
+ } catch (error) {
1312
+ console.warn(`Failed to process module config:`, error.message);
1313
+ }
1314
+ }
1315
+ }
1316
+
1317
+ /**
1318
+ * Private: Sync module files (preserving user modifications)
1319
+ * @param {string} sourcePath - Source module path
1320
+ * @param {string} targetPath - Target module path
1321
+ */
1322
+ async syncModule(sourcePath, targetPath) {
1323
+ // Get list of all source files
1324
+ const sourceFiles = await this.getFileList(sourcePath);
1325
+
1326
+ for (const file of sourceFiles) {
1327
+ const sourceFile = path.join(sourcePath, file);
1328
+ const targetFile = path.join(targetPath, file);
1329
+
1330
+ // Check if target file exists and has been modified
1331
+ if (await fs.pathExists(targetFile)) {
1332
+ const sourceStats = await fs.stat(sourceFile);
1333
+ const targetStats = await fs.stat(targetFile);
1334
+
1335
+ // Skip if target is newer (user modified)
1336
+ if (targetStats.mtime > sourceStats.mtime) {
1337
+ continue;
1338
+ }
1339
+ }
1340
+
1341
+ // Copy file with placeholder replacement
1342
+ await this.copyFileWithPlaceholderReplacement(sourceFile, targetFile);
1343
+ }
1344
+ }
1345
+
1346
+ /**
1347
+ * Private: Get list of all files in a directory
1348
+ * @param {string} dir - Directory path
1349
+ * @param {string} baseDir - Base directory for relative paths
1350
+ * @returns {Array} List of relative file paths
1351
+ */
1352
+ async getFileList(dir, baseDir = dir) {
1353
+ const files = [];
1354
+ const entries = await fs.readdir(dir, { withFileTypes: true });
1355
+
1356
+ for (const entry of entries) {
1357
+ const fullPath = path.join(dir, entry.name);
1358
+
1359
+ if (entry.isDirectory()) {
1360
+ // Skip _module-installer directories
1361
+ if (entry.name === '_module-installer') {
1362
+ continue;
1363
+ }
1364
+ const subFiles = await this.getFileList(fullPath, baseDir);
1365
+ files.push(...subFiles);
1366
+ } else {
1367
+ files.push(path.relative(baseDir, fullPath));
1368
+ }
1369
+ }
1370
+
1371
+ return files;
1372
+ }
1373
+ }
1374
+
1375
+ module.exports = { ModuleManager };