bmad-method 6.0.0-alpha.13 → 6.0.0-alpha.15
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.
- package/.coderabbit.yaml +36 -0
- package/.github/CODE_OF_CONDUCT.md +128 -0
- package/.github/ISSUE_TEMPLATE/idea_submission.md +1 -1
- package/.github/scripts/discord-helpers.sh +15 -0
- package/.github/workflows/discord.yaml +278 -8
- package/.github/workflows/quality.yaml +19 -0
- package/.markdownlint-cli2.yaml +42 -0
- package/.prettierignore +3 -0
- package/CHANGELOG.md +183 -360
- package/README.md +4 -1
- package/docs/agent-customization-guide.md +2 -2
- package/docs/custom-content-installation.md +245 -0
- package/docs/document-sharding-guide.md +1 -1
- package/docs/index.md +2 -2
- package/docs/installers-bundlers/installers-modules-platforms-reference.md +6 -5
- package/docs/web-bundles-gemini-gpt-guide.md +1 -1
- package/eslint.config.mjs +14 -0
- package/example-custom-content/README.md +8 -0
- package/{custom/src → example-custom-content}/agents/commit-poet/commit-poet.agent.yaml +1 -1
- package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/instructions.md +5 -5
- package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/knowledge/docs.md +1 -1
- package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/knowledge/installers.md +1 -1
- package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/knowledge/modules.md +2 -2
- package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/memories.md +1 -1
- package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith.agent.yaml +18 -17
- package/example-custom-content/module.yaml +4 -0
- package/example-custom-content/workflows/quiz-master/steps/step-01-init.md +168 -0
- package/example-custom-content/workflows/quiz-master/steps/step-02-q1.md +155 -0
- package/example-custom-content/workflows/quiz-master/steps/step-03-q2.md +89 -0
- package/example-custom-content/workflows/quiz-master/steps/step-04-q3.md +36 -0
- package/example-custom-content/workflows/quiz-master/steps/step-05-q4.md +36 -0
- package/example-custom-content/workflows/quiz-master/steps/step-06-q5.md +36 -0
- package/example-custom-content/workflows/quiz-master/steps/step-07-q6.md +36 -0
- package/example-custom-content/workflows/quiz-master/steps/step-08-q7.md +36 -0
- package/example-custom-content/workflows/quiz-master/steps/step-09-q8.md +36 -0
- package/example-custom-content/workflows/quiz-master/steps/step-10-q9.md +36 -0
- package/example-custom-content/workflows/quiz-master/steps/step-11-q10.md +36 -0
- package/example-custom-content/workflows/quiz-master/steps/step-12-results.md +150 -0
- package/example-custom-content/workflows/quiz-master/templates/csv-headers.template +1 -0
- package/example-custom-content/workflows/quiz-master/workflow.md +54 -0
- package/example-custom-content/workflows/wassup/workflow.md +26 -0
- package/example-custom-module/mwm/README.md +9 -0
- package/example-custom-module/mwm/agents/cbt-coach/cbt-coach-sidecar/cognitive-distortions.md +47 -0
- package/example-custom-module/mwm/agents/cbt-coach/cbt-coach-sidecar/thought-records.md +17 -0
- package/example-custom-module/mwm/agents/cbt-coach/cbt-coach.agent.yaml +151 -0
- package/example-custom-module/mwm/agents/crisis-navigator.agent.yaml +138 -0
- package/example-custom-module/mwm/agents/meditation-guide.agent.yaml +138 -0
- package/example-custom-module/mwm/agents/wellness-companion/wellness-companion-sidecar/insights.md +13 -0
- package/example-custom-module/mwm/agents/wellness-companion/wellness-companion-sidecar/instructions.md +30 -0
- package/example-custom-module/mwm/agents/wellness-companion/wellness-companion-sidecar/memories.md +13 -0
- package/example-custom-module/mwm/agents/wellness-companion/wellness-companion-sidecar/patterns.md +17 -0
- package/example-custom-module/mwm/agents/wellness-companion/wellness-companion.agent.yaml +125 -0
- package/example-custom-module/mwm/module.yaml +28 -0
- package/example-custom-module/mwm/workflows/cbt-thought-record/README.md +31 -0
- package/example-custom-module/mwm/workflows/cbt-thought-record/workflow.md +45 -0
- package/example-custom-module/mwm/workflows/crisis-support/README.md +31 -0
- package/example-custom-module/mwm/workflows/crisis-support/workflow.md +45 -0
- package/example-custom-module/mwm/workflows/daily-checkin/README.md +32 -0
- package/example-custom-module/mwm/workflows/daily-checkin/workflow.md +45 -0
- package/example-custom-module/mwm/workflows/guided-meditation/README.md +31 -0
- package/example-custom-module/mwm/workflows/guided-meditation/workflow.md +45 -0
- package/example-custom-module/mwm/workflows/wellness-journal/README.md +31 -0
- package/example-custom-module/mwm/workflows/wellness-journal/workflow.md +45 -0
- package/package.json +9 -4
- package/src/core/_module-installer/installer.js +1 -1
- package/src/core/{_module-installer/install-config.yaml → module.yaml} +5 -1
- package/src/core/resources/excalidraw/library-loader.md +2 -2
- package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +1 -1
- package/src/core/workflows/brainstorming/workflow.md +1 -1
- package/src/core/workflows/party-mode/steps/step-03-graceful-exit.md +0 -1
- package/src/core/workflows/party-mode/workflow.md +2 -3
- package/src/modules/bmb/README.md +1 -1
- package/src/modules/bmb/_module-installer/installer.js +76 -0
- package/src/modules/bmb/agents/bmad-builder.agent.yaml +32 -9
- package/src/modules/bmb/docs/agents/agent-menu-patterns.md +5 -5
- package/src/modules/bmb/docs/agents/expert-agent-architecture.md +20 -20
- package/src/modules/bmb/docs/agents/index.md +1 -1
- package/src/modules/bmb/docs/agents/module-agent-architecture.md +45 -45
- package/src/modules/bmb/docs/agents/simple-agent-architecture.md +7 -3
- package/src/modules/bmb/docs/workflows/architecture.md +1 -1
- package/src/modules/bmb/docs/workflows/templates/step-01-init-continuable-template.md +241 -0
- package/src/modules/bmb/docs/workflows/templates/step-1b-template.md +223 -0
- package/src/modules/bmb/{workflows/create-workflow → docs/workflows}/templates/step-file.md +4 -4
- package/src/modules/bmb/docs/workflows/{step-template.md → templates/step-template.md} +40 -33
- package/src/modules/bmb/docs/workflows/templates/workflow-template.md +104 -0
- package/src/modules/bmb/{workflows/create-workflow → docs/workflows}/templates/workflow.md +1 -1
- package/src/modules/bmb/{_module-installer/install-config.yaml → module.yaml} +4 -9
- package/src/modules/bmb/reference/agents/expert-examples/journal-keeper/README.md +4 -4
- package/src/modules/bmb/reference/agents/expert-examples/journal-keeper/journal-keeper.agent.yaml +8 -8
- package/src/modules/bmb/reference/agents/module-examples/security-engineer.agent.yaml +6 -6
- package/src/modules/bmb/reference/agents/module-examples/trend-analyst.agent.yaml +7 -7
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-01-init.md +2 -3
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-01b-continue.md +10 -40
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-02-profile.md +1 -1
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-03-assessment.md +1 -0
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-04-strategy.md +2 -2
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-05-shopping.md +2 -2
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-06-prep-schedule.md +2 -2
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/workflow.md +2 -2
- package/src/modules/bmb/workflows/create-agent/data/info-and-installation-guide.md +16 -4
- package/src/modules/bmb/workflows/create-agent/data/reference/agents/expert-examples/journal-keeper/README.md +4 -4
- package/src/modules/bmb/workflows/create-agent/data/reference/agents/expert-examples/journal-keeper/journal-keeper.agent.yaml +7 -7
- package/src/modules/bmb/workflows/create-agent/data/reference/workflows/meal-prep-nutrition/steps/step-05-shopping.md +1 -1
- package/src/modules/bmb/workflows/create-agent/data/validation-complete.md +3 -3
- package/src/modules/bmb/workflows/create-agent/steps/step-01-brainstorm.md +3 -3
- package/src/modules/bmb/workflows/create-agent/steps/step-02-discover.md +3 -3
- package/src/modules/bmb/workflows/create-agent/steps/step-03-persona.md +3 -3
- package/src/modules/bmb/workflows/create-agent/steps/step-04-commands.md +6 -6
- package/src/modules/bmb/workflows/create-agent/steps/step-05-name.md +2 -2
- package/src/modules/bmb/workflows/create-agent/steps/step-06-build.md +3 -3
- package/src/modules/bmb/workflows/create-agent/steps/step-07-validate.md +3 -3
- package/src/modules/bmb/workflows/create-agent/steps/step-08-setup.md +2 -2
- package/src/modules/bmb/workflows/create-agent/steps/step-09-customize.md +3 -3
- package/src/modules/bmb/workflows/create-agent/steps/step-10-build-tools.md +2 -2
- package/src/modules/bmb/workflows/create-agent/steps/step-11-celebrate.md +2 -2
- package/src/modules/bmb/workflows/create-agent/workflow.md +11 -11
- package/src/modules/bmb/workflows/create-module/steps/step-01-init.md +155 -0
- package/src/modules/bmb/workflows/create-module/steps/step-01b-continue.md +169 -0
- package/src/modules/bmb/workflows/create-module/steps/step-02-concept.md +217 -0
- package/src/modules/bmb/workflows/create-module/steps/step-03-components.md +267 -0
- package/src/modules/bmb/workflows/create-module/steps/step-04-structure.md +228 -0
- package/src/modules/bmb/workflows/create-module/steps/step-05-config.md +233 -0
- package/src/modules/bmb/workflows/create-module/steps/step-06-agents.md +296 -0
- package/src/modules/bmb/workflows/create-module/steps/step-07-workflows.md +228 -0
- package/src/modules/bmb/workflows/create-module/steps/step-08-installer.md +186 -0
- package/src/modules/bmb/workflows/create-module/steps/step-09-documentation.md +309 -0
- package/src/modules/bmb/workflows/create-module/steps/step-10-roadmap.md +337 -0
- package/src/modules/bmb/workflows/create-module/steps/step-11-validate.md +335 -0
- package/src/modules/bmb/workflows/create-module/templates/agent.template.md +317 -0
- package/src/modules/bmb/workflows/create-module/templates/installer.template.js +47 -0
- package/src/modules/bmb/workflows/create-module/templates/module-plan.template.md +5 -0
- package/src/modules/bmb/workflows/create-module/templates/module.template.yaml +53 -0
- package/src/modules/bmb/workflows/create-module/templates/workflow-plan-template.md +23 -0
- package/src/modules/bmb/workflows/create-module/validation.md +126 -0
- package/src/modules/bmb/workflows/create-module/workflow.md +55 -0
- package/src/modules/bmb/workflows/create-workflow/steps/step-01-init.md +45 -56
- package/src/modules/bmb/workflows/create-workflow/steps/step-02-gather.md +9 -31
- package/src/modules/bmb/workflows/create-workflow/steps/step-03-tools-configuration.md +250 -0
- package/src/modules/bmb/workflows/create-workflow/steps/step-04-plan-review.md +216 -0
- package/src/modules/bmb/workflows/create-workflow/steps/step-05-output-format-design.md +289 -0
- package/src/modules/bmb/workflows/create-workflow/steps/{step-09-design.md → step-06-design.md} +76 -44
- package/src/modules/bmb/workflows/create-workflow/steps/{step-11-build.md → step-07-build.md} +71 -25
- package/src/modules/bmb/workflows/create-workflow/steps/{step-12-review.md → step-08-review.md} +30 -16
- package/src/modules/bmb/workflows/create-workflow/steps/step-09-complete.md +187 -0
- package/src/modules/bmb/workflows/create-workflow/workflow.md +2 -2
- package/src/modules/bmb/workflows/edit-agent/steps/step-01-discover-intent.md +2 -2
- package/src/modules/bmb/workflows/edit-agent/steps/step-02-analyze-agent.md +14 -14
- package/src/modules/bmb/workflows/edit-agent/steps/step-03-propose-changes.md +4 -4
- package/src/modules/bmb/workflows/edit-agent/steps/step-04-apply-changes.md +2 -2
- package/src/modules/bmb/workflows/edit-agent/steps/step-05-validate.md +4 -4
- package/src/modules/bmb/workflows/edit-agent/workflow.md +1 -1
- package/src/modules/bmb/workflows/edit-workflow/steps/step-01-analyze.md +2 -6
- package/src/modules/bmb/workflows/edit-workflow/steps/step-03-improve.md +2 -2
- package/src/modules/bmb/workflows/edit-workflow/steps/step-04-validate.md +1 -1
- package/src/modules/bmb/workflows/edit-workflow/workflow.md +1 -1
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-01-validate-goal.md +2 -2
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-02-workflow-validation.md +5 -5
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-03-step-validation.md +7 -7
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-04-file-validation.md +3 -3
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-05-intent-spectrum-validation.md +3 -3
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-06-web-subprocess-validation.md +3 -3
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-07-holistic-analysis.md +3 -3
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-08-generate-report.md +2 -2
- package/src/modules/bmb/workflows/workflow-compliance-check/workflow.md +1 -1
- package/src/modules/bmb/workflows-legacy/edit-module/checklist.md +0 -1
- package/src/modules/bmgd/README.md +2 -1
- package/src/modules/bmgd/workflows/3-technical/game-architecture/instructions.md +8 -8
- package/src/modules/bmm/_module-installer/installer.js +1 -1
- package/src/modules/bmm/_module-installer/platform-specifics/claude-code.js +1 -1
- package/src/modules/bmm/_module-installer/platform-specifics/windsurf.js +1 -1
- package/src/modules/bmm/agents/analyst.agent.yaml +11 -8
- package/src/modules/bmm/agents/architect.agent.yaml +1 -5
- package/src/modules/bmm/agents/pm.agent.yaml +5 -5
- package/src/modules/bmm/docs/README.md +23 -1
- package/src/modules/bmm/docs/agents-guide.md +16 -35
- package/src/modules/bmm/docs/brownfield-guide.md +17 -30
- package/src/modules/bmm/docs/enterprise-agentic-development.md +2 -2
- package/src/modules/bmm/docs/faq.md +6 -39
- package/src/modules/bmm/docs/glossary.md +11 -24
- package/src/modules/bmm/docs/images/README.md +37 -0
- package/src/modules/bmm/docs/images/workflow-method-greenfield.excalidraw +62 -202
- package/src/modules/bmm/docs/images/workflow-method-greenfield.svg +3 -1
- package/src/modules/bmm/docs/quick-spec-flow.md +652 -0
- package/src/modules/bmm/docs/quick-start.md +9 -25
- package/src/modules/bmm/docs/test-architecture.md +6 -6
- package/src/modules/bmm/docs/troubleshooting.md +680 -0
- package/src/modules/bmm/docs/workflow-document-project-reference.md +1 -1
- package/src/modules/bmm/docs/workflows-implementation.md +143 -3
- package/src/modules/bmm/docs/workflows-solutioning.md +2 -2
- package/src/modules/bmm/{_module-installer/install-config.yaml → module.yaml} +1 -1
- package/src/modules/bmm/tasks/daily-standup.xml +85 -0
- package/src/modules/bmm/testarch/knowledge/ci-burn-in.md +1 -1
- package/src/modules/bmm/testarch/knowledge/overview.md +1 -1
- package/src/modules/bmm/workflows/1-analysis/product-brief/steps/step-02-vision.md +2 -2
- package/src/modules/bmm/workflows/1-analysis/product-brief/steps/step-03-users.md +2 -2
- package/src/modules/bmm/workflows/1-analysis/product-brief/steps/step-04-metrics.md +2 -2
- package/src/modules/bmm/workflows/1-analysis/product-brief/steps/step-05-scope.md +2 -2
- package/src/modules/bmm/workflows/1-analysis/product-brief/workflow.md +1 -1
- package/src/modules/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +8 -8
- package/src/modules/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +18 -18
- package/src/modules/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +18 -18
- package/src/modules/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +18 -18
- package/src/modules/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +17 -17
- package/src/modules/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +35 -36
- package/src/modules/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +5 -6
- package/src/modules/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +20 -19
- package/src/modules/bmm/workflows/1-analysis/research/market-steps/step-02-customer-insights.md +21 -20
- package/src/modules/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +20 -19
- package/src/modules/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +21 -20
- package/src/modules/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +16 -15
- package/src/modules/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +36 -37
- package/src/modules/bmm/workflows/1-analysis/research/research.template.md +0 -1
- package/src/modules/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +8 -8
- package/src/modules/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +19 -18
- package/src/modules/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +20 -19
- package/src/modules/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +21 -20
- package/src/modules/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +19 -18
- package/src/modules/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +38 -39
- package/src/modules/bmm/workflows/1-analysis/research/workflow.md +14 -8
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +6 -0
- package/src/modules/bmm/workflows/2-plan-workflows/prd/prd-template.md +7 -0
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-01-init.md +138 -56
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-01b-continue.md +93 -51
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-02-discovery.md +223 -78
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-03-success.md +20 -2
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-04-journeys.md +18 -0
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-05-domain.md +21 -0
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-06-innovation.md +21 -0
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-07-project-type.md +21 -0
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-08-scoping.md +18 -0
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-09-functional.md +18 -0
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-10-nonfunctional.md +18 -0
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-11-complete.md +13 -0
- package/src/modules/bmm/workflows/2-plan-workflows/prd/workflow.md +2 -2
- package/src/modules/bmm/workflows/3-solutioning/architecture/steps/step-03-starter.md +14 -14
- package/src/modules/bmm/workflows/3-solutioning/architecture/steps/step-04-decisions.md +7 -7
- package/src/modules/bmm/workflows/3-solutioning/architecture/workflow.md +2 -1
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md +258 -0
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +232 -0
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +271 -0
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +144 -0
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/templates/epics-template.md +57 -0
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +58 -0
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/steps/step-01-document-discovery.md +189 -0
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/steps/step-02-prd-analysis.md +177 -0
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/steps/step-03-epic-coverage-validation.md +178 -0
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/steps/step-04-ux-alignment.md +138 -0
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/steps/step-05-epic-quality-review.md +251 -0
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/steps/step-06-final-assessment.md +132 -0
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/templates/readiness-report-template.md +4 -0
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/workflow.md +54 -0
- package/src/modules/{bmgd/workflows/4-production → bmm/workflows/4-implementation}/code-review/checklist.md +2 -1
- package/src/modules/bmm/workflows/4-implementation/code-review/instructions.xml +51 -3
- package/src/modules/bmm/workflows/4-implementation/code-review/workflow.yaml +1 -1
- package/src/modules/bmm/workflows/4-implementation/create-story/instructions.xml +32 -2
- package/src/modules/bmm/workflows/4-implementation/retrospective/instructions.md +3 -3
- package/src/modules/bmm/workflows/4-implementation/sprint-planning/instructions.md +19 -21
- package/src/modules/bmm/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +10 -10
- package/src/modules/bmm/workflows/4-implementation/sprint-status/instructions.md +174 -0
- package/src/modules/bmm/workflows/4-implementation/sprint-status/workflow.yaml +35 -0
- package/src/modules/bmm/workflows/bmad-quick-flow/quick-dev/instructions.md +104 -7
- package/src/modules/bmm/workflows/bmad-quick-flow/quick-dev/workflow.yaml +4 -0
- package/src/modules/bmm/workflows/document-project/instructions.md +1 -1
- package/src/modules/bmm/workflows/document-project/workflows/deep-dive-instructions.md +2 -2
- package/src/modules/bmm/workflows/generate-project-context/workflow.md +1 -1
- package/src/modules/bmm/workflows/testarch/atdd/atdd-checklist-template.md +1 -1
- package/src/modules/bmm/workflows/testarch/ci/checklist.md +1 -1
- package/src/modules/bmm/workflows/testarch/ci/github-actions-template.yaml +36 -3
- package/src/modules/bmm/workflows/testarch/ci/gitlab-ci-template.yaml +25 -4
- package/src/modules/bmm/workflows/testarch/ci/instructions.md +2 -2
- package/src/modules/bmm/workflows/testarch/test-review/instructions.md +1 -1
- package/src/modules/bmm/workflows/workflow-status/paths/enterprise-brownfield.yaml +1 -6
- package/src/modules/bmm/workflows/workflow-status/paths/enterprise-greenfield.yaml +1 -6
- package/src/modules/bmm/workflows/workflow-status/paths/method-brownfield.yaml +1 -6
- package/src/modules/bmm/workflows/workflow-status/paths/method-greenfield.yaml +1 -7
- package/src/modules/cis/_module-installer/installer.js +1 -1
- package/tools/cli/README.md +7 -7
- package/tools/cli/commands/build.js +9 -184
- package/tools/cli/commands/install.js +1 -6
- package/tools/cli/installers/lib/core/config-collector.js +80 -12
- package/tools/cli/installers/lib/core/custom-module-cache.js +239 -0
- package/tools/cli/installers/lib/core/detector.js +8 -4
- package/tools/cli/installers/lib/core/installer.js +933 -376
- package/tools/cli/installers/lib/core/manifest-generator.js +265 -41
- package/tools/cli/installers/lib/core/manifest.js +47 -0
- package/tools/cli/installers/lib/core/post-install-sidecar-replacement.js +79 -0
- package/tools/cli/installers/lib/custom/handler.js +396 -0
- package/tools/cli/installers/lib/ide/_base-ide.js +10 -0
- package/tools/cli/installers/lib/ide/auggie.js +19 -7
- package/tools/cli/installers/lib/ide/crush.js +19 -6
- package/tools/cli/installers/lib/ide/cursor.js +29 -13
- package/tools/cli/installers/lib/ide/gemini.js +49 -1
- package/tools/cli/installers/lib/ide/iflow.js +20 -1
- package/tools/cli/installers/lib/ide/kiro-cli.js +327 -0
- package/tools/cli/installers/lib/ide/opencode.js +3 -3
- package/tools/cli/installers/lib/ide/roo.js +120 -184
- package/tools/cli/installers/lib/ide/rovo-dev.js +1 -1
- package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +8 -2
- package/tools/cli/installers/lib/ide/shared/bmad-artifacts.js +34 -19
- package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +18 -14
- package/tools/cli/installers/lib/ide/templates/agent-command-template.md +1 -1
- package/tools/cli/installers/lib/ide/templates/workflow-commander.md +5 -0
- package/tools/cli/installers/lib/modules/manager.js +535 -56
- package/tools/cli/lib/agent/compiler.js +57 -16
- package/tools/cli/lib/agent/installer.js +129 -28
- package/tools/cli/lib/cli-utils.js +21 -4
- package/tools/cli/lib/config.js +2 -1
- package/tools/cli/lib/ui.js +561 -12
- package/tools/cli/lib/yaml-xml-builder.js +0 -15
- package/tools/maintainer/review-pr-README.md +55 -0
- package/tools/maintainer/review-pr.md +242 -0
- package/tools/migrate-custom-module-paths.js +124 -0
- package/tools/schema/agent.js +149 -89
- package/tools/validate-svg-changes.sh +356 -0
- package/custom/src/agents/commit-poet/installation-guide.md +0 -36
- package/custom/src/agents/toolsmith/installation-guide.md +0 -36
- package/docs/custom-agent-installation.md +0 -183
- package/src/modules/bmb/docs/workflows/workflow-template.md +0 -152
- package/src/modules/bmb/workflows/create-workflow/steps/step-03-tools-overview.md +0 -127
- package/src/modules/bmb/workflows/create-workflow/steps/step-04-core-tools.md +0 -145
- package/src/modules/bmb/workflows/create-workflow/steps/step-05-memory-requirements.md +0 -136
- package/src/modules/bmb/workflows/create-workflow/steps/step-06-external-tools.md +0 -154
- package/src/modules/bmb/workflows/create-workflow/steps/step-07-installation-guidance.md +0 -159
- package/src/modules/bmb/workflows/create-workflow/steps/step-08-tools-summary.md +0 -167
- package/src/modules/bmb/workflows/create-workflow/steps/step-10-plan-review.md +0 -215
- package/src/modules/bmb/workflows/create-workflow/templates/build-summary.md +0 -36
- package/src/modules/bmb/workflows/create-workflow/templates/completion-section.md +0 -39
- package/src/modules/bmb/workflows/create-workflow/templates/content-template.md +0 -21
- package/src/modules/bmb/workflows/create-workflow/templates/design-section.md +0 -53
- package/src/modules/bmb/workflows/create-workflow/templates/project-info.md +0 -18
- package/src/modules/bmb/workflows/create-workflow/templates/requirements-section.md +0 -47
- package/src/modules/bmb/workflows/create-workflow/templates/review-section.md +0 -56
- package/src/modules/bmb/workflows/create-workflow/templates/workflow-plan.md +0 -54
- package/src/modules/bmb/workflows-legacy/create-module/README.md +0 -229
- package/src/modules/bmb/workflows-legacy/create-module/brainstorm-context.md +0 -137
- package/src/modules/bmb/workflows-legacy/create-module/checklist.md +0 -235
- package/src/modules/bmb/workflows-legacy/create-module/installer-templates/install-config.yaml +0 -92
- package/src/modules/bmb/workflows-legacy/create-module/installer-templates/installer.js +0 -231
- package/src/modules/bmb/workflows-legacy/create-module/instructions.md +0 -577
- package/src/modules/bmb/workflows-legacy/create-module/module-structure.md +0 -400
- package/src/modules/bmb/workflows-legacy/create-module/workflow.yaml +0 -52
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/epics-template.md +0 -80
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/instructions.md +0 -387
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.yaml +0 -53
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/checklist.md +0 -169
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/instructions.md +0 -332
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/template.md +0 -146
- package/src/modules/bmm/workflows/3-solutioning/implementation-readiness/workflow.yaml +0 -64
- package/tools/cli/commands/agent-install.js +0 -409
- package/tools/cli/commands/cleanup.js +0 -141
- /package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/knowledge/bundlers.md +0 -0
- /package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/knowledge/deploy.md +0 -0
- /package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/knowledge/tests.md +0 -0
- /package/src/modules/bmgd/{_module-installer/install-config.yaml → module.yaml} +0 -0
- /package/src/modules/cis/{_module-installer/install-config.yaml → module.yaml} +0 -0
|
@@ -22,11 +22,12 @@ const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/p
|
|
|
22
22
|
* await manager.install('core-module', '/path/to/bmad');
|
|
23
23
|
*/
|
|
24
24
|
class ModuleManager {
|
|
25
|
-
constructor() {
|
|
25
|
+
constructor(options = {}) {
|
|
26
26
|
// Path to source modules directory
|
|
27
27
|
this.modulesSourcePath = getSourcePath('modules');
|
|
28
28
|
this.xmlHandler = new XmlHandler();
|
|
29
29
|
this.bmadFolderName = 'bmad'; // Default, can be overridden
|
|
30
|
+
this.scanProjectForModules = options.scanProjectForModules !== false; // Default to true for backward compatibility
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -37,6 +38,14 @@ class ModuleManager {
|
|
|
37
38
|
this.bmadFolderName = bmadFolderName;
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Set the core configuration for access during module installation
|
|
43
|
+
* @param {Object} coreConfig - Core configuration object
|
|
44
|
+
*/
|
|
45
|
+
setCoreConfig(coreConfig) {
|
|
46
|
+
this.coreConfig = coreConfig;
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
/**
|
|
41
50
|
* Copy a file and replace {bmad_folder} placeholder with actual folder name
|
|
42
51
|
* @param {string} sourcePath - Source file path
|
|
@@ -53,6 +62,11 @@ class ModuleManager {
|
|
|
53
62
|
// Read the file content
|
|
54
63
|
let content = await fs.readFile(sourcePath, 'utf8');
|
|
55
64
|
|
|
65
|
+
// Replace escape sequence {*bmad_folder*} with literal {bmad_folder}
|
|
66
|
+
if (content.includes('{*bmad_folder*}')) {
|
|
67
|
+
content = content.replaceAll('{*bmad_folder*}', '{bmad_folder}');
|
|
68
|
+
}
|
|
69
|
+
|
|
56
70
|
// Replace {bmad_folder} placeholder with actual folder name
|
|
57
71
|
if (content.includes('{bmad_folder}')) {
|
|
58
72
|
content = content.replaceAll('{bmad_folder}', this.bmadFolderName);
|
|
@@ -93,62 +107,297 @@ class ModuleManager {
|
|
|
93
107
|
}
|
|
94
108
|
|
|
95
109
|
/**
|
|
96
|
-
*
|
|
97
|
-
* @returns {Array} List of
|
|
110
|
+
* Find all modules in the project by searching for module.yaml files
|
|
111
|
+
* @returns {Array} List of module paths
|
|
112
|
+
*/
|
|
113
|
+
async findModulesInProject() {
|
|
114
|
+
const projectRoot = getProjectRoot();
|
|
115
|
+
const modulePaths = new Set();
|
|
116
|
+
|
|
117
|
+
// Helper function to recursively scan directories
|
|
118
|
+
async function scanDirectory(dir, excludePaths = []) {
|
|
119
|
+
try {
|
|
120
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
121
|
+
|
|
122
|
+
for (const entry of entries) {
|
|
123
|
+
const fullPath = path.join(dir, entry.name);
|
|
124
|
+
|
|
125
|
+
// Skip hidden directories, node_modules, and literal placeholder directories
|
|
126
|
+
if (
|
|
127
|
+
entry.name.startsWith('.') ||
|
|
128
|
+
entry.name === 'node_modules' ||
|
|
129
|
+
entry.name === 'dist' ||
|
|
130
|
+
entry.name === 'build' ||
|
|
131
|
+
entry.name === '{project-root}'
|
|
132
|
+
) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Skip excluded paths
|
|
137
|
+
if (excludePaths.some((exclude) => fullPath.startsWith(exclude))) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (entry.isDirectory()) {
|
|
142
|
+
// Skip core module - it's always installed first and not selectable
|
|
143
|
+
if (entry.name === 'core') {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Check if this directory contains a module (module.yaml OR custom.yaml)
|
|
148
|
+
const moduleConfigPath = path.join(fullPath, 'module.yaml');
|
|
149
|
+
const installerConfigPath = path.join(fullPath, '_module-installer', 'module.yaml');
|
|
150
|
+
const customConfigPath = path.join(fullPath, '_module-installer', 'custom.yaml');
|
|
151
|
+
const rootCustomConfigPath = path.join(fullPath, 'custom.yaml');
|
|
152
|
+
|
|
153
|
+
if (
|
|
154
|
+
(await fs.pathExists(moduleConfigPath)) ||
|
|
155
|
+
(await fs.pathExists(installerConfigPath)) ||
|
|
156
|
+
(await fs.pathExists(customConfigPath)) ||
|
|
157
|
+
(await fs.pathExists(rootCustomConfigPath))
|
|
158
|
+
) {
|
|
159
|
+
modulePaths.add(fullPath);
|
|
160
|
+
// Don't scan inside modules - they might have their own nested structures
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Recursively scan subdirectories
|
|
165
|
+
await scanDirectory(fullPath, excludePaths);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
// Ignore errors (e.g., permission denied)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Scan the entire project, but exclude src/modules since we handle it separately
|
|
174
|
+
await scanDirectory(projectRoot, [this.modulesSourcePath]);
|
|
175
|
+
|
|
176
|
+
return [...modulePaths];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* List all available modules (excluding core which is always installed)
|
|
181
|
+
* @returns {Object} Object with modules array and customModules array
|
|
98
182
|
*/
|
|
99
183
|
async listAvailable() {
|
|
100
184
|
const modules = [];
|
|
185
|
+
const customModules = [];
|
|
186
|
+
|
|
187
|
+
// First, scan src/modules (the standard location)
|
|
188
|
+
if (await fs.pathExists(this.modulesSourcePath)) {
|
|
189
|
+
const entries = await fs.readdir(this.modulesSourcePath, { withFileTypes: true });
|
|
190
|
+
|
|
191
|
+
for (const entry of entries) {
|
|
192
|
+
if (entry.isDirectory()) {
|
|
193
|
+
const modulePath = path.join(this.modulesSourcePath, entry.name);
|
|
194
|
+
// Check for module structure (module.yaml OR custom.yaml)
|
|
195
|
+
const moduleConfigPath = path.join(modulePath, 'module.yaml');
|
|
196
|
+
const installerConfigPath = path.join(modulePath, '_module-installer', 'module.yaml');
|
|
197
|
+
const customConfigPath = path.join(modulePath, '_module-installer', 'custom.yaml');
|
|
198
|
+
|
|
199
|
+
// Skip if this doesn't look like a module
|
|
200
|
+
if (
|
|
201
|
+
!(await fs.pathExists(moduleConfigPath)) &&
|
|
202
|
+
!(await fs.pathExists(installerConfigPath)) &&
|
|
203
|
+
!(await fs.pathExists(customConfigPath))
|
|
204
|
+
) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
101
207
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
208
|
+
// Skip core module - it's always installed first and not selectable
|
|
209
|
+
if (entry.name === 'core') {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const moduleInfo = await this.getModuleInfo(modulePath, entry.name, 'src/modules');
|
|
214
|
+
if (moduleInfo) {
|
|
215
|
+
modules.push(moduleInfo);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
105
219
|
}
|
|
106
220
|
|
|
107
|
-
|
|
221
|
+
// Then, find all other modules in the project (only if scanning is enabled)
|
|
222
|
+
if (this.scanProjectForModules) {
|
|
223
|
+
const otherModulePaths = await this.findModulesInProject();
|
|
224
|
+
for (const modulePath of otherModulePaths) {
|
|
225
|
+
const moduleName = path.basename(modulePath);
|
|
226
|
+
const relativePath = path.relative(getProjectRoot(), modulePath);
|
|
108
227
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const installerConfigPath = path.join(modulePath, '_module-installer', 'install-config.yaml');
|
|
114
|
-
// Fallback to old structure
|
|
115
|
-
const configPath = path.join(modulePath, 'config.yaml');
|
|
116
|
-
|
|
117
|
-
const moduleInfo = {
|
|
118
|
-
id: entry.name,
|
|
119
|
-
path: modulePath,
|
|
120
|
-
name: entry.name.toUpperCase(),
|
|
121
|
-
description: 'BMAD Module',
|
|
122
|
-
version: '5.0.0',
|
|
123
|
-
};
|
|
228
|
+
// Skip core module - it's always installed first and not selectable
|
|
229
|
+
if (moduleName === 'core') {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
124
232
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
233
|
+
const moduleInfo = await this.getModuleInfo(modulePath, moduleName, relativePath);
|
|
234
|
+
if (moduleInfo && !modules.some((m) => m.id === moduleInfo.id) && !customModules.some((m) => m.id === moduleInfo.id)) {
|
|
235
|
+
// Avoid duplicates - skip if we already have this module ID
|
|
236
|
+
if (moduleInfo.isCustom) {
|
|
237
|
+
customModules.push(moduleInfo);
|
|
238
|
+
} else {
|
|
239
|
+
modules.push(moduleInfo);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
131
243
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
244
|
+
// Also check for cached custom modules in _cfg/custom/
|
|
245
|
+
if (this.bmadDir) {
|
|
246
|
+
const customCacheDir = path.join(this.bmadDir, '_cfg', 'custom');
|
|
247
|
+
if (await fs.pathExists(customCacheDir)) {
|
|
248
|
+
const cacheEntries = await fs.readdir(customCacheDir, { withFileTypes: true });
|
|
249
|
+
for (const entry of cacheEntries) {
|
|
250
|
+
if (entry.isDirectory()) {
|
|
251
|
+
const cachePath = path.join(customCacheDir, entry.name);
|
|
252
|
+
const moduleInfo = await this.getModuleInfo(cachePath, entry.name, '_cfg/custom');
|
|
253
|
+
if (moduleInfo && !modules.some((m) => m.id === moduleInfo.id) && !customModules.some((m) => m.id === moduleInfo.id)) {
|
|
254
|
+
moduleInfo.isCustom = true;
|
|
255
|
+
moduleInfo.fromCache = true;
|
|
256
|
+
customModules.push(moduleInfo);
|
|
257
|
+
}
|
|
135
258
|
}
|
|
136
|
-
|
|
137
|
-
moduleInfo.name = config.name || moduleInfo.name;
|
|
138
|
-
moduleInfo.description = config.description || moduleInfo.description;
|
|
139
|
-
moduleInfo.version = config.version || moduleInfo.version;
|
|
140
|
-
moduleInfo.dependencies = config.dependencies || [];
|
|
141
|
-
moduleInfo.defaultSelected = config.default_selected === undefined ? false : config.default_selected;
|
|
142
|
-
} catch (error) {
|
|
143
|
-
console.warn(`Failed to read config for ${entry.name}:`, error.message);
|
|
144
259
|
}
|
|
145
260
|
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return { modules, customModules };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Get module information from a module path
|
|
269
|
+
* @param {string} modulePath - Path to the module directory
|
|
270
|
+
* @param {string} defaultName - Default name for the module
|
|
271
|
+
* @param {string} sourceDescription - Description of where the module was found
|
|
272
|
+
* @returns {Object|null} Module info or null if not a valid module
|
|
273
|
+
*/
|
|
274
|
+
async getModuleInfo(modulePath, defaultName, sourceDescription) {
|
|
275
|
+
// Check for module structure (module.yaml OR custom.yaml)
|
|
276
|
+
const moduleConfigPath = path.join(modulePath, 'module.yaml');
|
|
277
|
+
const installerConfigPath = path.join(modulePath, '_module-installer', 'module.yaml');
|
|
278
|
+
const customConfigPath = path.join(modulePath, '_module-installer', 'custom.yaml');
|
|
279
|
+
const rootCustomConfigPath = path.join(modulePath, 'custom.yaml');
|
|
280
|
+
let configPath = null;
|
|
281
|
+
|
|
282
|
+
if (await fs.pathExists(moduleConfigPath)) {
|
|
283
|
+
configPath = moduleConfigPath;
|
|
284
|
+
} else if (await fs.pathExists(installerConfigPath)) {
|
|
285
|
+
configPath = installerConfigPath;
|
|
286
|
+
} else if (await fs.pathExists(customConfigPath)) {
|
|
287
|
+
configPath = customConfigPath;
|
|
288
|
+
} else if (await fs.pathExists(rootCustomConfigPath)) {
|
|
289
|
+
configPath = rootCustomConfigPath;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Skip if this doesn't look like a module
|
|
293
|
+
if (!configPath) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Mark as custom if it's using custom.yaml OR if it's outside src/modules
|
|
298
|
+
const isCustomSource = sourceDescription !== 'src/modules';
|
|
299
|
+
const moduleInfo = {
|
|
300
|
+
id: defaultName,
|
|
301
|
+
path: modulePath,
|
|
302
|
+
name: defaultName
|
|
303
|
+
.split('-')
|
|
304
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
305
|
+
.join(' '),
|
|
306
|
+
description: 'BMAD Module',
|
|
307
|
+
version: '5.0.0',
|
|
308
|
+
source: sourceDescription,
|
|
309
|
+
isCustom: configPath === customConfigPath || configPath === rootCustomConfigPath || isCustomSource,
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// Read module config for metadata
|
|
313
|
+
try {
|
|
314
|
+
const configContent = await fs.readFile(configPath, 'utf8');
|
|
315
|
+
const config = yaml.load(configContent);
|
|
316
|
+
|
|
317
|
+
// Use the code property as the id if available
|
|
318
|
+
if (config.code) {
|
|
319
|
+
moduleInfo.id = config.code;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
moduleInfo.name = config.name || moduleInfo.name;
|
|
323
|
+
moduleInfo.description = config.description || moduleInfo.description;
|
|
324
|
+
moduleInfo.version = config.version || moduleInfo.version;
|
|
325
|
+
moduleInfo.dependencies = config.dependencies || [];
|
|
326
|
+
moduleInfo.defaultSelected = config.default_selected === undefined ? false : config.default_selected;
|
|
327
|
+
} catch (error) {
|
|
328
|
+
console.warn(`Failed to read config for ${defaultName}:`, error.message);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return moduleInfo;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Find the source path for a module by searching all possible locations
|
|
336
|
+
* @param {string} moduleName - Name of the module to find
|
|
337
|
+
* @returns {string|null} Path to the module source or null if not found
|
|
338
|
+
*/
|
|
339
|
+
async findModuleSource(moduleName) {
|
|
340
|
+
const projectRoot = getProjectRoot();
|
|
341
|
+
|
|
342
|
+
// First, check src/modules
|
|
343
|
+
const srcModulePath = path.join(this.modulesSourcePath, moduleName);
|
|
344
|
+
if (await fs.pathExists(srcModulePath)) {
|
|
345
|
+
// Check if this looks like a module (has module.yaml)
|
|
346
|
+
const moduleConfigPath = path.join(srcModulePath, 'module.yaml');
|
|
347
|
+
const installerConfigPath = path.join(srcModulePath, '_module-installer', 'module.yaml');
|
|
348
|
+
|
|
349
|
+
if ((await fs.pathExists(moduleConfigPath)) || (await fs.pathExists(installerConfigPath))) {
|
|
350
|
+
return srcModulePath;
|
|
351
|
+
}
|
|
146
352
|
|
|
147
|
-
|
|
353
|
+
// Also check for custom.yaml in src/modules/_module-installer
|
|
354
|
+
const customConfigPath = path.join(srcModulePath, '_module-installer', 'custom.yaml');
|
|
355
|
+
if (await fs.pathExists(customConfigPath)) {
|
|
356
|
+
return srcModulePath;
|
|
148
357
|
}
|
|
149
358
|
}
|
|
150
359
|
|
|
151
|
-
|
|
360
|
+
// If not found in src/modules, search the entire project
|
|
361
|
+
const allModulePaths = await this.findModulesInProject();
|
|
362
|
+
for (const modulePath of allModulePaths) {
|
|
363
|
+
if (path.basename(modulePath) === moduleName) {
|
|
364
|
+
return modulePath;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Also check by module ID (not just folder name)
|
|
369
|
+
// Need to read configs to match by ID
|
|
370
|
+
for (const modulePath of allModulePaths) {
|
|
371
|
+
const moduleConfigPath = path.join(modulePath, 'module.yaml');
|
|
372
|
+
const installerConfigPath = path.join(modulePath, '_module-installer', 'module.yaml');
|
|
373
|
+
const customConfigPath = path.join(modulePath, '_module-installer', 'custom.yaml');
|
|
374
|
+
const rootCustomConfigPath = path.join(modulePath, 'custom.yaml');
|
|
375
|
+
|
|
376
|
+
let configPath = null;
|
|
377
|
+
if (await fs.pathExists(moduleConfigPath)) {
|
|
378
|
+
configPath = moduleConfigPath;
|
|
379
|
+
} else if (await fs.pathExists(installerConfigPath)) {
|
|
380
|
+
configPath = installerConfigPath;
|
|
381
|
+
} else if (await fs.pathExists(customConfigPath)) {
|
|
382
|
+
configPath = customConfigPath;
|
|
383
|
+
} else if (await fs.pathExists(rootCustomConfigPath)) {
|
|
384
|
+
configPath = rootCustomConfigPath;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if (configPath) {
|
|
388
|
+
try {
|
|
389
|
+
const configContent = await fs.readFile(configPath, 'utf8');
|
|
390
|
+
const config = yaml.load(configContent);
|
|
391
|
+
if (config.code === moduleName) {
|
|
392
|
+
return modulePath;
|
|
393
|
+
}
|
|
394
|
+
} catch {
|
|
395
|
+
// Skip if can't read config
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return null;
|
|
152
401
|
}
|
|
153
402
|
|
|
154
403
|
/**
|
|
@@ -162,12 +411,41 @@ class ModuleManager {
|
|
|
162
411
|
* @param {Object} options.logger - Logger instance for output
|
|
163
412
|
*/
|
|
164
413
|
async install(moduleName, bmadDir, fileTrackingCallback = null, options = {}) {
|
|
165
|
-
const sourcePath =
|
|
414
|
+
const sourcePath = await this.findModuleSource(moduleName);
|
|
166
415
|
const targetPath = path.join(bmadDir, moduleName);
|
|
167
416
|
|
|
168
417
|
// Check if source module exists
|
|
169
|
-
if (!
|
|
170
|
-
throw new Error(`Module '${moduleName}' not found in
|
|
418
|
+
if (!sourcePath) {
|
|
419
|
+
throw new Error(`Module '${moduleName}' not found in any source location`);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Check if this is a custom module and read its custom.yaml values
|
|
423
|
+
let customConfig = null;
|
|
424
|
+
const rootCustomConfigPath = path.join(sourcePath, 'custom.yaml');
|
|
425
|
+
const moduleInstallerCustomPath = path.join(sourcePath, '_module-installer', 'custom.yaml');
|
|
426
|
+
|
|
427
|
+
if (await fs.pathExists(rootCustomConfigPath)) {
|
|
428
|
+
try {
|
|
429
|
+
const customContent = await fs.readFile(rootCustomConfigPath, 'utf8');
|
|
430
|
+
customConfig = yaml.load(customContent);
|
|
431
|
+
} catch (error) {
|
|
432
|
+
console.warn(chalk.yellow(`Warning: Failed to read custom.yaml for ${moduleName}:`, error.message));
|
|
433
|
+
}
|
|
434
|
+
} else if (await fs.pathExists(moduleInstallerCustomPath)) {
|
|
435
|
+
try {
|
|
436
|
+
const customContent = await fs.readFile(moduleInstallerCustomPath, 'utf8');
|
|
437
|
+
customConfig = yaml.load(customContent);
|
|
438
|
+
} catch (error) {
|
|
439
|
+
console.warn(chalk.yellow(`Warning: Failed to read custom.yaml for ${moduleName}:`, error.message));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// If this is a custom module, merge its values into the module config
|
|
444
|
+
if (customConfig) {
|
|
445
|
+
options.moduleConfig = { ...options.moduleConfig, ...customConfig };
|
|
446
|
+
if (options.logger) {
|
|
447
|
+
options.logger.log(chalk.cyan(` Merged custom configuration for ${moduleName}`));
|
|
448
|
+
}
|
|
171
449
|
}
|
|
172
450
|
|
|
173
451
|
// Check if already installed
|
|
@@ -183,6 +461,9 @@ class ModuleManager {
|
|
|
183
461
|
// Copy module files with filtering
|
|
184
462
|
await this.copyModuleWithFiltering(sourcePath, targetPath, fileTrackingCallback, options.moduleConfig);
|
|
185
463
|
|
|
464
|
+
// Compile any .agent.yaml files to .md format
|
|
465
|
+
await this.compileModuleAgents(sourcePath, targetPath, moduleName, bmadDir);
|
|
466
|
+
|
|
186
467
|
// Process agent files to inject activation block
|
|
187
468
|
await this.processAgentFiles(targetPath, moduleName);
|
|
188
469
|
|
|
@@ -205,12 +486,12 @@ class ModuleManager {
|
|
|
205
486
|
* @param {boolean} force - Force update (overwrite modifications)
|
|
206
487
|
*/
|
|
207
488
|
async update(moduleName, bmadDir, force = false) {
|
|
208
|
-
const sourcePath =
|
|
489
|
+
const sourcePath = await this.findModuleSource(moduleName);
|
|
209
490
|
const targetPath = path.join(bmadDir, moduleName);
|
|
210
491
|
|
|
211
492
|
// Check if source module exists
|
|
212
|
-
if (!
|
|
213
|
-
throw new Error(`Module '${moduleName}' not found in source`);
|
|
493
|
+
if (!sourcePath) {
|
|
494
|
+
throw new Error(`Module '${moduleName}' not found in any source location`);
|
|
214
495
|
}
|
|
215
496
|
|
|
216
497
|
// Check if module is installed
|
|
@@ -325,13 +606,29 @@ class ModuleManager {
|
|
|
325
606
|
continue;
|
|
326
607
|
}
|
|
327
608
|
|
|
609
|
+
// Skip sidecar directories - they are handled separately during agent compilation
|
|
610
|
+
if (
|
|
611
|
+
path
|
|
612
|
+
.dirname(file)
|
|
613
|
+
.split('/')
|
|
614
|
+
.some((dir) => dir.toLowerCase().includes('sidecar'))
|
|
615
|
+
) {
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
|
|
328
619
|
// Skip _module-installer directory - it's only needed at install time
|
|
329
|
-
if (file.startsWith('_module-installer/')) {
|
|
620
|
+
if (file.startsWith('_module-installer/') || file === 'module.yaml') {
|
|
330
621
|
continue;
|
|
331
622
|
}
|
|
332
623
|
|
|
333
624
|
// Skip config.yaml templates - we'll generate clean ones with actual values
|
|
334
|
-
|
|
625
|
+
// Also skip custom.yaml files - their values will be merged into core config
|
|
626
|
+
if (file === 'config.yaml' || file.endsWith('/config.yaml') || file === 'custom.yaml' || file.endsWith('/custom.yaml')) {
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Skip .agent.yaml files - they will be compiled separately
|
|
631
|
+
if (file.endsWith('.agent.yaml')) {
|
|
335
632
|
continue;
|
|
336
633
|
}
|
|
337
634
|
|
|
@@ -396,8 +693,9 @@ class ModuleManager {
|
|
|
396
693
|
// Read the source YAML file
|
|
397
694
|
let yamlContent = await fs.readFile(sourceFile, 'utf8');
|
|
398
695
|
|
|
399
|
-
// IMPORTANT: Replace
|
|
696
|
+
// IMPORTANT: Replace escape sequence and placeholder BEFORE parsing YAML
|
|
400
697
|
// Otherwise parsing will fail on the placeholder
|
|
698
|
+
yamlContent = yamlContent.replaceAll('{*bmad_folder*}', '{bmad_folder}');
|
|
401
699
|
yamlContent = yamlContent.replaceAll('{bmad_folder}', this.bmadFolderName);
|
|
402
700
|
|
|
403
701
|
try {
|
|
@@ -476,6 +774,157 @@ class ModuleManager {
|
|
|
476
774
|
}
|
|
477
775
|
}
|
|
478
776
|
|
|
777
|
+
/**
|
|
778
|
+
* Compile .agent.yaml files to .md format in modules
|
|
779
|
+
* @param {string} sourcePath - Source module path
|
|
780
|
+
* @param {string} targetPath - Target module path
|
|
781
|
+
* @param {string} moduleName - Module name
|
|
782
|
+
* @param {string} bmadDir - BMAD installation directory
|
|
783
|
+
*/
|
|
784
|
+
async compileModuleAgents(sourcePath, targetPath, moduleName, bmadDir) {
|
|
785
|
+
const sourceAgentsPath = path.join(sourcePath, 'agents');
|
|
786
|
+
const targetAgentsPath = path.join(targetPath, 'agents');
|
|
787
|
+
const cfgAgentsDir = path.join(bmadDir, '_cfg', 'agents');
|
|
788
|
+
|
|
789
|
+
// Check if agents directory exists in source
|
|
790
|
+
if (!(await fs.pathExists(sourceAgentsPath))) {
|
|
791
|
+
return; // No agents to compile
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// Get all agent YAML files recursively
|
|
795
|
+
const agentFiles = await this.findAgentFiles(sourceAgentsPath);
|
|
796
|
+
|
|
797
|
+
for (const agentFile of agentFiles) {
|
|
798
|
+
if (!agentFile.endsWith('.agent.yaml')) continue;
|
|
799
|
+
|
|
800
|
+
const relativePath = path.relative(sourceAgentsPath, agentFile);
|
|
801
|
+
const targetDir = path.join(targetAgentsPath, path.dirname(relativePath));
|
|
802
|
+
|
|
803
|
+
await fs.ensureDir(targetDir);
|
|
804
|
+
|
|
805
|
+
const agentName = path.basename(agentFile, '.agent.yaml');
|
|
806
|
+
const sourceYamlPath = agentFile;
|
|
807
|
+
const targetMdPath = path.join(targetDir, `${agentName}.md`);
|
|
808
|
+
const customizePath = path.join(cfgAgentsDir, `${moduleName}-${agentName}.customize.yaml`);
|
|
809
|
+
|
|
810
|
+
// Read and compile the YAML
|
|
811
|
+
try {
|
|
812
|
+
const yamlContent = await fs.readFile(sourceYamlPath, 'utf8');
|
|
813
|
+
const { compileAgent } = require('../../../lib/agent/compiler');
|
|
814
|
+
|
|
815
|
+
// Create customize template if it doesn't exist
|
|
816
|
+
if (!(await fs.pathExists(customizePath))) {
|
|
817
|
+
const { getSourcePath } = require('../../../lib/project-root');
|
|
818
|
+
const genericTemplatePath = getSourcePath('utility', 'templates', 'agent.customize.template.yaml');
|
|
819
|
+
if (await fs.pathExists(genericTemplatePath)) {
|
|
820
|
+
await this.copyFileWithPlaceholderReplacement(genericTemplatePath, customizePath);
|
|
821
|
+
console.log(chalk.dim(` Created customize: ${moduleName}-${agentName}.customize.yaml`));
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Check for customizations
|
|
826
|
+
let customizedFields = [];
|
|
827
|
+
if (await fs.pathExists(customizePath)) {
|
|
828
|
+
const customizeContent = await fs.readFile(customizePath, 'utf8');
|
|
829
|
+
const customizeData = yaml.load(customizeContent);
|
|
830
|
+
customizedFields = customizeData.customized_fields || [];
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// Load core config to get agent_sidecar_folder
|
|
834
|
+
const coreConfigPath = path.join(bmadDir, 'bmb', 'config.yaml');
|
|
835
|
+
let coreConfig = {};
|
|
836
|
+
|
|
837
|
+
if (await fs.pathExists(coreConfigPath)) {
|
|
838
|
+
const yamlLib = require('yaml');
|
|
839
|
+
const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8');
|
|
840
|
+
coreConfig = yamlLib.parse(coreConfigContent);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// Check if agent has sidecar
|
|
844
|
+
let hasSidecar = false;
|
|
845
|
+
try {
|
|
846
|
+
const yamlLib = require('yaml');
|
|
847
|
+
const agentYaml = yamlLib.parse(yamlContent);
|
|
848
|
+
hasSidecar = agentYaml?.agent?.metadata?.hasSidecar === true;
|
|
849
|
+
} catch {
|
|
850
|
+
// Continue without sidecar processing
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// Compile with customizations if any
|
|
854
|
+
const { xml } = compileAgent(yamlContent, {}, agentName, relativePath, { config: this.coreConfig });
|
|
855
|
+
|
|
856
|
+
// Replace {bmad_folder} placeholder if needed
|
|
857
|
+
if (xml.includes('{bmad_folder}') && this.bmadFolderName) {
|
|
858
|
+
const processedXml = xml.replaceAll('{bmad_folder}', this.bmadFolderName);
|
|
859
|
+
await fs.writeFile(targetMdPath, processedXml, 'utf8');
|
|
860
|
+
} else {
|
|
861
|
+
await fs.writeFile(targetMdPath, xml, 'utf8');
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// Copy sidecar files if agent has hasSidecar flag
|
|
865
|
+
if (hasSidecar) {
|
|
866
|
+
const { copyAgentSidecarFiles } = require('../../../lib/agent/installer');
|
|
867
|
+
|
|
868
|
+
// Get agent sidecar folder from core config (should always be set)
|
|
869
|
+
const agentSidecarFolder = this.coreConfig?.agent_sidecar_folder;
|
|
870
|
+
|
|
871
|
+
// Resolve path variables
|
|
872
|
+
const projectDir = path.dirname(bmadDir);
|
|
873
|
+
const resolvedSidecarFolder = agentSidecarFolder
|
|
874
|
+
.replaceAll('{project-root}', projectDir)
|
|
875
|
+
.replaceAll('{bmad_folder}', path.basename(bmadDir));
|
|
876
|
+
|
|
877
|
+
// Create sidecar directory for this agent
|
|
878
|
+
const agentSidecarDir = path.join(resolvedSidecarFolder, agentName);
|
|
879
|
+
await fs.ensureDir(agentSidecarDir);
|
|
880
|
+
|
|
881
|
+
// Copy sidecar files (preserve existing, add new)
|
|
882
|
+
const sidecarResult = copyAgentSidecarFiles(path.dirname(sourceYamlPath), agentSidecarDir, sourceYamlPath);
|
|
883
|
+
const totalFiles = sidecarResult.copied.length + sidecarResult.preserved.length;
|
|
884
|
+
|
|
885
|
+
if (sidecarResult.copied.length > 0) {
|
|
886
|
+
console.log(chalk.dim(` Copied ${sidecarResult.copied.length} new sidecar file(s) to: ${agentSidecarDir}`));
|
|
887
|
+
}
|
|
888
|
+
if (sidecarResult.preserved.length > 0) {
|
|
889
|
+
console.log(chalk.dim(` Preserved ${sidecarResult.preserved.length} existing sidecar file(s)`));
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
console.log(
|
|
894
|
+
chalk.dim(` Compiled agent: ${agentName} -> ${path.relative(targetPath, targetMdPath)}${hasSidecar ? ' (with sidecar)' : ''}`),
|
|
895
|
+
);
|
|
896
|
+
} catch (error) {
|
|
897
|
+
console.warn(chalk.yellow(` Failed to compile agent ${agentName}:`, error.message));
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Find all .agent.yaml files recursively in a directory
|
|
904
|
+
* @param {string} dir - Directory to search
|
|
905
|
+
* @returns {Array} List of .agent.yaml file paths
|
|
906
|
+
*/
|
|
907
|
+
async findAgentFiles(dir) {
|
|
908
|
+
const agentFiles = [];
|
|
909
|
+
|
|
910
|
+
async function searchDirectory(searchDir) {
|
|
911
|
+
const entries = await fs.readdir(searchDir, { withFileTypes: true });
|
|
912
|
+
|
|
913
|
+
for (const entry of entries) {
|
|
914
|
+
const fullPath = path.join(searchDir, entry.name);
|
|
915
|
+
|
|
916
|
+
if (entry.isFile() && entry.name.endsWith('.agent.yaml')) {
|
|
917
|
+
agentFiles.push(fullPath);
|
|
918
|
+
} else if (entry.isDirectory()) {
|
|
919
|
+
await searchDirectory(fullPath);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
await searchDirectory(dir);
|
|
925
|
+
return agentFiles;
|
|
926
|
+
}
|
|
927
|
+
|
|
479
928
|
/**
|
|
480
929
|
* Process agent files to inject activation block
|
|
481
930
|
* @param {string} modulePath - Path to installed module
|
|
@@ -489,24 +938,49 @@ class ModuleManager {
|
|
|
489
938
|
return; // No agents to process
|
|
490
939
|
}
|
|
491
940
|
|
|
492
|
-
// Get all agent files
|
|
493
|
-
const agentFiles = await
|
|
941
|
+
// Get all agent MD files recursively
|
|
942
|
+
const agentFiles = await this.findAgentMdFiles(agentsPath);
|
|
494
943
|
|
|
495
944
|
for (const agentFile of agentFiles) {
|
|
496
945
|
if (!agentFile.endsWith('.md')) continue;
|
|
497
946
|
|
|
498
|
-
|
|
499
|
-
let content = await fs.readFile(agentPath, 'utf8');
|
|
947
|
+
let content = await fs.readFile(agentFile, 'utf8');
|
|
500
948
|
|
|
501
949
|
// Check if content has agent XML and no activation block
|
|
502
950
|
if (content.includes('<agent') && !content.includes('<activation')) {
|
|
503
951
|
// Inject the activation block using XML handler
|
|
504
952
|
content = this.xmlHandler.injectActivationSimple(content);
|
|
505
|
-
await fs.writeFile(
|
|
953
|
+
await fs.writeFile(agentFile, content, 'utf8');
|
|
506
954
|
}
|
|
507
955
|
}
|
|
508
956
|
}
|
|
509
957
|
|
|
958
|
+
/**
|
|
959
|
+
* Find all .md agent files recursively in a directory
|
|
960
|
+
* @param {string} dir - Directory to search
|
|
961
|
+
* @returns {Array} List of .md agent file paths
|
|
962
|
+
*/
|
|
963
|
+
async findAgentMdFiles(dir) {
|
|
964
|
+
const agentFiles = [];
|
|
965
|
+
|
|
966
|
+
async function searchDirectory(searchDir) {
|
|
967
|
+
const entries = await fs.readdir(searchDir, { withFileTypes: true });
|
|
968
|
+
|
|
969
|
+
for (const entry of entries) {
|
|
970
|
+
const fullPath = path.join(searchDir, entry.name);
|
|
971
|
+
|
|
972
|
+
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
973
|
+
agentFiles.push(fullPath);
|
|
974
|
+
} else if (entry.isDirectory()) {
|
|
975
|
+
await searchDirectory(fullPath);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
await searchDirectory(dir);
|
|
981
|
+
return agentFiles;
|
|
982
|
+
}
|
|
983
|
+
|
|
510
984
|
/**
|
|
511
985
|
* Vendor cross-module workflows referenced in agent files
|
|
512
986
|
* Scans SOURCE agent.yaml files for workflow-install and copies workflows to destination
|
|
@@ -648,7 +1122,11 @@ class ModuleManager {
|
|
|
648
1122
|
if (moduleName === 'core') {
|
|
649
1123
|
sourcePath = getSourcePath('core');
|
|
650
1124
|
} else {
|
|
651
|
-
sourcePath =
|
|
1125
|
+
sourcePath = await this.findModuleSource(moduleName);
|
|
1126
|
+
if (!sourcePath) {
|
|
1127
|
+
// No source found, skip module installer
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
652
1130
|
}
|
|
653
1131
|
|
|
654
1132
|
const installerPath = path.join(sourcePath, '_module-installer', 'installer.js');
|
|
@@ -677,6 +1155,7 @@ class ModuleManager {
|
|
|
677
1155
|
const result = await moduleInstaller.install({
|
|
678
1156
|
projectRoot,
|
|
679
1157
|
config: options.moduleConfig || {},
|
|
1158
|
+
coreConfig: options.coreConfig || {},
|
|
680
1159
|
installedIDEs: options.installedIDEs || [],
|
|
681
1160
|
logger,
|
|
682
1161
|
});
|