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,233 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.10"
4
+ # ///
5
+ """Serve the elicitation method catalog without loading it all into context.
6
+
7
+ The catalog is a CSV (num, category, method_name, description, output_pattern).
8
+ `description` is a one-line gist — enough to run the method; `output_pattern` is
9
+ a flexible flow guide (e.g. "assumptions → truths → new approach").
10
+
11
+ Commands:
12
+ categories list category names + counts (the cheap entry point)
13
+ list --category C [...] the index (num/category/name/gist) for those categories
14
+ list --all the whole catalog at once — deliberate; large, avoid interactively
15
+ show NAME_OR_NUM [...] full row for each method, matched by name or num
16
+ random [-n N] [--category C ...] [--exclude NAME ...] [--spread]
17
+ draw N at random; --spread forces category diversity
18
+ (at most one per category until categories run out) —
19
+ the reshuffle draw; --exclude skips already-shown methods
20
+
21
+ `list` refuses to run with neither --category nor --all: dumping the full catalog
22
+ into context must always be an explicit, deliberate choice.
23
+
24
+ `--extra SPEC` merges additional methods (customize.toml's `additional_methods`)
25
+ into every command. SPEC is either a JSON array literal (starts with `[`) or a
26
+ path to a JSON file; each item is {code, category, method_name, description,
27
+ output_pattern}. An extra whose method_name matches a catalog row
28
+ (case-insensitive) REPLACES it and keeps that row's num — retune a shipped
29
+ method; others append and get the next free nums, so new methods and whole new
30
+ categories are first-class and number-addressable everywhere.
31
+
32
+ Default output is lean tab-separated text for an LLM to read; --json for structured.
33
+ """
34
+ import argparse
35
+ import csv
36
+ import json
37
+ import random
38
+ import sys
39
+ from pathlib import Path
40
+
41
+ DEFAULT_FILE = Path(__file__).resolve().parent.parent / "assets" / "methods.csv"
42
+ FIELDS = ("num", "category", "method_name", "description", "output_pattern")
43
+
44
+
45
+ def load(file: Path) -> list[dict]:
46
+ # utf-8-sig: tolerate BOM-prefixed catalogs (Excel "CSV UTF-8", Notepad)
47
+ with open(file, newline="", encoding="utf-8-sig") as f:
48
+ rows = list(csv.DictReader(f))
49
+ for r in rows:
50
+ for k in FIELDS:
51
+ r.setdefault(k, "")
52
+ r[k] = (r.get(k) or "").strip()
53
+ return rows
54
+
55
+
56
+ def load_extra(spec: str) -> list[dict]:
57
+ """Parse the --extra overlay: a JSON array literal or a path to a JSON file."""
58
+ text = spec if spec.lstrip().startswith("[") else Path(spec).read_text(encoding="utf-8-sig")
59
+ data = json.loads(text)
60
+ if not isinstance(data, list):
61
+ raise ValueError("--extra must be a JSON array of objects")
62
+ rows = []
63
+ for item in data:
64
+ if not isinstance(item, dict):
65
+ raise ValueError(f"each --extra entry must be a JSON object, got: {item!r}")
66
+ row = {k: str(item.get(k) or "").strip() for k in FIELDS}
67
+ row["code"] = str(item.get("code") or "").strip() # kept for traceability
68
+ rows.append(row)
69
+ return rows
70
+
71
+
72
+ def merge_extra(rows: list[dict], extras: list[dict]) -> list[dict]:
73
+ """Extras replace a catalog row with the same method_name (case-insensitive),
74
+ otherwise append — so overrides can retune shipped methods or grow the catalog.
75
+ A replacement inherits the shipped row's num; appended extras get the next
76
+ free nums, so every merged method stays addressable by number."""
77
+ merged = list(rows)
78
+ index = {r["method_name"].lower(): i for i, r in enumerate(merged)}
79
+ for e in extras:
80
+ key = e["method_name"].lower()
81
+ if key in index:
82
+ e = dict(e)
83
+ e["num"] = e["num"] or merged[index[key]]["num"]
84
+ merged[index[key]] = e
85
+ else:
86
+ index[key] = len(merged)
87
+ merged.append(dict(e))
88
+ next_num = max((int(r["num"]) for r in merged if r["num"].isdigit()), default=0) + 1
89
+ for r in merged:
90
+ if not r["num"]:
91
+ r["num"] = str(next_num)
92
+ next_num += 1
93
+ return merged
94
+
95
+
96
+ def categories(rows: list[dict]) -> list[tuple[str, int]]:
97
+ counts: dict[str, int] = {}
98
+ for r in rows:
99
+ counts[r["category"]] = counts.get(r["category"], 0) + 1
100
+ return sorted(counts.items())
101
+
102
+
103
+ def filter_cats(rows: list[dict], cats: list[str] | None) -> list[dict]:
104
+ if not cats:
105
+ return rows
106
+ wanted = {c.lower() for c in cats}
107
+ return [r for r in rows if r["category"].lower() in wanted]
108
+
109
+
110
+ def find(rows: list[dict], names: list[str]) -> tuple[list[dict], list[str]]:
111
+ """Match each query by method_name or by num, case-insensitively."""
112
+ by_key: dict[str, dict] = {}
113
+ for r in rows:
114
+ by_key[r["method_name"].lower()] = r
115
+ if r["num"]:
116
+ by_key.setdefault(r["num"], r)
117
+ found, missing = [], []
118
+ for n in names:
119
+ r = by_key.get(n.strip().lower())
120
+ (found if r else missing).append(r if r else n)
121
+ return found, missing
122
+
123
+
124
+ def exclude(rows: list[dict], names: list[str] | None) -> list[dict]:
125
+ if not names:
126
+ return rows
127
+ skip = {n.strip().lower() for n in names}
128
+ return [r for r in rows if r["method_name"].lower() not in skip]
129
+
130
+
131
+ def spread_sample(rows: list[dict], n: int, rng: random.Random | None = None) -> list[dict]:
132
+ """Draw n methods with maximum category diversity: shuffle the categories,
133
+ take one random method per category round-robin, wrapping only when there
134
+ are fewer categories than picks."""
135
+ rng = rng or random
136
+ by_cat: dict[str, list[dict]] = {}
137
+ for r in rows:
138
+ by_cat.setdefault(r["category"], []).append(r)
139
+ buckets = list(by_cat.values())
140
+ rng.shuffle(buckets)
141
+ for b in buckets:
142
+ rng.shuffle(b)
143
+ out: list[dict] = []
144
+ while buckets and len(out) < n:
145
+ exhausted = []
146
+ for b in buckets:
147
+ if len(out) >= n:
148
+ break
149
+ out.append(b.pop())
150
+ if not b:
151
+ exhausted.append(b)
152
+ buckets = [b for b in buckets if b not in exhausted]
153
+ return out
154
+
155
+
156
+ def fmt_categories(cats: list[tuple[str, int]], as_json: bool) -> str:
157
+ if as_json:
158
+ return json.dumps([{"category": c, "count": n} for c, n in cats])
159
+ return "\n".join(f"{c}\t{n}" for c, n in cats)
160
+
161
+
162
+ def fmt_rows(rows: list[dict], as_json: bool) -> str:
163
+ if as_json:
164
+ return json.dumps([{k: r[k] for k in FIELDS} for r in rows])
165
+ return "\n".join(
166
+ f"{r['num']}\t{r['category']}\t{r['method_name']}\t{r['description']}\t{r['output_pattern']}"
167
+ for r in rows
168
+ )
169
+
170
+
171
+ def main(argv: list[str] | None = None) -> int:
172
+ if hasattr(sys.stdout, "reconfigure"):
173
+ sys.stdout.reconfigure(encoding="utf-8") # catalog rows contain →; don't die on locale code pages
174
+ p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
175
+ p.add_argument("--file", type=Path, default=DEFAULT_FILE, help="method CSV (default: sibling assets/methods.csv)")
176
+ p.add_argument("--extra", help="additional methods: a JSON array literal or a path to a JSON file")
177
+ p.add_argument("--json", action="store_true", help="emit structured JSON instead of lean text")
178
+ sub = p.add_subparsers(dest="cmd", required=True)
179
+ sub.add_parser("categories", help="list category names + counts")
180
+ pl = sub.add_parser("list", help="the index for chosen categories (needs --category or --all)")
181
+ pl.add_argument("--category", action="append", help="filter to a category (repeatable)")
182
+ pl.add_argument("--all", action="store_true", help="dump the entire catalog (deliberate; large)")
183
+ ps = sub.add_parser("show", help="full row for each named method")
184
+ ps.add_argument("names", nargs="+", help="method names or nums")
185
+ pr = sub.add_parser("random", help="draw methods at random")
186
+ pr.add_argument("-n", type=int, default=1, help="how many (default 1)")
187
+ pr.add_argument("--category", action="append", help="restrict to a category (repeatable)")
188
+ pr.add_argument("--exclude", action="append", help="method name to skip (repeatable) — e.g. already shown")
189
+ pr.add_argument("--spread", action="store_true", help="force category diversity across the draw")
190
+ args = p.parse_args(argv)
191
+
192
+ if not args.file.is_file():
193
+ print(f"error: method file not found: {args.file}", file=sys.stderr)
194
+ return 2
195
+ rows = load(args.file)
196
+ if args.extra:
197
+ try:
198
+ rows = merge_extra(rows, load_extra(args.extra))
199
+ except (OSError, ValueError) as e:
200
+ print(f"error: could not read --extra: {e}", file=sys.stderr)
201
+ return 2
202
+
203
+ if args.cmd == "categories":
204
+ print(fmt_categories(categories(rows), args.json))
205
+ elif args.cmd == "list":
206
+ if not args.category and not args.all:
207
+ print(
208
+ "error: `list` needs --category (one or more) — or --all to dump the whole "
209
+ "catalog on purpose. Use `categories` for the cheap map, or `random` to draw blind.",
210
+ file=sys.stderr,
211
+ )
212
+ return 2
213
+ print(fmt_rows(filter_cats(rows, args.category), args.json))
214
+ elif args.cmd == "show":
215
+ found, missing = find(rows, args.names)
216
+ for m in missing:
217
+ print(f"# not found: {m}", file=sys.stderr)
218
+ if not found:
219
+ return 1
220
+ print(fmt_rows(found, args.json))
221
+ elif args.cmd == "random":
222
+ pool = exclude(filter_cats(rows, args.category), args.exclude)
223
+ if not pool:
224
+ print("# no methods match", file=sys.stderr)
225
+ return 1
226
+ n = max(0, min(args.n, len(pool))) # clamp: never crash on a negative or oversized -n
227
+ picks = spread_sample(pool, n) if args.spread else random.sample(pool, n)
228
+ print(fmt_rows(picks, args.json))
229
+ return 0
230
+
231
+
232
+ if __name__ == "__main__":
233
+ sys.exit(main())
@@ -0,0 +1,228 @@
1
+ # /// script
2
+ # requires-python = ">=3.10"
3
+ # dependencies = ["pytest>=8.0"]
4
+ # ///
5
+ """Tests for pick_methods.py.
6
+
7
+ Run: uv run scripts/tests/test_pick_methods.py
8
+ or: uv run --with pytest -m pytest scripts/tests/test_pick_methods.py
9
+ """
10
+ import json
11
+ import random
12
+ import sys
13
+ from pathlib import Path
14
+
15
+ import pytest
16
+
17
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
18
+ import pick_methods # noqa: E402
19
+
20
+ CSV = """num,category,method_name,description,output_pattern
21
+ 1,risk,Pre-mortem Analysis,Imagine future failure then work backwards,failure → causes → prevention
22
+ 2,risk,Assumption Audit,List and stress-test every assumption,list → rate → stress-test
23
+ 3,core,First Principles Analysis,Rebuild from fundamental truths,assumptions → truths → new approach
24
+ 4,core,Socratic Questioning,Targeted questions reveal hidden assumptions,questions → revelations → understanding
25
+ 5,creative,SCAMPER Method,Seven creativity lenses,S→C→A→M→P→E→R
26
+ """
27
+
28
+ EXTRA = [
29
+ {
30
+ "code": "reg-inversion",
31
+ "category": "domain",
32
+ "method_name": "Regulatory Inversion",
33
+ "description": "Start from the compliance constraint",
34
+ "output_pattern": "constraint → possibility",
35
+ },
36
+ {
37
+ "code": "premortem-lite",
38
+ "category": "risk",
39
+ "method_name": "Pre-mortem Analysis",
40
+ "description": "RETUNED pre-mortem",
41
+ "output_pattern": "failure → prevention",
42
+ },
43
+ ]
44
+
45
+
46
+ @pytest.fixture
47
+ def lib(tmp_path):
48
+ csv_path = tmp_path / "methods.csv"
49
+ csv_path.write_text(CSV, encoding="utf-8")
50
+ return csv_path
51
+
52
+
53
+ def rows(lib):
54
+ return pick_methods.load(lib)
55
+
56
+
57
+ # --- load / merge -----------------------------------------------------------
58
+
59
+ def test_load_all_fields_present(lib):
60
+ r = rows(lib)
61
+ assert len(r) == 5
62
+ assert r[0]["method_name"] == "Pre-mortem Analysis"
63
+ assert all(set(pick_methods.FIELDS) <= set(row) for row in r)
64
+
65
+
66
+ def test_load_extra_json_literal_and_file(tmp_path, lib):
67
+ literal = pick_methods.load_extra(json.dumps(EXTRA))
68
+ f = tmp_path / "extra.json"
69
+ f.write_text(json.dumps(EXTRA), encoding="utf-8")
70
+ from_file = pick_methods.load_extra(str(f))
71
+ assert literal == from_file
72
+ assert literal[0]["method_name"] == "Regulatory Inversion"
73
+ assert literal[0]["num"] == "" # missing fields normalize to empty
74
+ assert literal[0]["code"] == "reg-inversion" # code survives loading
75
+
76
+
77
+ def test_merge_extra_replaces_by_name_and_appends(lib):
78
+ merged = pick_methods.merge_extra(rows(lib), pick_methods.load_extra(json.dumps(EXTRA)))
79
+ assert len(merged) == 6 # 5 shipped, 1 replaced in place, 1 appended
80
+ premortem = next(r for r in merged if r["method_name"] == "Pre-mortem Analysis")
81
+ assert premortem["description"] == "RETUNED pre-mortem"
82
+ assert premortem["num"] == "1" # replacement inherits the shipped num
83
+ appended = next(r for r in merged if r["method_name"] == "Regulatory Inversion")
84
+ assert appended["num"] == "6" # appended extras get the next free num
85
+ assert dict(pick_methods.categories(merged))["domain"] == 1 # new category is first-class
86
+
87
+
88
+ def test_extras_are_addressable_by_num(lib):
89
+ merged = pick_methods.merge_extra(rows(lib), pick_methods.load_extra(json.dumps(EXTRA)))
90
+ found, missing = pick_methods.find(merged, ["6", "1"])
91
+ assert [r["method_name"] for r in found] == ["Regulatory Inversion", "Pre-mortem Analysis"]
92
+ assert missing == []
93
+
94
+
95
+ # --- categories / filter / find / exclude -----------------------------------
96
+
97
+ def test_categories_counts_sorted(lib):
98
+ assert pick_methods.categories(rows(lib)) == [("core", 2), ("creative", 1), ("risk", 2)]
99
+
100
+
101
+ def test_filter_is_case_insensitive(lib):
102
+ got = pick_methods.filter_cats(rows(lib), ["RISK"])
103
+ assert {r["method_name"] for r in got} == {"Pre-mortem Analysis", "Assumption Audit"}
104
+
105
+
106
+ def test_filter_none_returns_all(lib):
107
+ assert len(pick_methods.filter_cats(rows(lib), None)) == 5
108
+
109
+
110
+ def test_find_by_name_num_and_missing(lib):
111
+ found, missing = pick_methods.find(rows(lib), ["scamper method", "3", "Nope"])
112
+ assert [r["method_name"] for r in found] == ["SCAMPER Method", "First Principles Analysis"]
113
+ assert missing == ["Nope"]
114
+
115
+
116
+ def test_exclude_skips_named(lib):
117
+ got = pick_methods.exclude(rows(lib), ["pre-mortem analysis", "SCAMPER Method"])
118
+ assert {r["method_name"] for r in got} == {
119
+ "Assumption Audit", "First Principles Analysis", "Socratic Questioning",
120
+ }
121
+
122
+
123
+ # --- spread sampling ---------------------------------------------------------
124
+
125
+ def test_spread_hits_distinct_categories(lib):
126
+ for seed in range(20):
127
+ picks = pick_methods.spread_sample(rows(lib), 3, random.Random(seed))
128
+ assert len({r["category"] for r in picks}) == 3
129
+
130
+
131
+ def test_spread_wraps_when_categories_run_out(lib):
132
+ picks = pick_methods.spread_sample(rows(lib), 5, random.Random(0))
133
+ assert len(picks) == 5
134
+ assert len({r["method_name"] for r in picks}) == 5 # no duplicates
135
+
136
+
137
+ def test_spread_clamps_to_pool(lib):
138
+ assert len(pick_methods.spread_sample(rows(lib), 99, random.Random(0))) == 5
139
+
140
+
141
+ # --- CLI ---------------------------------------------------------------------
142
+
143
+ def run(args, lib, capsys):
144
+ code = pick_methods.main(["--file", str(lib), *args])
145
+ captured = capsys.readouterr()
146
+ return code, captured.out, captured.err
147
+
148
+
149
+ def test_cli_categories(lib, capsys):
150
+ code, out, _ = run(["categories"], lib, capsys)
151
+ assert code == 0
152
+ assert "risk\t2" in out
153
+
154
+
155
+ def test_cli_list_requires_scope(lib, capsys):
156
+ code, _, err = run(["list"], lib, capsys)
157
+ assert code == 2
158
+ assert "--category" in err
159
+
160
+
161
+ def test_cli_list_category_and_all(lib, capsys):
162
+ code, out, _ = run(["list", "--category", "core"], lib, capsys)
163
+ assert code == 0 and len(out.strip().splitlines()) == 2
164
+ assert "Socratic Questioning" in out and "SCAMPER" not in out
165
+ code, out, _ = run(["list", "--all"], lib, capsys)
166
+ assert code == 0 and "SCAMPER" in out
167
+
168
+
169
+ def test_cli_show_found_and_missing(lib, capsys):
170
+ code, out, err = run(["show", "Assumption Audit", "Ghost"], lib, capsys)
171
+ assert code == 0
172
+ assert "stress-test" in out
173
+ assert "not found: Ghost" in err
174
+ code, _, _ = run(["show", "Ghost"], lib, capsys)
175
+ assert code == 1
176
+
177
+
178
+ def test_cli_random_spread_exclude(lib, capsys):
179
+ code, out, _ = run(
180
+ ["random", "-n", "3", "--spread", "--exclude", "SCAMPER Method"], lib, capsys
181
+ )
182
+ assert code == 0
183
+ lines = [ln for ln in out.strip().splitlines() if ln]
184
+ assert len(lines) == 3
185
+ assert "SCAMPER" not in out
186
+
187
+
188
+ def test_cli_random_clamps_and_empty_pool(lib, capsys):
189
+ code, out, _ = run(["random", "-n", "99"], lib, capsys)
190
+ assert code == 0 and len(out.strip().splitlines()) == 5
191
+ code, _, err = run(["random", "--category", "nope"], lib, capsys)
192
+ assert code == 1 and "no methods match" in err
193
+
194
+
195
+ def test_cli_extra_inline_json(lib, capsys):
196
+ code, out, _ = run(
197
+ ["--extra", json.dumps(EXTRA), "list", "--category", "domain"], lib, capsys
198
+ )
199
+ assert code == 0 and "Regulatory Inversion" in out
200
+
201
+
202
+ def test_cli_bad_extra_and_missing_file(tmp_path, lib, capsys):
203
+ code, _, err = run(["--extra", str(tmp_path / "gone.json"), "categories"], lib, capsys)
204
+ assert code == 2 and "--extra" in err
205
+ code = pick_methods.main(["--file", str(tmp_path / "gone.csv"), "categories"])
206
+ assert code == 2
207
+
208
+
209
+ def test_cli_json_output(lib, capsys):
210
+ code, out, _ = run(["--json", "show", "1"], lib, capsys)
211
+ assert code == 0
212
+ data = json.loads(out)
213
+ assert data[0]["method_name"] == "Pre-mortem Analysis"
214
+
215
+
216
+ # --- shipped catalog integration ----------------------------------------------
217
+
218
+ def test_shipped_catalog_loads_clean():
219
+ shipped = pick_methods.DEFAULT_FILE
220
+ assert shipped.is_file(), f"shipped catalog missing: {shipped}"
221
+ r = pick_methods.load(shipped)
222
+ assert len(r) >= 60
223
+ for row in r:
224
+ assert row["category"] and row["method_name"] and row["description"], row
225
+
226
+
227
+ if __name__ == "__main__":
228
+ sys.exit(pytest.main([__file__, "-q"]))
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: bmad-brainstorming
3
+ description: Facilitate a brainstorming session using diverse creative techniques. Use when the user says 'help me brainstorm' or 'help me ideate'.
4
+ ---
5
+
6
+ # BMad Brainstorming
7
+
8
+ ## Overview
9
+
10
+ You are a creative brainstorming coach. This skill runs a brainstorming session: someone brings a topic and wants to generate far more and far better ideas on it than they would alone — pushing past the obvious with sharper questions and harder constraints, with no rush to finish. The best sessions end with the user surprised by what came out.
11
+
12
+ The session runs in one of three stances, chosen by the user — set explicitly at the start, or already implied by how they asked: **Facilitator** (you never supply ideas — a forcing function for theirs), **Creative Partner** (you facilitate *and* play along, trading ideas), or **Ideate for me** (you run the whole session yourself and show them the result). The chosen stance holds for the whole run.
13
+
14
+ ## Conventions
15
+
16
+ - Bare paths (e.g. `references/headless.md`) resolve from `{skill-root}` (where `customize.toml` lives); `{project-root}`-prefixed paths from the project working directory.
17
+ - `{workflow.<name>}` resolves to fields in the merged `customize.toml` `[workflow]` table.
18
+
19
+ ## On Activation
20
+
21
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, use a subagent to read `{skill-root}/customize.toml` directly with defaults.
22
+ 2. Run each `{workflow.activation_steps_prepend}` entry. Treat each `{workflow.persistent_facts}` entry as foundational context (`file:`-prefixed entries are paths/globs under `{project-root}` — load their contents; others are facts verbatim).
23
+ 3. Resolve central config: `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root} --key core` (merges `_bmad/config.toml`, `_bmad/config.user.toml`, and the `_bmad/custom/` overrides); from the merged JSON resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{output_folder}`, `{project_name}`; `{date}` is today. On failure or missing values → neutral defaults; never block.
24
+ 4. **If launched headless** (a machine signal, not a human asking for output — `references/headless.md` lists them): load `references/headless.md` and follow it for the whole run; never load it otherwise. Outside headless, you generate ideas yourself only in autonomous mode (`references/mode-autonomous.md`) — never in facilitator or partner mode.
25
+ 5. **Otherwise (interactive):** greet `{user_name}` in `{communication_language}` and stay in it. Note that `bmad-party-mode` and `bmad-advanced-elicitation` are available any time (mention only the ones installed; either may be absent). Glob `{workflow.output_dir}/*/.memlog.md`, read each frontmatter, and offer to resume any with `status` not `complete` (`## Resuming`) or start fresh (`## Run a Session`).
26
+
27
+ Run each `{workflow.activation_steps_append}` entry; if either hook list was non-empty, confirm every entry ran before continuing.
28
+
29
+ ## Framing — hold this the whole run
30
+
31
+ These fight your defaults, in every mode; hold them deliberately. The stance you pick adds one more frame (`references/mode-*.md`) on top.
32
+
33
+ - **Aim past 100 ideas; resist concluding.** The urge to organize or wrap is the enemy of divergence — when in doubt, push for one more. Land only when the user is spent or the topic is mined out.
34
+ - **Keep shifting the creative domain** — every 5–10 turns (or ~10 ideas when you're generating), usually by moving to the next technique.
35
+ - **One prompt per message while in dialogue (Facilitator, Creative Partner); no multiple-choice menus.** Don't stack questions into a wall or hand a menu that invites lazy picking — both pull the user out of generating. The only exceptions are the two up-front *process* choices (stance, and the technique flow): *how* to run is theirs to pick; *what* to ideate never is.
36
+
37
+ **The memlog** is the session's memory: the single source every output builds from, and the file a resume reloads. Whatever isn't in it is gone. Log every idea, decision, question, and bit of user direction — anything you'd regret losing if the window closed — one line each, the gist in the user's meaning, in time order; never edit or reorder. Skip your prompts and small talk. All writes to memlog are atomic and use the script `memlog.py` invoked as follows:
38
+
39
+ - `uv run {project-root}/_bmad/scripts/memlog.py init --workspace {doc_workspace} --field topic="<topic>" --field goal="<goal>" --field mode="<facilitator|partner|autonomous>"` — create it once topic, goal, and stance are known.
40
+ - `uv run {project-root}/_bmad/scripts/memlog.py append --workspace {doc_workspace} --type <kind> --text "<one-line gist>"` — log one entry. `--type` ∈ `idea`/`insight`/`question`/`decision`/`direction`/`technique` (a switch: `--text "started <name>"`); omit for a plain note. Add `--by user`/`--by coach` to mark authorship — **required in Creative Partner mode** (renders `(idea by user)`); skip it otherwise.
41
+ - `uv run {project-root}/_bmad/scripts/memlog.py set --workspace {doc_workspace} --key status --value complete` — flip status at wrap-up.
42
+
43
+ ## Run a Session
44
+
45
+ Open with one compound question what are we brainstorming, and what's the goal or why behind it (along with asking if there are any inputs or special requests). The why shapes technique choice and synthesis (*kids' iPhone apps to build with your own kids* vs. *to win market share* point different ways). If the kickoff already made both clear, skip the question and confirm; read anything they point you to. Derive a kebab-case `{topic_slug}` and bind `{doc_workspace} = {workflow.output_dir}/{workflow.output_folder_name}/`.
46
+
47
+ Now set the **stance** and the **technique batch** in one step — the composer page does both, so make it the default.
48
+
49
+ **The composer page (primary).** The file is `{skill-root}/assets/brain-selector.html`. With a customized catalog (overridden `{workflow.brain_methods}` or any `{workflow.additional_techniques}`), regenerate it first: `uv run {skill-root}/scripts/brain.py --file {workflow.brain_methods} [--extra {doc_workspace}/extra-techniques.json] html --out {doc_workspace}/brain-selector.html` (pass `--extra`, a JSON list of `{category, technique_name, description}`, when there are additional techniques; the file is then `{doc_workspace}/brain-selector.html`). Try to open it (`open` / `xdg-open` / `start`), then say, in one message: *"It should open in your browser — compose your session, click **Copy prompt**, and paste the result back. If it didn't open, open `<path>` yourself, or say 'let's do it in chat'."* You can't see their browser, so never claim it opened.
50
+
51
+ Read the pasted block: the **`Facilitation mode:`** line → the stance; the **listed techniques** (full category/name/description, some tagged `(random pick)`) → run them as given, no `list`/`show` needed; **`invent N`** / **`you choose N`** → see `## Choosing Techniques`.
52
+
53
+ **Or in chat.** If they can't open the page or would rather not, pick the stance here and choose techniques per `## Choosing Techniques`.
54
+
55
+ Either way, once the stance is known, create the memlog (the `init` above, with `--field mode=`) and load its frame for the rest of the run — Facilitator → `references/mode-facilitator.md`, Creative Partner → `references/mode-partner.md`, Ideate for me → `references/mode-autonomous.md`. Tell the user the memlog path: state is on disk now, so the session survives interruption.
56
+
57
+ ## Choosing Techniques
58
+
59
+ For **Facilitator** and **Creative Partner**. (In **Ideate for me** you pick and run techniques yourself — see `references/mode-autonomous.md`.)
60
+
61
+ Most sessions arrive with a batch already composed on the page — run it as given (each technique's full text is in the paste; no `list`/`show` needed). Two parts of a paste delegate back to you:
62
+
63
+ - **`invent N`** (Inventive Flow) — invent N brand-new techniques on the fly. A line may scope an invention (`invent 1 new technique in the spirit of <category>`, from the page's per-category invent card) — when it does, honor that category's spirit. Announce the order, log each one's name + description, and offer to save a keeper to `{workflow.additional_techniques}` at wrap-up.
64
+ - **`you choose N`** (Facilitator Chosen) — pick N techniques fitting the goal, `{workflow.favorite_techniques}` first; confirm exact names with a scoped `uv run {skill-root}/scripts/brain.py --file {workflow.brain_methods} list --category <cat>`. Never pull the library whole into context.
65
+
66
+ If they didn't use the page, load `references/in-chat-techniques.md` and pick the batch in chat (**3–4 is the sweet spot**).
67
+
68
+ Run each technique until it stops producing — log each idea, and the switch itself as a `technique` entry when you move on — then announce the new lens and let the change of technique do the domain-shifting. When the batch is spent, offer three paths: run another batch, **converge** to narrow and decide (`## Converging`), or wrap up (`## Wrap-Up`).
69
+
70
+ ## Converging
71
+
72
+ The catalog is all *divergent* — built to generate. When the user is ready to narrow and decide (or asks to "pick"/"prioritize"/"make it real"), load `references/converge.md` and follow it; it ends by handing off to `## Wrap-Up`. Convergence is a distinct phase: never fold it into a generating batch, and don't push toward it while ideas are still flowing.
73
+
74
+ ## Resuming
75
+
76
+ Picking up an existing session instead of starting fresh: load `references/resume.md` and follow it.
77
+
78
+ ## Wrap-Up
79
+
80
+ Load `references/finalize.md` (after `## Converging`, or directly when the user is spent): synthesis, `status: complete`, artifacts.