bmad-method-quarkus 1.0.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 (380) hide show
  1. package/.claude-plugin/marketplace.json +53 -0
  2. package/AGENTS.md +12 -0
  3. package/LICENSE +30 -0
  4. package/README.md +94 -0
  5. package/README_CN.md +108 -0
  6. package/README_VN.md +109 -0
  7. package/bmad-modules.yaml +133 -0
  8. package/package.json +123 -0
  9. package/removals.txt +87 -0
  10. package/src/bmm-skills/agents/bmad-agent-analyst/SKILL.md +76 -0
  11. package/src/bmm-skills/agents/bmad-agent-analyst/customize.toml +105 -0
  12. package/src/bmm-skills/agents/bmad-agent-architect/SKILL.md +76 -0
  13. package/src/bmm-skills/agents/bmad-agent-architect/customize.toml +65 -0
  14. package/src/bmm-skills/agents/bmad-agent-dev/SKILL.md +76 -0
  15. package/src/bmm-skills/agents/bmad-agent-dev/customize.toml +83 -0
  16. package/src/bmm-skills/agents/bmad-agent-pm/SKILL.md +76 -0
  17. package/src/bmm-skills/agents/bmad-agent-pm/customize.toml +75 -0
  18. package/src/bmm-skills/agents/bmad-agent-ux-designer/SKILL.md +76 -0
  19. package/src/bmm-skills/agents/bmad-agent-ux-designer/customize.toml +60 -0
  20. package/src/bmm-skills/agents/bmad-quarkus-architect/.memlog.md +12 -0
  21. package/src/bmm-skills/agents/bmad-quarkus-architect/.memlog.md:Zone.Identifier +0 -0
  22. package/src/bmm-skills/agents/bmad-quarkus-architect/SKILL.md +86 -0
  23. package/src/bmm-skills/agents/bmad-quarkus-architect/SKILL.md:Zone.Identifier +0 -0
  24. package/src/bmm-skills/agents/bmad-quarkus-architect/customize.toml +37 -0
  25. package/src/bmm-skills/agents/bmad-quarkus-architect/customize.toml:Zone.Identifier +0 -0
  26. package/src/bmm-skills/agents/bmad-quarkus-architect/references/enrich-stories.md +19 -0
  27. package/src/bmm-skills/agents/bmad-quarkus-architect/references/enrich-stories.md:Zone.Identifier +0 -0
  28. package/src/bmm-skills/agents/bmad-quarkus-architect/references/prompt-quality-canon.md +79 -0
  29. package/src/bmm-skills/agents/bmad-quarkus-architect/references/prompt-quality-canon.md:Zone.Identifier +0 -0
  30. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/SKILL.md +80 -0
  31. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/SKILL.md:Zone.Identifier +0 -0
  32. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module-help.csv +9 -0
  33. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module-help.csv:Zone.Identifier +0 -0
  34. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module.yaml +16 -0
  35. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module.yaml:Zone.Identifier +0 -0
  36. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/cleanup-legacy.py +287 -0
  37. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/cleanup-legacy.py:Zone.Identifier +0 -0
  38. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-config.py +441 -0
  39. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-config.py:Zone.Identifier +0 -0
  40. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-help-csv.py +246 -0
  41. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-help-csv.py:Zone.Identifier +0 -0
  42. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-error-handling-i18n/SKILL.md +181 -0
  43. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-error-handling-i18n/SKILL.md:Zone.Identifier +0 -0
  44. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-grpc-services/SKILL.md +141 -0
  45. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-grpc-services/SKILL.md:Zone.Identifier +0 -0
  46. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-hexagonal-core/SKILL.md +392 -0
  47. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-hexagonal-core/SKILL.md:Zone.Identifier +0 -0
  48. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-kafka-messaging/SKILL.md +148 -0
  49. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-kafka-messaging/SKILL.md:Zone.Identifier +0 -0
  50. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-observability-otel/SKILL.md +180 -0
  51. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-observability-otel/SKILL.md:Zone.Identifier +0 -0
  52. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-openapi-tmforum/SKILL.md +128 -0
  53. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-openapi-tmforum/SKILL.md:Zone.Identifier +0 -0
  54. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-sql-jdbc-agroal/SKILL.md +245 -0
  55. package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-sql-jdbc-agroal/SKILL.md:Zone.Identifier +0 -0
  56. package/src/bmm-skills/module-help.csv +19 -0
  57. package/src/bmm-skills/module.yaml +92 -0
  58. package/src/bmm-skills/plan/bmad-architecture/SKILL.md +85 -0
  59. package/src/bmm-skills/plan/bmad-architecture/assets/spine-template.md +79 -0
  60. package/src/bmm-skills/plan/bmad-architecture/customize.toml +102 -0
  61. package/src/bmm-skills/plan/bmad-architecture/references/headless.md +26 -0
  62. package/src/bmm-skills/plan/bmad-architecture/references/reviewer-gate.md +13 -0
  63. package/src/bmm-skills/plan/bmad-architecture/scripts/lint_spine.py +257 -0
  64. package/src/bmm-skills/plan/bmad-architecture/scripts/tests/test_lint_spine.py +270 -0
  65. package/src/bmm-skills/plan/bmad-create-epics-and-stories/SKILL.md +93 -0
  66. package/src/bmm-skills/plan/bmad-create-epics-and-stories/customize.toml +41 -0
  67. package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-01-validate-prerequisites.md +263 -0
  68. package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-02-design-epics.md +242 -0
  69. package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-03-create-stories.md +255 -0
  70. package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-04-final-validation.md +143 -0
  71. package/src/bmm-skills/plan/bmad-create-epics-and-stories/templates/epics-template.md +61 -0
  72. package/src/bmm-skills/plan/bmad-generate-project-context/SKILL.md +10 -0
  73. package/src/bmm-skills/plan/bmad-prd/SKILL.md +94 -0
  74. package/src/bmm-skills/plan/bmad-prd/assets/headless-schemas.md +76 -0
  75. package/src/bmm-skills/plan/bmad-prd/assets/prd-template.md +165 -0
  76. package/src/bmm-skills/plan/bmad-prd/assets/prd-validation-checklist.md +135 -0
  77. package/src/bmm-skills/plan/bmad-prd/assets/validation-report-template.html +325 -0
  78. package/src/bmm-skills/plan/bmad-prd/customize.toml +149 -0
  79. package/src/bmm-skills/plan/bmad-prd/references/headless.md +39 -0
  80. package/src/bmm-skills/plan/bmad-prd/references/validate.md +97 -0
  81. package/src/bmm-skills/plan/bmad-prfaq/SKILL.md +135 -0
  82. package/src/bmm-skills/plan/bmad-prfaq/agents/artifact-analyzer.md +60 -0
  83. package/src/bmm-skills/plan/bmad-prfaq/agents/web-researcher.md +49 -0
  84. package/src/bmm-skills/plan/bmad-prfaq/assets/prfaq-template.md +62 -0
  85. package/src/bmm-skills/plan/bmad-prfaq/bmad-manifest.json +16 -0
  86. package/src/bmm-skills/plan/bmad-prfaq/customize.toml +41 -0
  87. package/src/bmm-skills/plan/bmad-prfaq/references/customer-faq.md +55 -0
  88. package/src/bmm-skills/plan/bmad-prfaq/references/internal-faq.md +51 -0
  89. package/src/bmm-skills/plan/bmad-prfaq/references/press-release.md +60 -0
  90. package/src/bmm-skills/plan/bmad-prfaq/references/verdict.md +83 -0
  91. package/src/bmm-skills/plan/bmad-product-brief/SKILL.md +91 -0
  92. package/src/bmm-skills/plan/bmad-product-brief/assets/brief-template.md +41 -0
  93. package/src/bmm-skills/plan/bmad-product-brief/customize.toml +101 -0
  94. package/src/bmm-skills/plan/bmad-project-context/SKILL.md +110 -0
  95. package/src/bmm-skills/plan/bmad-project-context/customize.toml +24 -0
  96. package/src/bmm-skills/plan/bmad-project-context/references/best-practices.md +65 -0
  97. package/src/bmm-skills/plan/bmad-project-context/references/template.md +55 -0
  98. package/src/bmm-skills/plan/bmad-spec/SKILL.md +160 -0
  99. package/src/bmm-skills/plan/bmad-spec/assets/headless-schemas.md +33 -0
  100. package/src/bmm-skills/plan/bmad-spec/assets/spec-template.md +49 -0
  101. package/src/bmm-skills/plan/bmad-spec/assets/stories-schema.md +44 -0
  102. package/src/bmm-skills/plan/bmad-spec/customize.toml +52 -0
  103. package/src/bmm-skills/plan/bmad-sprint-planning/SKILL.md +62 -0
  104. package/src/bmm-skills/plan/bmad-sprint-planning/customize.toml +41 -0
  105. package/src/bmm-skills/plan/bmad-sprint-planning/references/fix-sprint-status.md +30 -0
  106. package/src/bmm-skills/plan/bmad-sprint-planning/references/generate-tracking.md +25 -0
  107. package/src/bmm-skills/plan/bmad-sprint-planning/references/readiness-gate.md +20 -0
  108. package/src/bmm-skills/plan/bmad-sprint-planning/references/status-view.md +14 -0
  109. package/src/bmm-skills/plan/bmad-sprint-planning/references/validate.md +10 -0
  110. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc +0 -0
  111. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/sprint_plan.py +697 -0
  112. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-311-pytest-9.1.1.pyc +0 -0
  113. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/test_sprint_plan.py +524 -0
  114. package/src/bmm-skills/plan/bmad-sprint-planning/sprint-status-template.yaml +71 -0
  115. package/src/bmm-skills/plan/bmad-ux/SKILL.md +90 -0
  116. package/src/bmm-skills/plan/bmad-ux/assets/color-themes.md +9 -0
  117. package/src/bmm-skills/plan/bmad-ux/assets/design-directions.md +9 -0
  118. package/src/bmm-skills/plan/bmad-ux/assets/design-example-editorial.md +158 -0
  119. package/src/bmm-skills/plan/bmad-ux/assets/design-example-mobile.md +93 -0
  120. package/src/bmm-skills/plan/bmad-ux/assets/design-example-shadcn.md +109 -0
  121. package/src/bmm-skills/plan/bmad-ux/assets/excalidraw-wireframe.md +19 -0
  122. package/src/bmm-skills/plan/bmad-ux/assets/experience-example-mobile.md +112 -0
  123. package/src/bmm-skills/plan/bmad-ux/assets/experience-example-shadcn.md +133 -0
  124. package/src/bmm-skills/plan/bmad-ux/assets/headless-schemas.md +84 -0
  125. package/src/bmm-skills/plan/bmad-ux/assets/key-screens.md +29 -0
  126. package/src/bmm-skills/plan/bmad-ux/assets/validation-report-template.html +319 -0
  127. package/src/bmm-skills/plan/bmad-ux/customize.toml +102 -0
  128. package/src/bmm-skills/plan/bmad-ux/references/creative-tools.md +19 -0
  129. package/src/bmm-skills/plan/bmad-ux/references/design-md-spec.md +50 -0
  130. package/src/bmm-skills/plan/bmad-ux/references/headless.md +37 -0
  131. package/src/bmm-skills/plan/bmad-ux/references/validate.md +115 -0
  132. package/src/bmm-skills/ship/bmad-build/SKILL.md +13 -0
  133. package/src/bmm-skills/ship/bmad-build/compile-epic-context.md +62 -0
  134. package/src/bmm-skills/ship/bmad-build/customize.toml +164 -0
  135. package/src/bmm-skills/ship/bmad-build/references/deletion-check.md +14 -0
  136. package/src/bmm-skills/ship/bmad-build/review-prompts/edge-case-hunter.md +88 -0
  137. package/src/bmm-skills/ship/bmad-build/review-prompts/verification-gap.md +113 -0
  138. package/src/bmm-skills/ship/bmad-build/spec-template.md +89 -0
  139. package/src/bmm-skills/ship/bmad-build/step-01-clarify-and-route.md +105 -0
  140. package/src/bmm-skills/ship/bmad-build/step-02-plan.md +47 -0
  141. package/src/bmm-skills/ship/bmad-build/step-03-implement.md +49 -0
  142. package/src/bmm-skills/ship/bmad-build/step-04-review.md +55 -0
  143. package/src/bmm-skills/ship/bmad-build/step-05-present.md +75 -0
  144. package/src/bmm-skills/ship/bmad-build/step-oneshot.md +77 -0
  145. package/src/bmm-skills/ship/bmad-build/sync-sprint-status.md +19 -0
  146. package/src/bmm-skills/ship/bmad-build/workflow.md +84 -0
  147. package/src/bmm-skills/ship/bmad-build-auto/SKILL.md +13 -0
  148. package/src/bmm-skills/ship/bmad-build-auto/compile-epic-context.md +62 -0
  149. package/src/bmm-skills/ship/bmad-build-auto/customize.toml +121 -0
  150. package/src/bmm-skills/ship/bmad-build-auto/references/deletion-check.md +14 -0
  151. package/src/bmm-skills/ship/bmad-build-auto/review-prompts/edge-case-hunter.md +88 -0
  152. package/src/bmm-skills/ship/bmad-build-auto/review-prompts/verification-gap.md +113 -0
  153. package/src/bmm-skills/ship/bmad-build-auto/spec-template.md +99 -0
  154. package/src/bmm-skills/ship/bmad-build-auto/step-01-clarify-and-route.md +83 -0
  155. package/src/bmm-skills/ship/bmad-build-auto/step-02-plan.md +27 -0
  156. package/src/bmm-skills/ship/bmad-build-auto/step-03-implement.md +44 -0
  157. package/src/bmm-skills/ship/bmad-build-auto/step-04-review.md +96 -0
  158. package/src/bmm-skills/ship/bmad-build-auto/workflow.md +104 -0
  159. package/src/bmm-skills/ship/bmad-checkpoint-preview/SKILL.md +68 -0
  160. package/src/bmm-skills/ship/bmad-checkpoint-preview/customize.toml +41 -0
  161. package/src/bmm-skills/ship/bmad-checkpoint-preview/generate-trail.md +38 -0
  162. package/src/bmm-skills/ship/bmad-checkpoint-preview/step-01-orientation.md +105 -0
  163. package/src/bmm-skills/ship/bmad-checkpoint-preview/step-02-walkthrough.md +89 -0
  164. package/src/bmm-skills/ship/bmad-checkpoint-preview/step-03-detail-pass.md +106 -0
  165. package/src/bmm-skills/ship/bmad-checkpoint-preview/step-04-testing.md +74 -0
  166. package/src/bmm-skills/ship/bmad-checkpoint-preview/step-05-wrapup.md +30 -0
  167. package/src/bmm-skills/ship/bmad-code-review/SKILL.md +90 -0
  168. package/src/bmm-skills/ship/bmad-code-review/customize.toml +113 -0
  169. package/src/bmm-skills/ship/bmad-code-review/references/deletion-check.md +14 -0
  170. package/src/bmm-skills/ship/bmad-code-review/review-prompts/edge-case-hunter.md +88 -0
  171. package/src/bmm-skills/ship/bmad-code-review/review-prompts/verification-gap.md +113 -0
  172. package/src/bmm-skills/ship/bmad-code-review/steps/step-01-gather-context.md +87 -0
  173. package/src/bmm-skills/ship/bmad-code-review/steps/step-02-review.md +32 -0
  174. package/src/bmm-skills/ship/bmad-code-review/steps/step-03-triage.md +50 -0
  175. package/src/bmm-skills/ship/bmad-code-review/steps/step-04-present.md +132 -0
  176. package/src/bmm-skills/ship/bmad-correct-course/SKILL.md +300 -0
  177. package/src/bmm-skills/ship/bmad-correct-course/checklist.md +288 -0
  178. package/src/bmm-skills/ship/bmad-correct-course/customize.toml +41 -0
  179. package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/SKILL.md +176 -0
  180. package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/checklist.md +33 -0
  181. package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/customize.toml +41 -0
  182. package/src/bmm-skills/ship/bmad-retrospective/SKILL.md +94 -0
  183. package/src/bmm-skills/ship/bmad-retrospective/customize.toml +41 -0
  184. package/src/bmm-skills/ship/bmad-retrospective/references/acceptance-verdict.md +55 -0
  185. package/src/bmm-skills/ship/bmad-retrospective/references/aggregate-views.md +17 -0
  186. package/src/bmm-skills/ship/bmad-retrospective/references/evidence-gathering.md +30 -0
  187. package/src/bmm-skills/ship/bmad-retrospective/references/retro-document.md +84 -0
  188. package/src/bmm-skills/ship/bmad-retrospective/references/team-discussion.md +22 -0
  189. package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc +0 -0
  190. package/src/bmm-skills/ship/bmad-retrospective/scripts/git_evidence.py +304 -0
  191. package/src/bmm-skills/ship/bmad-retrospective/scripts/sprint_status.py +746 -0
  192. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-311-pytest-9.1.1.pyc +0 -0
  193. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-311-pytest-9.1.1.pyc +0 -0
  194. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/fixtures/sprint-status-template.yaml +71 -0
  195. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/test_git_evidence.py +750 -0
  196. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/test_sprint_status.py +1579 -0
  197. package/src/bmm-skills/v6-shims/README.md +28 -0
  198. package/src/bmm-skills/v6-shims/bmad-create-architecture/SKILL.md +30 -0
  199. package/src/bmm-skills/v6-shims/bmad-create-architecture/customize.toml +41 -0
  200. package/src/bmm-skills/v6-shims/bmad-create-prd/SKILL.md +30 -0
  201. package/src/bmm-skills/v6-shims/bmad-create-prd/customize.toml +41 -0
  202. package/src/bmm-skills/v6-shims/bmad-create-story/SKILL.md +434 -0
  203. package/src/bmm-skills/v6-shims/bmad-create-story/checklist.md +357 -0
  204. package/src/bmm-skills/v6-shims/bmad-create-story/customize.toml +41 -0
  205. package/src/bmm-skills/v6-shims/bmad-create-story/discover-inputs.md +88 -0
  206. package/src/bmm-skills/v6-shims/bmad-create-story/template.md +49 -0
  207. package/src/bmm-skills/v6-shims/bmad-dev-auto/SKILL.md +19 -0
  208. package/src/bmm-skills/v6-shims/bmad-dev-story/SKILL.md +502 -0
  209. package/src/bmm-skills/v6-shims/bmad-dev-story/checklist.md +80 -0
  210. package/src/bmm-skills/v6-shims/bmad-dev-story/customize.toml +44 -0
  211. package/src/bmm-skills/v6-shims/bmad-document-project/SKILL.md +14 -0
  212. package/src/bmm-skills/v6-shims/bmad-domain-research/SKILL.md +14 -0
  213. package/src/bmm-skills/v6-shims/bmad-edit-prd/SKILL.md +30 -0
  214. package/src/bmm-skills/v6-shims/bmad-edit-prd/customize.toml +42 -0
  215. package/src/bmm-skills/v6-shims/bmad-market-research/SKILL.md +14 -0
  216. package/src/bmm-skills/v6-shims/bmad-quick-dev/SKILL.md +19 -0
  217. package/src/bmm-skills/v6-shims/bmad-sprint-status/SKILL.md +26 -0
  218. package/src/bmm-skills/v6-shims/bmad-sprint-status/customize.toml +41 -0
  219. package/src/bmm-skills/v6-shims/bmad-technical-research/SKILL.md +14 -0
  220. package/src/bmm-skills/v6-shims/bmad-validate-prd/SKILL.md +30 -0
  221. package/src/bmm-skills/v6-shims/bmad-validate-prd/customize.toml +42 -0
  222. package/src/core-skills/bmad-advanced-elicitation/SKILL.md +65 -0
  223. package/src/core-skills/bmad-advanced-elicitation/assets/methods.csv +72 -0
  224. package/src/core-skills/bmad-advanced-elicitation/customize.toml +54 -0
  225. package/src/core-skills/bmad-advanced-elicitation/scripts/pick_methods.py +233 -0
  226. package/src/core-skills/bmad-advanced-elicitation/scripts/tests/test_pick_methods.py +228 -0
  227. package/src/core-skills/bmad-brainstorming/SKILL.md +80 -0
  228. package/src/core-skills/bmad-brainstorming/assets/brain-icons.json +166 -0
  229. package/src/core-skills/bmad-brainstorming/assets/brain-methods.csv +109 -0
  230. package/src/core-skills/bmad-brainstorming/assets/brain-selector.html +328 -0
  231. package/src/core-skills/bmad-brainstorming/customize.toml +84 -0
  232. package/src/core-skills/bmad-brainstorming/references/converge.md +24 -0
  233. package/src/core-skills/bmad-brainstorming/references/finalize.md +26 -0
  234. package/src/core-skills/bmad-brainstorming/references/headless.md +54 -0
  235. package/src/core-skills/bmad-brainstorming/references/in-chat-techniques.md +18 -0
  236. package/src/core-skills/bmad-brainstorming/references/mode-autonomous.md +10 -0
  237. package/src/core-skills/bmad-brainstorming/references/mode-facilitator.md +11 -0
  238. package/src/core-skills/bmad-brainstorming/references/mode-partner.md +16 -0
  239. package/src/core-skills/bmad-brainstorming/references/resume.md +5 -0
  240. package/src/core-skills/bmad-brainstorming/scripts/brain.py +770 -0
  241. package/src/core-skills/bmad-brainstorming/scripts/tests/test_brain.py +239 -0
  242. package/src/core-skills/bmad-customize/SKILL.md +111 -0
  243. package/src/core-skills/bmad-customize/scripts/list_customizable_skills.py +231 -0
  244. package/src/core-skills/bmad-customize/scripts/tests/test_list_customizable_skills.py +249 -0
  245. package/src/core-skills/bmad-deep-recon/SKILL.md +82 -0
  246. package/src/core-skills/bmad-deep-recon/assets/research.template.md +18 -0
  247. package/src/core-skills/bmad-deep-recon/customize.toml +212 -0
  248. package/src/core-skills/bmad-deep-recon/references/draft.md +8 -0
  249. package/src/core-skills/bmad-deep-recon/references/finalize.md +11 -0
  250. package/src/core-skills/bmad-deep-recon/references/html-briefing.md +16 -0
  251. package/src/core-skills/bmad-deep-recon/references/lifecycle.md +11 -0
  252. package/src/core-skills/bmad-deep-recon/references/process.md +10 -0
  253. package/src/core-skills/bmad-deep-recon/references/run.md +73 -0
  254. package/src/core-skills/bmad-deep-recon/references/selection.md +13 -0
  255. package/src/core-skills/bmad-deep-recon/references/synthesis.md +16 -0
  256. package/src/core-skills/bmad-deep-recon/references/verification.md +29 -0
  257. package/src/core-skills/bmad-deep-recon/scripts/recon_kit.py +322 -0
  258. package/src/core-skills/bmad-deep-recon/scripts/tests/test_recon_kit.py +144 -0
  259. package/src/core-skills/bmad-deep-recon/types/academic-lit.md +19 -0
  260. package/src/core-skills/bmad-deep-recon/types/competitive.md +19 -0
  261. package/src/core-skills/bmad-deep-recon/types/domain.md +19 -0
  262. package/src/core-skills/bmad-deep-recon/types/market.md +19 -0
  263. package/src/core-skills/bmad-deep-recon/types/technical.md +19 -0
  264. package/src/core-skills/bmad-deep-recon/types/user-voice.md +19 -0
  265. package/src/core-skills/bmad-forge-idea/SKILL.md +107 -0
  266. package/src/core-skills/bmad-forge-idea/customize.toml +42 -0
  267. package/src/core-skills/bmad-forge-idea/scripts/resolve_personas.py +275 -0
  268. package/src/core-skills/bmad-forge-idea/scripts/tests/test_resolve_personas.py +138 -0
  269. package/src/core-skills/bmad-help/SKILL.md +75 -0
  270. package/src/core-skills/bmad-party-mode/SKILL.md +60 -0
  271. package/src/core-skills/bmad-party-mode/customize.toml +211 -0
  272. package/src/core-skills/bmad-party-mode/references/create-party.md +70 -0
  273. package/src/core-skills/bmad-party-mode/references/mode-agent-team.md +13 -0
  274. package/src/core-skills/bmad-party-mode/references/mode-auto.md +13 -0
  275. package/src/core-skills/bmad-party-mode/references/mode-subagent.md +31 -0
  276. package/src/core-skills/bmad-party-mode/references/party-memory.md +51 -0
  277. package/src/core-skills/bmad-party-mode/scripts/resolve_party.py +282 -0
  278. package/src/core-skills/bmad-party-mode/scripts/tests/test_resolve_party.py +146 -0
  279. package/src/core-skills/bmad-review/SKILL.md +49 -0
  280. package/src/core-skills/bmad-review/customize.toml +141 -0
  281. package/src/core-skills/bmad-review/references/editorial-common.md +56 -0
  282. package/src/core-skills/bmad-review/references/lens-adversarial.md +19 -0
  283. package/src/core-skills/bmad-review/references/lens-edge-case-hunter.md +54 -0
  284. package/src/core-skills/bmad-review/references/lens-prose.md +7 -0
  285. package/src/core-skills/bmad-review/references/lens-structure.md +9 -0
  286. package/src/core-skills/bmad-review/references/lens-verification-gap.md +92 -0
  287. package/src/core-skills/bmad-review/references/structure-models.md +44 -0
  288. package/src/core-skills/bmad-review/scripts/tests/test_word_metrics.py +62 -0
  289. package/src/core-skills/bmad-review/scripts/word_metrics.py +102 -0
  290. package/src/core-skills/module-help.csv +10 -0
  291. package/src/core-skills/module.yaml +38 -0
  292. package/src/core-skills/v6-shims/README.md +25 -0
  293. package/src/core-skills/v6-shims/bmad-editorial-review/SKILL.md +6 -0
  294. package/src/core-skills/v6-shims/bmad-editorial-review/customize.toml +31 -0
  295. package/src/core-skills/v6-shims/bmad-editorial-review-prose/SKILL.md +6 -0
  296. package/src/core-skills/v6-shims/bmad-editorial-review-structure/SKILL.md +6 -0
  297. package/src/core-skills/v6-shims/bmad-review-adversarial-general/SKILL.md +6 -0
  298. package/src/core-skills/v6-shims/bmad-review-edge-case-hunter/SKILL.md +6 -0
  299. package/src/core-skills/v6-shims/bmad-review-verification-gap/SKILL.md +6 -0
  300. package/src/scripts/__pycache__/config_utils.cpython-311.pyc +0 -0
  301. package/src/scripts/config_utils.py +119 -0
  302. package/src/scripts/memlog.py +224 -0
  303. package/src/scripts/render_skill.py +401 -0
  304. package/src/scripts/resolve_config.py +74 -0
  305. package/src/scripts/resolve_customization.py +99 -0
  306. package/src/scripts/tests/__pycache__/test_config_utils.cpython-311.pyc +0 -0
  307. package/src/scripts/tests/__pycache__/test_resolve_config.cpython-311.pyc +0 -0
  308. package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-311.pyc +0 -0
  309. package/src/scripts/tests/test_config_utils.py +85 -0
  310. package/src/scripts/tests/test_memlog.py +306 -0
  311. package/src/scripts/tests/test_resolve_config.py +89 -0
  312. package/src/scripts/tests/test_resolve_customization.py +77 -0
  313. package/tools/bundle-web-bundles.js +117 -0
  314. package/tools/format-workflow-md.js +263 -0
  315. package/tools/installer/README.md +60 -0
  316. package/tools/installer/bmad-cli.js +105 -0
  317. package/tools/installer/cli-utils.js +57 -0
  318. package/tools/installer/commands/install.js +149 -0
  319. package/tools/installer/commands/status.js +65 -0
  320. package/tools/installer/commands/uninstall.js +167 -0
  321. package/tools/installer/core/config.js +73 -0
  322. package/tools/installer/core/existing-install.js +121 -0
  323. package/tools/installer/core/install-paths.js +132 -0
  324. package/tools/installer/core/installer.js +1767 -0
  325. package/tools/installer/core/legacy-warnings.js +151 -0
  326. package/tools/installer/core/manifest-generator.js +859 -0
  327. package/tools/installer/core/manifest.js +433 -0
  328. package/tools/installer/core/uv-check.js +195 -0
  329. package/tools/installer/core/wsl-node-check.js +109 -0
  330. package/tools/installer/file-ops.js +204 -0
  331. package/tools/installer/fs-native.js +116 -0
  332. package/tools/installer/ide/_config-driven.js +972 -0
  333. package/tools/installer/ide/manager.js +324 -0
  334. package/tools/installer/ide/platform-codes.js +80 -0
  335. package/tools/installer/ide/platform-codes.yaml +343 -0
  336. package/tools/installer/ide/shared/installed-skills.js +50 -0
  337. package/tools/installer/ide/shared/path-utils.js +219 -0
  338. package/tools/installer/ide/shared/skill-manifest.js +57 -0
  339. package/tools/installer/install-messages.yaml +37 -0
  340. package/tools/installer/list-options.js +210 -0
  341. package/tools/installer/message-loader.js +83 -0
  342. package/tools/installer/modules/channel-plan.js +203 -0
  343. package/tools/installer/modules/channel-resolver.js +241 -0
  344. package/tools/installer/modules/custom-module-manager.js +924 -0
  345. package/tools/installer/modules/external-manager.js +671 -0
  346. package/tools/installer/modules/git-env.js +47 -0
  347. package/tools/installer/modules/module-help-schema.js +13 -0
  348. package/tools/installer/modules/official-modules.js +2257 -0
  349. package/tools/installer/modules/plugin-resolver.js +398 -0
  350. package/tools/installer/modules/version-resolver.js +336 -0
  351. package/tools/installer/project-root.js +224 -0
  352. package/tools/installer/prompts.js +791 -0
  353. package/tools/installer/set-overrides.js +330 -0
  354. package/tools/installer/ui.js +2167 -0
  355. package/tools/installer/yaml-format.js +245 -0
  356. package/tools/javascript-conventions.md +5 -0
  357. package/tools/migrate-custom-module-paths.js +124 -0
  358. package/tools/skill-validator.md +378 -0
  359. package/tools/validate-published-implementation-model.mjs +68 -0
  360. package/tools/validate-sidebar-order.js +388 -0
  361. package/tools/validate-skills.js +735 -0
  362. package/tools/validate-svg-changes.sh +356 -0
  363. package/web-bundles/README.md +46 -0
  364. package/web-bundles/brainstorming-coach/INSTRUCTIONS.md +86 -0
  365. package/web-bundles/brainstorming-coach/SKILL.md +83 -0
  366. package/web-bundles/brainstorming-coach/brain-methods.csv +62 -0
  367. package/web-bundles/bundles.json +139 -0
  368. package/web-bundles/market-and-industry-research/INSTRUCTIONS.md +88 -0
  369. package/web-bundles/market-and-industry-research/SKILL.md +59 -0
  370. package/web-bundles/prd-coach/INSTRUCTIONS.md +86 -0
  371. package/web-bundles/prd-coach/SKILL.md +101 -0
  372. package/web-bundles/prd-coach/prd-template.md +165 -0
  373. package/web-bundles/prd-coach/prd-validation-checklist.md +135 -0
  374. package/web-bundles/prfaq-coach/INSTRUCTIONS.md +86 -0
  375. package/web-bundles/prfaq-coach/SKILL.md +139 -0
  376. package/web-bundles/product-brief-coach/INSTRUCTIONS.md +86 -0
  377. package/web-bundles/product-brief-coach/SKILL.md +113 -0
  378. package/web-bundles/ux-coach/INSTRUCTIONS.md +92 -0
  379. package/web-bundles/ux-coach/SKILL.md +187 -0
  380. package/web-bundles/ux-coach/ux-validation.md +100 -0
@@ -0,0 +1,282 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.11"
4
+ # ///
5
+ """Resolve the party-mode roster, lazily.
6
+
7
+ Merges the installed BMAD agents with the user's custom `party_members`
8
+ into one collective, then projects only what the moment needs:
9
+
10
+ * default (no flag) — the active roster to load on entry: the
11
+ `default_party` group if one is configured, else the whole collective.
12
+ Other groups come back as names only, so nothing you aren't using is
13
+ loaded into the party.
14
+ * --list-groups — just id + name + size for every configured group. The
15
+ cheap menu for "which room?", with no member detail.
16
+ * --party <id> — full member detail for one chosen group, on demand
17
+ (e.g. when the user switches rooms). Unknown id returns the available
18
+ names instead of an error wall.
19
+
20
+ The merge is deterministic (a keyed union; a custom member whose code
21
+ matches an installed agent overrides it), so the orchestrator consumes a
22
+ resolved roster instead of re-deriving it every session.
23
+
24
+ Stdlib only (Python 3.11+ for tomllib). Shells out to the project's
25
+ resolve_config.py and resolve_customization.py; falls back to reading
26
+ customize.toml directly if the customization resolver is unavailable.
27
+
28
+ resolve_party.py --project-root P --skill S
29
+ resolve_party.py --project-root P --skill S --list-groups
30
+ resolve_party.py --project-root P --skill S --party writers-room
31
+ """
32
+
33
+ import argparse
34
+ import json
35
+ import subprocess
36
+ import sys
37
+ from pathlib import Path
38
+
39
+ try:
40
+ import tomllib
41
+ except ImportError: # pragma: no cover - guarded for <3.11
42
+ sys.stderr.write("error: Python 3.11+ is required (stdlib `tomllib`).\n")
43
+ sys.exit(3)
44
+
45
+
46
+ def _run_json(cmd):
47
+ """Run a resolver script and parse its JSON stdout. None on any failure."""
48
+ try:
49
+ out = subprocess.run(
50
+ cmd, capture_output=True, text=True, encoding="utf-8", timeout=60
51
+ )
52
+ except (OSError, subprocess.SubprocessError):
53
+ return None
54
+ if out.returncode != 0 or not out.stdout.strip():
55
+ return None
56
+ try:
57
+ return json.loads(out.stdout)
58
+ except json.JSONDecodeError:
59
+ return None
60
+
61
+
62
+ def load_agents(project_root: Path):
63
+ """Installed agents as {code: entry}. Empty dict (with a flag) on failure."""
64
+ script = project_root / "_bmad" / "scripts" / "resolve_config.py"
65
+ data = _run_json([sys.executable, str(script), "--project-root", str(project_root), "--key", "agents"])
66
+ if data is None:
67
+ return {}, False
68
+ return data.get("agents", {}) or {}, True
69
+
70
+
71
+ def load_workflow(project_root: Path, skill_root: Path):
72
+ """Merged [workflow] table. Falls back to the skill's base customize.toml."""
73
+ script = project_root / "_bmad" / "scripts" / "resolve_customization.py"
74
+ data = _run_json([sys.executable, str(script), "--skill", str(skill_root), "--key", "workflow"])
75
+ if data is not None and "workflow" in data:
76
+ return data["workflow"]
77
+ # Fallback: read the skill's base customize.toml directly (no override merge).
78
+ toml_path = skill_root / "customize.toml"
79
+ if toml_path.exists():
80
+ try:
81
+ with toml_path.open("rb") as f:
82
+ return tomllib.load(f).get("workflow", {})
83
+ except (OSError, tomllib.TOMLDecodeError):
84
+ pass
85
+ return {}
86
+
87
+
88
+ def _alias(code: str) -> str:
89
+ """Short alias for an installed agent code: bmad-agent-analyst -> analyst."""
90
+ for prefix in ("bmad-agent-", "bmad-"):
91
+ if code.startswith(prefix):
92
+ return code[len(prefix):]
93
+ return code
94
+
95
+
96
+ def build_collective(agents: dict, party_members: list):
97
+ """One pool keyed by code. Custom members override matching installed agents.
98
+
99
+ Returns (collective, index, installed_codes):
100
+ * collective — every member (installed + custom), the pool groups draw
101
+ from and the orchestrator can summon by name.
102
+ * index — maps every resolvable token (code, prefix-stripped alias,
103
+ lower-cased name) to a canonical code.
104
+ * installed_codes — the codes occupying an installed-agent slot, in
105
+ order. This is the DEFAULT room: installed agents (with any custom
106
+ override applied in place), and NOT the pure-custom additions. So
107
+ shipping or defining custom members grows the pool without crowding
108
+ the default party.
109
+ """
110
+ collective = {}
111
+ index = {}
112
+ installed_codes = []
113
+
114
+ def register(code, entry):
115
+ collective[code] = entry
116
+ index[code] = code
117
+ index[code.lower()] = code
118
+ index[_alias(code).lower()] = code
119
+ name = entry.get("name")
120
+ if name:
121
+ index[name.lower()] = code
122
+
123
+ for code, info in agents.items():
124
+ register(code, {
125
+ "code": code,
126
+ "name": info.get("name", code),
127
+ "icon": info.get("icon", ""),
128
+ "title": info.get("title", ""),
129
+ "description": info.get("description", ""),
130
+ "module": info.get("module", ""),
131
+ "team": info.get("team", ""),
132
+ "source": "installed",
133
+ })
134
+ installed_codes.append(code)
135
+
136
+ for m in (party_members if isinstance(party_members, list) else []):
137
+ if not isinstance(m, dict):
138
+ continue
139
+ code = m.get("code")
140
+ if not code:
141
+ continue
142
+ # A custom member overrides an installed agent it matches by code/alias/name.
143
+ canonical = index.get(code) or index.get(code.lower()) or code
144
+ # Start from the installed entry so fields the override omits
145
+ # (icon, title, description, module, team) survive.
146
+ entry = dict(collective.get(canonical, {}))
147
+ entry.update({"code": canonical, "source": "custom"})
148
+ for field in ("name", "icon", "title", "persona", "capabilities", "model"):
149
+ if m.get(field) is not None:
150
+ entry[field] = m[field]
151
+ entry.setdefault("name", canonical)
152
+ register(canonical, entry)
153
+ # An override keeps the installed slot; a brand-new custom does not join it.
154
+
155
+ return collective, index, installed_codes
156
+
157
+
158
+ def resolve_members(member_tokens, collective, index):
159
+ """(resolved entries in listed order, unresolved tokens)."""
160
+ resolved, unresolved = [], []
161
+ for token in member_tokens or []:
162
+ if not isinstance(token, str):
163
+ unresolved.append(token) # malformed config value — never a key lookup
164
+ continue
165
+ code = index.get(token) or index.get(token.lower())
166
+ if code and code in collective:
167
+ resolved.append(collective[code])
168
+ else:
169
+ unresolved.append(token)
170
+ return resolved, unresolved
171
+
172
+
173
+ def group_menu(groups):
174
+ """Names only — the cheap menu. Open-cast groups (no roster) are flagged."""
175
+ out = []
176
+ for g in groups or []:
177
+ if not isinstance(g, dict) or not g.get("id"):
178
+ continue
179
+ members = g.get("members", []) or []
180
+ entry = {"id": g["id"], "name": g.get("name", g["id"]),
181
+ "member_count": len(members)}
182
+ if not members:
183
+ entry["open_cast"] = True
184
+ out.append(entry)
185
+ return out
186
+
187
+
188
+ def find_group(groups, group_id):
189
+ for g in groups or []:
190
+ if isinstance(g, dict) and g.get("id") == group_id:
191
+ return g
192
+ return None
193
+
194
+
195
+ def group_detail(g, collective, index):
196
+ """Full detail for one group: resolved members + the optional scene.
197
+
198
+ `scene` is a freeform line the orchestrator plays — setting, what's
199
+ happening, room dynamics, in-the-moment character notes. Surfaced only
200
+ here (when a group is the active/chosen roster), never in the menu.
201
+
202
+ `members` is optional. With none, the group is open-cast: `open_cast`
203
+ is flagged and the scene describes the pool the orchestrator casts from
204
+ on the fly (e.g. "figures from the Star Wars Rebels universe"). A few
205
+ listed members anchor the room; the scene can still invite more.
206
+ """
207
+ raw_members = g.get("members", []) or []
208
+ members, unresolved = resolve_members(raw_members, collective, index)
209
+ detail = {"active": g["id"], "name": g.get("name", g["id"]),
210
+ "members": members, "unresolved": unresolved,
211
+ "memory_enabled": bool(g.get("memory", False))}
212
+ if g.get("scene"):
213
+ detail["scene"] = g["scene"]
214
+ if not raw_members:
215
+ detail["open_cast"] = True
216
+ return detail
217
+
218
+
219
+ def main():
220
+ ap = argparse.ArgumentParser(description="Resolve the party-mode roster, lazily.")
221
+ ap.add_argument("--project-root", required=True)
222
+ ap.add_argument("--skill", required=True, help="Path to the bmad-party-mode skill dir")
223
+ ap.add_argument("--party", help="Resolve full detail for this group id")
224
+ ap.add_argument("--list-groups", action="store_true", help="Group names only")
225
+ args = ap.parse_args()
226
+
227
+ project_root = Path(args.project_root).resolve()
228
+ skill_root = Path(args.skill).resolve()
229
+
230
+ workflow = load_workflow(project_root, skill_root)
231
+ groups = workflow.get("party_groups", []) or []
232
+ default_party = workflow.get("default_party", "") or ""
233
+ party_mode = workflow.get("party_mode", "session") or "session"
234
+ # The global party_memory flag governs only the DEFAULT installed-agent room;
235
+ # a named group carries its own `memory` flag (resolved in group_detail).
236
+ party_memory = bool(workflow.get("party_memory", True))
237
+
238
+ # Group menu never needs the (more expensive) installed-agent resolve.
239
+ if args.list_groups:
240
+ _emit({
241
+ "party_mode": party_mode,
242
+ "default_party": default_party,
243
+ "groups": group_menu(groups),
244
+ })
245
+ return
246
+
247
+ agents, agents_ok = load_agents(project_root)
248
+ collective, index, installed_codes = build_collective(agents, workflow.get("party_members", []))
249
+
250
+ if args.party:
251
+ g = find_group(groups, args.party)
252
+ if g is None:
253
+ _emit({"error": "unknown_group", "requested": args.party,
254
+ "available": group_menu(groups)})
255
+ return
256
+ _emit({**group_detail(g, collective, index), "party_mode": party_mode})
257
+ return
258
+
259
+ # Default: the active roster to load on entry.
260
+ result = {"party_mode": party_mode, "groups": group_menu(groups),
261
+ "installed_agents_resolved": agents_ok}
262
+ g = find_group(groups, default_party) if default_party else None
263
+ if g is not None:
264
+ result.update(group_detail(g, collective, index))
265
+ else:
266
+ # No default group: the installed agents (custom additions stay in the
267
+ # pool but don't crowd the default room), exactly like a plain install.
268
+ result.update({"active": "installed",
269
+ "members": [collective[c] for c in installed_codes],
270
+ "memory_enabled": party_memory})
271
+ _emit(result)
272
+
273
+
274
+ def _emit(obj):
275
+ reconfigure = getattr(sys.stdout, "reconfigure", None)
276
+ if reconfigure is not None:
277
+ reconfigure(encoding="utf-8")
278
+ sys.stdout.write(json.dumps(obj, indent=2, ensure_ascii=False) + "\n")
279
+
280
+
281
+ if __name__ == "__main__":
282
+ main()
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.11"
4
+ # ///
5
+ """Unit tests for resolve_party.py — merge, alias, override, group resolution."""
6
+
7
+ import sys
8
+ import unittest
9
+ from pathlib import Path
10
+
11
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
12
+ import resolve_party as rp # noqa: E402
13
+
14
+ AGENTS = {
15
+ "bmad-agent-analyst": {"name": "Mary", "icon": "📊", "title": "Analyst"},
16
+ "bmad-agent-pm": {"name": "John", "icon": "📋", "title": "PM"},
17
+ }
18
+
19
+
20
+ class TestAlias(unittest.TestCase):
21
+ def test_strips_known_prefixes(self):
22
+ self.assertEqual(rp._alias("bmad-agent-analyst"), "analyst")
23
+ self.assertEqual(rp._alias("bmad-foo"), "foo")
24
+
25
+ def test_passes_through_unprefixed(self):
26
+ self.assertEqual(rp._alias("morpheus"), "morpheus")
27
+
28
+
29
+ class TestBuildCollective(unittest.TestCase):
30
+ def test_installed_agents_indexed_by_code_alias_and_name(self):
31
+ col, idx, _ = rp.build_collective(AGENTS, [])
32
+ self.assertEqual(set(col), {"bmad-agent-analyst", "bmad-agent-pm"})
33
+ self.assertEqual(idx["analyst"], "bmad-agent-analyst") # alias
34
+ self.assertEqual(idx["mary"], "bmad-agent-analyst") # name (ci)
35
+ self.assertEqual(idx["bmad-agent-pm"], "bmad-agent-pm") # full code
36
+ self.assertEqual(col["bmad-agent-analyst"]["source"], "installed")
37
+
38
+ def test_custom_member_appends(self):
39
+ col, _, _ = rp.build_collective(AGENTS, [{"code": "morpheus", "name": "Morpheus", "persona": "riddles"}])
40
+ self.assertIn("morpheus", col)
41
+ self.assertEqual(col["morpheus"]["source"], "custom")
42
+ self.assertEqual(col["morpheus"]["persona"], "riddles")
43
+
44
+ def test_custom_overrides_installed_by_alias(self):
45
+ col, _, _ = rp.build_collective(AGENTS, [{"code": "analyst", "name": "Mary-Custom", "persona": "p"}])
46
+ # Override lands on the canonical installed code, not a new "analyst" entry.
47
+ self.assertNotIn("analyst", col)
48
+ self.assertEqual(col["bmad-agent-analyst"]["source"], "custom")
49
+ self.assertEqual(col["bmad-agent-analyst"]["name"], "Mary-Custom")
50
+
51
+ def test_member_without_code_skipped(self):
52
+ col, _, _ = rp.build_collective(AGENTS, [{"name": "Nameless"}])
53
+ self.assertEqual(set(col), {"bmad-agent-analyst", "bmad-agent-pm"})
54
+
55
+
56
+ class TestResolveMembers(unittest.TestCase):
57
+ def setUp(self):
58
+ self.col, self.idx, _ = rp.build_collective(AGENTS, [{"code": "morpheus", "name": "Morpheus"}])
59
+
60
+ def test_resolves_in_listed_order_and_flags_unknowns(self):
61
+ resolved, unresolved = rp.resolve_members(["morpheus", "analyst", "ghost"], self.col, self.idx)
62
+ self.assertEqual([m["code"] for m in resolved], ["morpheus", "bmad-agent-analyst"])
63
+ self.assertEqual(unresolved, ["ghost"])
64
+
65
+ def test_empty(self):
66
+ self.assertEqual(rp.resolve_members([], self.col, self.idx), ([], []))
67
+
68
+
69
+ class TestGroups(unittest.TestCase):
70
+ GROUPS = [
71
+ {"id": "wr", "name": "Writers", "members": ["analyst", "morpheus"]},
72
+ {"id": "bad"}, # no name -> falls back to id; no members -> count 0
73
+ {"name": "no-id"}, # dropped from menu
74
+ ]
75
+
76
+ def test_menu_is_names_only_with_counts_and_open_cast_flag(self):
77
+ menu = rp.group_menu(self.GROUPS)
78
+ self.assertEqual(menu, [
79
+ {"id": "wr", "name": "Writers", "member_count": 2},
80
+ {"id": "bad", "name": "bad", "member_count": 0, "open_cast": True},
81
+ ])
82
+
83
+ def test_find_group(self):
84
+ self.assertEqual(rp.find_group(self.GROUPS, "wr")["name"], "Writers")
85
+ self.assertIsNone(rp.find_group(self.GROUPS, "missing"))
86
+
87
+
88
+ class TestGroupDetail(unittest.TestCase):
89
+ def setUp(self):
90
+ self.col, self.idx, _ = rp.build_collective(AGENTS, [{"code": "morpheus", "name": "Morpheus"}])
91
+
92
+ def test_scene_passes_through_when_present(self):
93
+ g = {"id": "tos-10-forward", "name": "Ten Forward", "members": ["morpheus"],
94
+ "scene": "Late evening, a few rounds in."}
95
+ d = rp.group_detail(g, self.col, self.idx)
96
+ self.assertEqual(d["scene"], "Late evening, a few rounds in.")
97
+ self.assertEqual([m["code"] for m in d["members"]], ["morpheus"])
98
+
99
+ def test_scene_omitted_when_absent_or_empty(self):
100
+ for g in ({"id": "g", "members": ["morpheus"]},
101
+ {"id": "g", "members": ["morpheus"], "scene": ""}):
102
+ self.assertNotIn("scene", rp.group_detail(g, self.col, self.idx))
103
+
104
+ def test_anchored_group_is_not_open_cast(self):
105
+ g = {"id": "g", "members": ["morpheus"]}
106
+ self.assertNotIn("open_cast", rp.group_detail(g, self.col, self.idx))
107
+
108
+ def test_open_cast_group_flagged_with_empty_members(self):
109
+ g = {"id": "rebels", "name": "Star Wars Rebels",
110
+ "scene": "Figures from the Rebels universe drop in as the topic calls for them."}
111
+ d = rp.group_detail(g, self.col, self.idx)
112
+ self.assertTrue(d["open_cast"])
113
+ self.assertEqual(d["members"], [])
114
+ self.assertEqual(d["scene"][:7], "Figures")
115
+
116
+ def test_memory_enabled_follows_group_flag_and_defaults_off(self):
117
+ on = rp.group_detail({"id": "g", "members": ["morpheus"], "memory": True}, self.col, self.idx)
118
+ self.assertTrue(on["memory_enabled"])
119
+ off = rp.group_detail({"id": "g", "members": ["morpheus"], "memory": False}, self.col, self.idx)
120
+ self.assertFalse(off["memory_enabled"])
121
+ absent = rp.group_detail({"id": "g", "members": ["morpheus"]}, self.col, self.idx)
122
+ self.assertFalse(absent["memory_enabled"]) # opt-in per named group
123
+
124
+
125
+ class TestInstalledCodesIsDefaultRoom(unittest.TestCase):
126
+ """The default room is installed agents only; pure customs stay in the pool."""
127
+
128
+ def test_pure_custom_excluded_override_kept_in_default_room(self):
129
+ col, _, installed = rp.build_collective(AGENTS, [
130
+ {"code": "morpheus", "name": "Morpheus"}, # pure custom
131
+ {"code": "analyst", "name": "Mary-Custom", "persona": "p"}, # override
132
+ {"code": "sec-hawk", "name": "Vex"}, # shipped crew member
133
+ ])
134
+ # Pure customs are in the pool...
135
+ self.assertIn("morpheus", col)
136
+ self.assertIn("sec-hawk", col)
137
+ # ...but NOT in the default room.
138
+ self.assertEqual(installed, ["bmad-agent-analyst", "bmad-agent-pm"])
139
+ default_room = [col[c]["code"] for c in installed]
140
+ self.assertEqual(default_room, ["bmad-agent-analyst", "bmad-agent-pm"])
141
+ # An override keeps its installed slot (and its custom content).
142
+ self.assertEqual(col["bmad-agent-analyst"]["name"], "Mary-Custom")
143
+
144
+
145
+ if __name__ == "__main__":
146
+ unittest.main()
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: bmad-review
3
+ description: 'Multi-lens review over any diff, doc, spec, or artifact — whichever installed lenses fit the content, run singly or together. Shipped lenses include adversarial, edge-case, verification-gap, structure, and prose. Use when the user says "review this", "critical review", "editorial review", "hunt edge cases", "review the structure", or "review the prose".'
4
+ ---
5
+
6
+ # BMad Review
7
+
8
+ Review content through lenses — each a distinct method and stance — and report findings in one canonical shape. Report what is real — never pad to look thorough. Each lens sets its own stance toward the content and toward zero findings: for most an empty result is valid; the adversarial lens requires at least ten concrete findings and treats an empty list as a signal to re-check; the editorial lenses hold content sacrosanct and critique only how it is organized and expressed.
9
+
10
+ The lens set is whatever `{workflow.lenses}` resolves to, not a fixed list — overrides add lenses and replace shipped ones. Never claim a capability from this file; read the resolved lenses and work from those.
11
+
12
+ ## Inputs
13
+
14
+ - **content** — what to review: a diff, branch, uncommitted changes, file, spec, story, or any document. Args: `[path]`.
15
+ - **lenses** (optional) — one or more lens codes or names, however the caller expresses them: a spoken request, or a directive of the form `skill:bmad-review lenses=<code>[,<code>...]` (the form bmm's `doc_standards` uses). Default: every applicable lens (a full review).
16
+ - **also_consider** (optional) — areas to keep in mind alongside each lens's normal analysis.
17
+ - **pre-resolved customization** (optional) — `[workflow]` field values supplied by a forwarding caller. See Execution step 1.
18
+
19
+ ## Conventions
20
+
21
+ - Bare paths (e.g. `references/lens-edge-case-hunter.md`) resolve from `{skill-root}` — this skill's installed directory, where `customize.toml` lives. `{project-root}` resolves to the project working directory.
22
+ - `{workflow.<name>}` resolves to fields in `customize.toml`'s `[workflow]` table (overrides win per BMad merge rules).
23
+ - In `style_guide`, `review_guidance`, and `persistent_facts`, a value prefixed `file:` is a path or glob — load that file's contents. If a `file:` value cannot be read, name the failed file in the output header and continue: the shipped baseline for `style_guide`, the remaining entries otherwise.
24
+
25
+ ## Execution
26
+
27
+ 1. **Resolve customization:** `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults. **Forwarded activation:** if a caller invoked you with pre-resolved customization fields (e.g. the `bmad-editorial-review` shim), honor them verbatim for those named fields — they already carry the user's overrides — and resolve only the remaining fields from your own `customize.toml`. Then execute each `{workflow.activation_steps_prepend}` entry in order, hold `{workflow.persistent_facts}` as standing context for the session, and treat `{workflow.review_guidance}` entries as standing review directives for every lens.
28
+ 2. **Load the content.** If it is empty or cannot be decoded as text: when the caller expects the raw findings JSON array (e.g. the legacy edge-case forwarder), return `[{"location":"N/A","trigger_condition":"Input empty or undecodable","guard_snippet":"Provide valid content to review","potential_consequence":"Review skipped — no analysis performed"}]` (no `lens` field) and stop; otherwise say what's wrong and ask for reviewable content. Classify the content — diff, source file, function, or document — and whether it is **code** or **docs**; scope rules and lens applicability both depend on it. A document that defines behavior (spec, requirements, plan, story) is `docs` that a behavioral lens may still apply to; judge by `when`.
29
+ 3. **Select lenses** from `{workflow.lenses}`. A lens with an empty `instruction` is disabled. If the user or caller named lenses, run exactly those only — `applies_to` and `when` do not filter an explicit request. Otherwise run every enabled lens whose `applies_to` covers the content class (`any` always covers) and whose `when` applies.
30
+ 4. **Announce the plan** in one line before running anything: the content class, the lenses about to run, and — when any lens has `after` set — that it runs on top of the named lens's findings. Skip the announcement entirely when the caller pinned an exact output contract (the legacy forwarders that demand raw JSON or one exact line) — their contract covers everything you emit, not just the findings block. Then execute each `{workflow.activation_steps_append}` entry in order.
31
+ 5. **Run the independent lenses** — every selected lens without `after`. Each sees the content and `also_consider`, never another lens's findings. Follow each lens's `instruction`; the shipped lenses load their reference file just-in-time, so load only what runs. When subagents are available, spawn one per lens in parallel: give it the lens `instruction` with `{skill-root}` and paths resolved absolute, the content or where to read it, any `also_consider` areas, the standing review directives, and the constraint "Return ONLY your findings — no other output." Otherwise run the lenses sequentially yourself, completing one before starting the next.
32
+ 6. **Run the dependent lenses** — every selected lens with `after`, once the lens it names has completed, passing that lens's findings in. A lens whose `after` target was not selected or produced nothing still runs, with no prior findings. Dependent lenses that name different targets are independent of each other and may run in parallel.
33
+ 7. **Assemble and present** per Output below. Keep every lens's findings — overlap between lenses is signal, not duplication; note it in the markdown report rather than deduping. Execute `{workflow.on_complete}` if set.
34
+
35
+ ## Output
36
+
37
+ One JSON array holding every finding from every lens. Each finding carries:
38
+
39
+ - `lens` — the code of the lens that produced it
40
+ - `location` — where in the content (file:line-range for code, section for documents)
41
+ - `trigger_condition` — the problem, or the condition that exposes it, in one line
42
+ - `guard_snippet` — the concrete fix, guard, or missing check
43
+ - `potential_consequence` — what goes wrong if it ships as-is
44
+
45
+ Each lens file refines these semantics for its findings and may add lens-specific fields (e.g. `kind`/`confidence` on deletion findings, `gap_shape`/`consumer`/`evidence` on verification-gap findings). A lens file may instead declare its own findings shape and rendering — the editorial lenses render a findings table — and that shape wins for that lens's findings. `[]` is valid when nothing is found. No severity, priority, or ranking anywhere.
46
+
47
+ Present per `{workflow.output_format}` — `"json"` (the raw array in a fenced json block), `"markdown"`, or `"both"` — unless the caller requested a specific shape; a legacy forwarder's output contract always wins, and governs everything you emit rather than the findings block alone. The markdown report groups findings by lens, each rendered in its declared shape: a short block per finding rendering the fields plus any extras worth surfacing, one line for a lens that found nothing, and a plain clean statement when the whole review is clean. Shape the report per `{workflow.output_preferences}`.
48
+
49
+ When `{workflow.report_path}` is set, write the report there; otherwise present it in chat.
@@ -0,0 +1,141 @@
1
+ # DO NOT EDIT -- overwritten on every update.
2
+ #
3
+ # Workflow customization surface for bmad-review.
4
+ #
5
+ # Override files (not edited here):
6
+ # {project-root}/_bmad/custom/bmad-review.toml (team)
7
+ # {project-root}/_bmad/custom/bmad-review.user.toml (personal)
8
+
9
+ [workflow]
10
+
11
+ # --- Configurable below. Overrides merge per BMad structural rules: ---
12
+ # scalars: override wins
13
+ # arrays (persistent_facts, activation_steps_*, review_guidance): append
14
+ # arrays of tables keyed by `code`: matching key replaces, new keys append
15
+
16
+ # Steps executed on activation: prepend runs before the skill's own
17
+ # activation flow, append runs after the lens plan is settled and before the
18
+ # lenses run. Each entry is a literal instruction.
19
+ activation_steps_prepend = []
20
+ activation_steps_append = []
21
+
22
+ # Standing context held for every review, code and document alike. Entries
23
+ # prefixed `file:` are paths or globs whose contents load as facts; all others
24
+ # are literal facts. The shipped entry is a project-wide glob — set it to []
25
+ # if you don't want every review scanning for it.
26
+ persistent_facts = ["file:{project-root}/**/project-context.md"]
27
+
28
+ # Standing review directives applied on every run alongside each lens's own
29
+ # method. Each entry is a literal sentence or a `file:`-prefixed path/glob
30
+ # whose contents load as directives.
31
+ #
32
+ # Examples:
33
+ # "Flag passive voice in headings."
34
+ # "Second-person imperative is the house voice; never suggest changing it."
35
+ # "file:{project-root}/docs/terminology.md"
36
+ review_guidance = []
37
+
38
+ # Executed after the findings are delivered. Freeform directive; empty = the
39
+ # review ends with the findings.
40
+ #
41
+ # Example:
42
+ # on_complete = "Append a one-line review summary to {project-root}/docs/review-log.md"
43
+ on_complete = ""
44
+
45
+ # How findings are presented when the caller doesn't say: "json" (the raw
46
+ # findings array only), "markdown" (the human report only), or "both". A lens
47
+ # that declares its own rendering keeps it for its own findings.
48
+ output_format = "both"
49
+
50
+ # Where to write the review report. Empty = present in chat only. Accepts
51
+ # {project-root}-prefixed paths.
52
+ report_path = ""
53
+
54
+ # How findings are presented — shaping, not destination. Freeform directive;
55
+ # empty = each lens's default ordering and rollup.
56
+ #
57
+ # Example:
58
+ # output_preferences = "Cap output at the 20 highest-impact findings."
59
+ output_preferences = ""
60
+
61
+ # --- Editorial lens settings (used by the structure and prose lenses) ---
62
+
63
+ # Default reader the editorial lenses calibrate for when the request doesn't
64
+ # say:
65
+ # "humans" clarity, flow, comprehension aids preserved
66
+ # "llm" precision, consistent terminology, no hedging
67
+ # A reader type stated in the request wins for that run.
68
+ reader_type = "humans"
69
+
70
+ # The baseline style guide for every editorial review: the name of a guide the
71
+ # model knows well, a `file:`-prefixed path to a style guide document, or the
72
+ # rules inline as text. A style guide stated in the request wins for that run.
73
+ # Where the guide in effect conflicts with the lens's generic principles, the
74
+ # guide wins — except content is sacrosanct.
75
+ #
76
+ # Examples (set in team/user override TOML):
77
+ # style_guide = "file:{project-root}/_bmad/style-guides/company-voice.md"
78
+ # style_guide = "Sentence-case headings. No Oxford comma. Address the reader as 'you'."
79
+ style_guide = "Microsoft Writing Style Guide"
80
+
81
+ # ---------------------------------------------------------------------------
82
+ # Review lenses. Each lens is a pass over the content with its own method and
83
+ # stance. `instruction` is the lens's whole execution recipe — the shipped
84
+ # lenses load a reference file from the skill root, but an override may inline
85
+ # any prompt.
86
+ #
87
+ # `applies_to` is the content this lens can review: "code", "docs", or "any".
88
+ # It is the first filter — a lens never joins a default review for content it
89
+ # does not apply to. `when` (optional) refines that judgement in prose. An
90
+ # explicitly requested lens always runs, whatever both say.
91
+ #
92
+ # `after` (optional) names a lens this one builds on: it runs once that lens
93
+ # has completed and receives its findings, instead of running independently.
94
+ #
95
+ # Empty `instruction` disables a lens. Keyed by `code`: an override with a
96
+ # matching code replaces the shipped lens, a new code appends.
97
+ #
98
+ # Example (add an org-specific lens in team/user override TOML):
99
+ # [[workflow.lenses]]
100
+ # code = "accessibility"
101
+ # name = "Accessibility"
102
+ # applies_to = "any"
103
+ # when = "UI code or user-facing documents."
104
+ # instruction = "Review against WCAG 2.2 AA. Emit findings in the canonical fields."
105
+ # ---------------------------------------------------------------------------
106
+
107
+ [[workflow.lenses]]
108
+ code = "adversarial"
109
+ name = "Adversarial"
110
+ applies_to = "any"
111
+ when = "always"
112
+ instruction = "Load `references/lens-adversarial.md` from the skill root and follow it."
113
+
114
+ [[workflow.lenses]]
115
+ code = "edge-case-hunter"
116
+ name = "Edge-Case Hunter"
117
+ applies_to = "any"
118
+ when = "Content with behavior to trace: code, diffs, and the specs, requirements, plans, and stories that define behavior. Skip for prose documents with no behavioral surface."
119
+ instruction = "Load `references/lens-edge-case-hunter.md` from the skill root and follow it."
120
+
121
+ [[workflow.lenses]]
122
+ code = "verification-gap"
123
+ name = "Verification Gap"
124
+ applies_to = "code"
125
+ when = "Reviewed inside a repo where tests can be searched and read."
126
+ instruction = "Load `references/lens-verification-gap.md` from the skill root and follow it."
127
+
128
+ [[workflow.lenses]]
129
+ code = "structure"
130
+ name = "Editorial Structure"
131
+ applies_to = "docs"
132
+ when = "Documents whose shape is the author's to change."
133
+ instruction = "Load `references/lens-structure.md` from the skill root and follow it."
134
+
135
+ [[workflow.lenses]]
136
+ code = "prose"
137
+ name = "Editorial Prose"
138
+ applies_to = "docs"
139
+ after = "structure"
140
+ when = "Documents being copy-edited."
141
+ instruction = "Load `references/lens-prose.md` from the skill root and follow it."