bmad-method 6.0.0-alpha.13 → 6.0.0-alpha.14
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/.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 +95 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/bmad-method-6.0.0-alpha.14.tgz +0 -0
- package/docs/agent-customization-guide.md +2 -2
- package/docs/custom-agent-installation.md +56 -102
- package/docs/document-sharding-guide.md +1 -1
- package/eslint.config.mjs +14 -0
- package/example-custom-content/README.md +4 -0
- package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/instructions.md +4 -4
- 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 +17 -16
- package/example-custom-content/custom.yaml +3 -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-plan-quiz-master.md +269 -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 +4 -0
- package/example-custom-module/mwm/_module-installer/install-config.yaml +27 -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 +150 -0
- package/example-custom-module/mwm/agents/crisis-navigator.agent.yaml +137 -0
- package/example-custom-module/mwm/agents/meditation-guide.agent.yaml +137 -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 +124 -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/install-config.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/install-config.yaml +4 -9
- 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/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/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 +308 -0
- package/src/modules/bmb/workflows/create-module/steps/step-10-roadmap.md +336 -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/install-config.template.yaml +53 -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/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} +70 -24
- 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/workflows/3-technical/game-architecture/instructions.md +8 -8
- package/src/modules/bmm/_module-installer/install-config.yaml +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/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/tools/cli/README.md +3 -3
- 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 +70 -10
- package/tools/cli/installers/lib/core/installer.js +153 -388
- package/tools/cli/installers/lib/core/manifest-generator.js +91 -30
- package/tools/cli/installers/lib/core/post-install-sidecar-replacement.js +79 -0
- package/tools/cli/installers/lib/custom/handler.js +266 -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 +486 -53
- package/tools/cli/lib/agent/compiler.js +54 -5
- package/tools/cli/lib/agent/installer.js +127 -27
- package/tools/cli/lib/config.js +2 -1
- package/tools/cli/lib/ui.js +65 -4
- package/tools/cli/lib/yaml-xml-builder.js +0 -15
- 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/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/commit-poet/commit-poet.agent.yaml +0 -0
- /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/docs.md +0 -0
- /package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/knowledge/installers.md +0 -0
- /package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/knowledge/modules.md +0 -0
- /package/{custom/src → example-custom-content}/agents/toolsmith/toolsmith-sidecar/knowledge/tests.md +0 -0
|
@@ -37,6 +37,7 @@ const { AgentPartyGenerator } = require('../../../lib/agent-party-generator');
|
|
|
37
37
|
const { CLIUtils } = require('../../../lib/cli-utils');
|
|
38
38
|
const { ManifestGenerator } = require('./manifest-generator');
|
|
39
39
|
const { IdeConfigManager } = require('./ide-config-manager');
|
|
40
|
+
const { replaceAgentSidecarFolders } = require('./post-install-sidecar-replacement');
|
|
40
41
|
|
|
41
42
|
class Installer {
|
|
42
43
|
constructor() {
|
|
@@ -51,6 +52,7 @@ class Installer {
|
|
|
51
52
|
this.configCollector = new ConfigCollector();
|
|
52
53
|
this.ideConfigManager = new IdeConfigManager();
|
|
53
54
|
this.installedFiles = []; // Track all installed files
|
|
55
|
+
this.ttsInjectedFiles = []; // Track files with TTS injection applied
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
/**
|
|
@@ -141,8 +143,13 @@ class Installer {
|
|
|
141
143
|
content = content.replaceAll('{bmad_folder}', bmadFolderName);
|
|
142
144
|
}
|
|
143
145
|
|
|
144
|
-
//
|
|
145
|
-
content
|
|
146
|
+
// Replace escape sequence {*bmad_folder*} with literal {bmad_folder}
|
|
147
|
+
if (content.includes('{*bmad_folder*}')) {
|
|
148
|
+
content = content.replaceAll('{*bmad_folder*}', '{bmad_folder}');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Process AgentVibes injection points (pass targetPath for tracking)
|
|
152
|
+
content = this.processTTSInjectionPoints(content, targetPath);
|
|
146
153
|
|
|
147
154
|
// Write to target with replaced content
|
|
148
155
|
await fs.ensureDir(path.dirname(targetPath));
|
|
@@ -221,10 +228,14 @@ class Installer {
|
|
|
221
228
|
* - src/modules/bmm/agents/*.md (rules sections)
|
|
222
229
|
* - TTS Hook: .claude/hooks/bmad-speak.sh (in AgentVibes repo)
|
|
223
230
|
*/
|
|
224
|
-
processTTSInjectionPoints(content) {
|
|
231
|
+
processTTSInjectionPoints(content, targetPath = null) {
|
|
225
232
|
// Check if AgentVibes is enabled (set during installation configuration)
|
|
226
233
|
const enableAgentVibes = this.enableAgentVibes || false;
|
|
227
234
|
|
|
235
|
+
// Check if content contains any TTS injection markers
|
|
236
|
+
const hasPartyMode = content.includes('<!-- TTS_INJECTION:party-mode -->');
|
|
237
|
+
const hasAgentTTS = content.includes('<!-- TTS_INJECTION:agent-tts -->');
|
|
238
|
+
|
|
228
239
|
if (enableAgentVibes) {
|
|
229
240
|
// Replace party-mode injection marker with actual TTS call
|
|
230
241
|
// Use single quotes to prevent shell expansion of special chars like !
|
|
@@ -248,6 +259,12 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
248
259
|
IMPORTANT: Use single quotes as shown - do NOT escape special characters like ! or $ inside single quotes
|
|
249
260
|
Run in background (&) to avoid blocking`,
|
|
250
261
|
);
|
|
262
|
+
|
|
263
|
+
// Track files that had TTS injection applied
|
|
264
|
+
if (targetPath && (hasPartyMode || hasAgentTTS)) {
|
|
265
|
+
const injectionType = hasPartyMode ? 'party-mode' : 'agent-tts';
|
|
266
|
+
this.ttsInjectedFiles.push({ path: targetPath, type: injectionType });
|
|
267
|
+
}
|
|
251
268
|
} else {
|
|
252
269
|
// Strip injection markers cleanly when AgentVibes is disabled
|
|
253
270
|
content = content.replaceAll(/<!-- TTS_INJECTION:party-mode -->\n?/g, '');
|
|
@@ -430,6 +447,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
430
447
|
|
|
431
448
|
// Set bmad folder name on module manager and IDE manager for placeholder replacement
|
|
432
449
|
this.moduleManager.setBmadFolderName(bmadFolderName);
|
|
450
|
+
this.moduleManager.setCoreConfig(moduleConfigs.core || {});
|
|
433
451
|
this.ideManager.setBmadFolderName(bmadFolderName);
|
|
434
452
|
|
|
435
453
|
// Tool selection will be collected after we determine if it's a reinstall/update/new install
|
|
@@ -894,6 +912,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
894
912
|
await this.moduleManager.runModuleInstaller('core', bmadDir, {
|
|
895
913
|
installedIDEs: config.ides || [],
|
|
896
914
|
moduleConfig: moduleConfigs.core || {},
|
|
915
|
+
coreConfig: moduleConfigs.core || {},
|
|
897
916
|
logger: {
|
|
898
917
|
log: (msg) => console.log(msg),
|
|
899
918
|
error: (msg) => console.error(msg),
|
|
@@ -911,6 +930,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
911
930
|
await this.moduleManager.runModuleInstaller(moduleName, bmadDir, {
|
|
912
931
|
installedIDEs: config.ides || [],
|
|
913
932
|
moduleConfig: moduleConfigs[moduleName] || {},
|
|
933
|
+
coreConfig: moduleConfigs.core || {},
|
|
914
934
|
logger: {
|
|
915
935
|
log: (msg) => console.log(msg),
|
|
916
936
|
error: (msg) => console.error(msg),
|
|
@@ -1008,6 +1028,20 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
1008
1028
|
}
|
|
1009
1029
|
}
|
|
1010
1030
|
|
|
1031
|
+
// Replace {agent_sidecar_folder} placeholders in all agent files
|
|
1032
|
+
console.log(chalk.dim('\n Configuring agent sidecar folders...'));
|
|
1033
|
+
const sidecarResults = await replaceAgentSidecarFolders(bmadDir);
|
|
1034
|
+
|
|
1035
|
+
if (sidecarResults.filesReplaced > 0) {
|
|
1036
|
+
console.log(
|
|
1037
|
+
chalk.green(
|
|
1038
|
+
` ✓ Updated ${sidecarResults.filesReplaced} agent file(s) with ${sidecarResults.totalReplacements} sidecar reference(s)`,
|
|
1039
|
+
),
|
|
1040
|
+
);
|
|
1041
|
+
} else {
|
|
1042
|
+
console.log(chalk.dim(' No agent sidecar references found'));
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1011
1045
|
// Display completion message
|
|
1012
1046
|
const { UI } = require('../../../lib/ui');
|
|
1013
1047
|
const ui = new UI();
|
|
@@ -1016,25 +1050,10 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
1016
1050
|
modules: config.modules,
|
|
1017
1051
|
ides: config.ides,
|
|
1018
1052
|
customFiles: customFiles.length > 0 ? customFiles : undefined,
|
|
1053
|
+
ttsInjectedFiles: this.enableAgentVibes && this.ttsInjectedFiles.length > 0 ? this.ttsInjectedFiles : undefined,
|
|
1054
|
+
agentVibesEnabled: this.enableAgentVibes || false,
|
|
1019
1055
|
});
|
|
1020
1056
|
|
|
1021
|
-
// Offer cleanup for legacy files (only for updates, not fresh installs, and only if not skipped)
|
|
1022
|
-
if (!config.skipCleanup && config._isUpdate) {
|
|
1023
|
-
try {
|
|
1024
|
-
const cleanupResult = await this.performCleanup(bmadDir, false);
|
|
1025
|
-
if (cleanupResult.deleted > 0) {
|
|
1026
|
-
console.log(chalk.green(`\n✓ Cleaned up ${cleanupResult.deleted} legacy file${cleanupResult.deleted > 1 ? 's' : ''}`));
|
|
1027
|
-
}
|
|
1028
|
-
if (cleanupResult.retained > 0) {
|
|
1029
|
-
console.log(chalk.dim(`Run 'bmad cleanup' anytime to manage retained files`));
|
|
1030
|
-
}
|
|
1031
|
-
} catch (cleanupError) {
|
|
1032
|
-
// Don't fail the installation for cleanup errors
|
|
1033
|
-
console.log(chalk.yellow(`\n⚠️ Cleanup warning: ${cleanupError.message}`));
|
|
1034
|
-
console.log(chalk.dim('Run "bmad cleanup" to manually clean up legacy files'));
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
1057
|
return {
|
|
1039
1058
|
success: true,
|
|
1040
1059
|
path: bmadDir,
|
|
@@ -1521,22 +1540,83 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
1521
1540
|
|
|
1522
1541
|
// Build YAML + customize to .md
|
|
1523
1542
|
const customizeExists = await fs.pathExists(customizePath);
|
|
1524
|
-
|
|
1543
|
+
let xmlContent = await this.xmlHandler.buildFromYaml(yamlPath, customizeExists ? customizePath : null, {
|
|
1525
1544
|
includeMetadata: true,
|
|
1526
1545
|
});
|
|
1527
1546
|
|
|
1528
1547
|
// DO NOT replace {project-root} - LLMs understand this placeholder at runtime
|
|
1529
1548
|
// const processedContent = xmlContent.replaceAll('{project-root}', projectDir);
|
|
1530
1549
|
|
|
1550
|
+
// Replace {agent_sidecar_folder} if configured
|
|
1551
|
+
const coreConfig = this.configCollector.collectedConfig.core || {};
|
|
1552
|
+
if (coreConfig.agent_sidecar_folder && xmlContent.includes('{agent_sidecar_folder}')) {
|
|
1553
|
+
xmlContent = xmlContent.replaceAll('{agent_sidecar_folder}', coreConfig.agent_sidecar_folder);
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
// Process TTS injection points (pass targetPath for tracking)
|
|
1557
|
+
xmlContent = this.processTTSInjectionPoints(xmlContent, mdPath);
|
|
1558
|
+
|
|
1559
|
+
// Check if agent has sidecar and copy it
|
|
1560
|
+
let agentYamlContent = null;
|
|
1561
|
+
let hasSidecar = false;
|
|
1562
|
+
|
|
1563
|
+
try {
|
|
1564
|
+
agentYamlContent = await fs.readFile(yamlPath, 'utf8');
|
|
1565
|
+
const yamlLib = require('yaml');
|
|
1566
|
+
const agentYaml = yamlLib.parse(agentYamlContent);
|
|
1567
|
+
hasSidecar = agentYaml?.agent?.metadata?.hasSidecar === true;
|
|
1568
|
+
} catch {
|
|
1569
|
+
// Continue without sidecar processing
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1531
1572
|
// Write the built .md file to bmad/{module}/agents/ with POSIX-compliant final newline
|
|
1532
1573
|
const content = xmlContent.endsWith('\n') ? xmlContent : xmlContent + '\n';
|
|
1533
1574
|
await fs.writeFile(mdPath, content, 'utf8');
|
|
1534
1575
|
this.installedFiles.push(mdPath);
|
|
1535
1576
|
|
|
1577
|
+
// Copy sidecar files if agent has hasSidecar flag
|
|
1578
|
+
if (hasSidecar) {
|
|
1579
|
+
const { copyAgentSidecarFiles } = require('../../../lib/agent/installer');
|
|
1580
|
+
|
|
1581
|
+
// Get agent sidecar folder from core config
|
|
1582
|
+
const coreConfigPath = path.join(bmadDir, 'bmb', 'config.yaml');
|
|
1583
|
+
let agentSidecarFolder;
|
|
1584
|
+
|
|
1585
|
+
if (await fs.pathExists(coreConfigPath)) {
|
|
1586
|
+
const yamlLib = require('yaml');
|
|
1587
|
+
const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8');
|
|
1588
|
+
const coreConfig = yamlLib.parse(coreConfigContent);
|
|
1589
|
+
agentSidecarFolder = coreConfig.agent_sidecar_folder || agentSidecarFolder;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// Resolve path variables
|
|
1593
|
+
const resolvedSidecarFolder = agentSidecarFolder
|
|
1594
|
+
.replaceAll('{project-root}', projectDir)
|
|
1595
|
+
.replaceAll('{bmad_folder}', this.bmadFolderName || 'bmad');
|
|
1596
|
+
|
|
1597
|
+
// Create sidecar directory for this agent
|
|
1598
|
+
const agentSidecarDir = path.join(resolvedSidecarFolder, agentName);
|
|
1599
|
+
await fs.ensureDir(agentSidecarDir);
|
|
1600
|
+
|
|
1601
|
+
// Find and copy sidecar folder from source module
|
|
1602
|
+
const sourceModulePath = getSourcePath(`modules/${moduleName}`);
|
|
1603
|
+
const sourceAgentPath = path.join(sourceModulePath, 'agents');
|
|
1604
|
+
|
|
1605
|
+
// Copy sidecar files (preserve existing, add new)
|
|
1606
|
+
const sidecarResult = copyAgentSidecarFiles(sourceAgentPath, agentSidecarDir, yamlPath);
|
|
1607
|
+
|
|
1608
|
+
if (sidecarResult.copied.length > 0) {
|
|
1609
|
+
console.log(chalk.dim(` Copied ${sidecarResult.copied.length} new sidecar file(s) to: ${agentSidecarDir}`));
|
|
1610
|
+
}
|
|
1611
|
+
if (sidecarResult.preserved.length > 0) {
|
|
1612
|
+
console.log(chalk.dim(` Preserved ${sidecarResult.preserved.length} existing sidecar file(s)`));
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1536
1616
|
// Remove the source YAML file - we can regenerate from installer source if needed
|
|
1537
1617
|
await fs.remove(yamlPath);
|
|
1538
1618
|
|
|
1539
|
-
console.log(chalk.dim(` Built agent: ${agentName}.md`));
|
|
1619
|
+
console.log(chalk.dim(` Built agent: ${agentName}.md${hasSidecar ? ' (with sidecar)' : ''}`));
|
|
1540
1620
|
}
|
|
1541
1621
|
// Handle legacy .md agents - inject activation if needed
|
|
1542
1622
|
else if (agentFile.endsWith('.md')) {
|
|
@@ -1623,13 +1703,16 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
1623
1703
|
}
|
|
1624
1704
|
|
|
1625
1705
|
// Build YAML to XML .md
|
|
1626
|
-
|
|
1706
|
+
let xmlContent = await this.xmlHandler.buildFromYaml(sourceYamlPath, customizeExists ? customizePath : null, {
|
|
1627
1707
|
includeMetadata: true,
|
|
1628
1708
|
});
|
|
1629
1709
|
|
|
1630
1710
|
// DO NOT replace {project-root} - LLMs understand this placeholder at runtime
|
|
1631
1711
|
// const processedContent = xmlContent.replaceAll('{project-root}', projectDir);
|
|
1632
1712
|
|
|
1713
|
+
// Process TTS injection points (pass targetPath for tracking)
|
|
1714
|
+
xmlContent = this.processTTSInjectionPoints(xmlContent, targetMdPath);
|
|
1715
|
+
|
|
1633
1716
|
// Write the built .md file with POSIX-compliant final newline
|
|
1634
1717
|
const content = xmlContent.endsWith('\n') ? xmlContent : xmlContent + '\n';
|
|
1635
1718
|
await fs.writeFile(targetMdPath, content, 'utf8');
|
|
@@ -1717,13 +1800,31 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
1717
1800
|
}
|
|
1718
1801
|
|
|
1719
1802
|
// Build YAML + customize to .md
|
|
1720
|
-
|
|
1803
|
+
let xmlContent = await this.xmlHandler.buildFromYaml(sourceYamlPath, customizeExists ? customizePath : null, {
|
|
1721
1804
|
includeMetadata: true,
|
|
1722
1805
|
});
|
|
1723
1806
|
|
|
1724
1807
|
// DO NOT replace {project-root} - LLMs understand this placeholder at runtime
|
|
1725
1808
|
// const processedContent = xmlContent.replaceAll('{project-root}', projectDir);
|
|
1726
1809
|
|
|
1810
|
+
// Replace {agent_sidecar_folder} if configured
|
|
1811
|
+
const coreConfigPath = path.join(bmadDir, 'bmb', 'config.yaml');
|
|
1812
|
+
let agentSidecarFolder = null;
|
|
1813
|
+
|
|
1814
|
+
if (await fs.pathExists(coreConfigPath)) {
|
|
1815
|
+
const yamlLib = require('yaml');
|
|
1816
|
+
const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8');
|
|
1817
|
+
const coreConfig = yamlLib.parse(coreConfigContent);
|
|
1818
|
+
agentSidecarFolder = coreConfig.agent_sidecar_folder;
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
if (agentSidecarFolder && xmlContent.includes('{agent_sidecar_folder}')) {
|
|
1822
|
+
xmlContent = xmlContent.replaceAll('{agent_sidecar_folder}', agentSidecarFolder);
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
// Process TTS injection points (pass targetPath for tracking)
|
|
1826
|
+
xmlContent = this.processTTSInjectionPoints(xmlContent, targetMdPath);
|
|
1827
|
+
|
|
1727
1828
|
// Write the rebuilt .md file with POSIX-compliant final newline
|
|
1728
1829
|
const content = xmlContent.endsWith('\n') ? xmlContent : xmlContent + '\n';
|
|
1729
1830
|
await fs.writeFile(targetMdPath, content, 'utf8');
|
|
@@ -2183,8 +2284,9 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
2183
2284
|
const installedFilesMap = new Map();
|
|
2184
2285
|
for (const fileEntry of existingFilesManifest) {
|
|
2185
2286
|
if (fileEntry.path) {
|
|
2186
|
-
//
|
|
2187
|
-
//
|
|
2287
|
+
// Paths are relative to bmadDir. Legacy manifests incorrectly prefixed 'bmad/' -
|
|
2288
|
+
// strip it if present. This is safe because no real path inside bmadDir would
|
|
2289
|
+
// start with 'bmad/' (you'd never have .bmad/bmad/... as an actual structure).
|
|
2188
2290
|
const relativePath = fileEntry.path.startsWith('bmad/') ? fileEntry.path.slice(5) : fileEntry.path;
|
|
2189
2291
|
const absolutePath = path.join(bmadDir, relativePath);
|
|
2190
2292
|
installedFilesMap.set(path.normalize(absolutePath), {
|
|
@@ -2504,8 +2606,10 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
2504
2606
|
agentType = parts.slice(-2).join('-'); // Take last 2 parts as type
|
|
2505
2607
|
}
|
|
2506
2608
|
|
|
2507
|
-
// Create target directory
|
|
2508
|
-
const agentTargetDir =
|
|
2609
|
+
// Create target directory - use relative path if agent is in a subdirectory
|
|
2610
|
+
const agentTargetDir = agent.relativePath
|
|
2611
|
+
? path.join(customAgentsDir, agent.relativePath)
|
|
2612
|
+
: path.join(customAgentsDir, finalAgentName);
|
|
2509
2613
|
await fs.ensureDir(agentTargetDir);
|
|
2510
2614
|
|
|
2511
2615
|
// Calculate paths
|
|
@@ -2519,6 +2623,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
2519
2623
|
agentConfig.defaults || {},
|
|
2520
2624
|
finalAgentName,
|
|
2521
2625
|
relativePath,
|
|
2626
|
+
{ config: config.coreConfig },
|
|
2522
2627
|
);
|
|
2523
2628
|
|
|
2524
2629
|
// Write compiled agent
|
|
@@ -2534,10 +2639,26 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
2534
2639
|
await fs.copy(agent.yamlFile, backupYamlPath);
|
|
2535
2640
|
}
|
|
2536
2641
|
|
|
2537
|
-
// Copy sidecar files
|
|
2538
|
-
if (
|
|
2539
|
-
const {
|
|
2540
|
-
|
|
2642
|
+
// Copy sidecar files for agents with hasSidecar flag
|
|
2643
|
+
if (agentConfig.hasSidecar === true && agent.type === 'expert') {
|
|
2644
|
+
const { copyAgentSidecarFiles } = require('../../../lib/agent/installer');
|
|
2645
|
+
|
|
2646
|
+
// Get agent sidecar folder from config or use default
|
|
2647
|
+
const agentSidecarFolder = config.coreConfig?.agent_sidecar_folder;
|
|
2648
|
+
|
|
2649
|
+
// Resolve path variables
|
|
2650
|
+
const resolvedSidecarFolder = agentSidecarFolder.replaceAll('{project-root}', projectDir).replaceAll('{bmad_folder}', bmadDir);
|
|
2651
|
+
|
|
2652
|
+
// Create sidecar directory for this agent
|
|
2653
|
+
const agentSidecarDir = path.join(resolvedSidecarFolder, finalAgentName);
|
|
2654
|
+
await fs.ensureDir(agentSidecarDir);
|
|
2655
|
+
|
|
2656
|
+
// Copy sidecar files (preserve existing, add new)
|
|
2657
|
+
const sidecarResult = copyAgentSidecarFiles(agent.path, agentSidecarDir, agent.yamlFile);
|
|
2658
|
+
|
|
2659
|
+
if (sidecarResult.copied.length > 0 || sidecarResult.preserved.length > 0) {
|
|
2660
|
+
console.log(chalk.dim(` Sidecar: ${sidecarResult.copied.length} new, ${sidecarResult.preserved.length} preserved`));
|
|
2661
|
+
}
|
|
2541
2662
|
}
|
|
2542
2663
|
|
|
2543
2664
|
// Update manifest CSV
|
|
@@ -2595,362 +2716,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
|
|
2595
2716
|
}
|
|
2596
2717
|
}
|
|
2597
2718
|
}
|
|
2598
|
-
|
|
2599
|
-
/**
|
|
2600
|
-
* Scan for legacy/obsolete files in BMAD installation
|
|
2601
|
-
* @param {string} bmadDir - BMAD installation directory
|
|
2602
|
-
* @returns {Object} Categorized files for cleanup
|
|
2603
|
-
*/
|
|
2604
|
-
async scanForLegacyFiles(bmadDir) {
|
|
2605
|
-
const legacyFiles = {
|
|
2606
|
-
backup: [],
|
|
2607
|
-
documentation: [],
|
|
2608
|
-
deprecated_task: [],
|
|
2609
|
-
unknown: [],
|
|
2610
|
-
};
|
|
2611
|
-
|
|
2612
|
-
try {
|
|
2613
|
-
// Load files manifest to understand what should exist
|
|
2614
|
-
const manifestPath = path.join(bmadDir, 'files-manifest.csv');
|
|
2615
|
-
const manifestFiles = new Set();
|
|
2616
|
-
|
|
2617
|
-
if (await fs.pathExists(manifestPath)) {
|
|
2618
|
-
const manifestContent = await fs.readFile(manifestPath, 'utf8');
|
|
2619
|
-
const lines = manifestContent.split('\n').slice(1); // Skip header
|
|
2620
|
-
for (const line of lines) {
|
|
2621
|
-
if (line.trim()) {
|
|
2622
|
-
const relativePath = line.split(',')[0];
|
|
2623
|
-
if (relativePath) {
|
|
2624
|
-
manifestFiles.add(relativePath);
|
|
2625
|
-
}
|
|
2626
|
-
}
|
|
2627
|
-
}
|
|
2628
|
-
}
|
|
2629
|
-
|
|
2630
|
-
// Scan all files recursively
|
|
2631
|
-
const allFiles = await this.getAllFiles(bmadDir);
|
|
2632
|
-
|
|
2633
|
-
for (const filePath of allFiles) {
|
|
2634
|
-
const relativePath = path.relative(bmadDir, filePath);
|
|
2635
|
-
|
|
2636
|
-
// Skip expected files
|
|
2637
|
-
if (this.isExpectedFile(relativePath, manifestFiles)) {
|
|
2638
|
-
continue;
|
|
2639
|
-
}
|
|
2640
|
-
|
|
2641
|
-
// Categorize legacy files
|
|
2642
|
-
if (relativePath.endsWith('.bak')) {
|
|
2643
|
-
legacyFiles.backup.push({
|
|
2644
|
-
path: filePath,
|
|
2645
|
-
relativePath: relativePath,
|
|
2646
|
-
size: (await fs.stat(filePath)).size,
|
|
2647
|
-
mtime: (await fs.stat(filePath)).mtime,
|
|
2648
|
-
});
|
|
2649
|
-
} else if (this.isDocumentationFile(relativePath)) {
|
|
2650
|
-
legacyFiles.documentation.push({
|
|
2651
|
-
path: filePath,
|
|
2652
|
-
relativePath: relativePath,
|
|
2653
|
-
size: (await fs.stat(filePath)).size,
|
|
2654
|
-
mtime: (await fs.stat(filePath)).mtime,
|
|
2655
|
-
});
|
|
2656
|
-
} else if (this.isDeprecatedTaskFile(relativePath)) {
|
|
2657
|
-
const suggestedAlternative = this.suggestAlternative(relativePath);
|
|
2658
|
-
legacyFiles.deprecated_task.push({
|
|
2659
|
-
path: filePath,
|
|
2660
|
-
relativePath: relativePath,
|
|
2661
|
-
size: (await fs.stat(filePath)).size,
|
|
2662
|
-
mtime: (await fs.stat(filePath)).mtime,
|
|
2663
|
-
suggestedAlternative,
|
|
2664
|
-
});
|
|
2665
|
-
} else {
|
|
2666
|
-
legacyFiles.unknown.push({
|
|
2667
|
-
path: filePath,
|
|
2668
|
-
relativePath: relativePath,
|
|
2669
|
-
size: (await fs.stat(filePath)).size,
|
|
2670
|
-
mtime: (await fs.stat(filePath)).mtime,
|
|
2671
|
-
});
|
|
2672
|
-
}
|
|
2673
|
-
}
|
|
2674
|
-
} catch (error) {
|
|
2675
|
-
console.warn(`Warning: Could not scan for legacy files: ${error.message}`);
|
|
2676
|
-
}
|
|
2677
|
-
|
|
2678
|
-
return legacyFiles;
|
|
2679
|
-
}
|
|
2680
|
-
|
|
2681
|
-
/**
|
|
2682
|
-
* Get all files in directory recursively
|
|
2683
|
-
* @param {string} dir - Directory to scan
|
|
2684
|
-
* @returns {Array} Array of file paths
|
|
2685
|
-
*/
|
|
2686
|
-
async getAllFiles(dir) {
|
|
2687
|
-
const files = [];
|
|
2688
|
-
|
|
2689
|
-
async function scan(currentDir) {
|
|
2690
|
-
const entries = await fs.readdir(currentDir);
|
|
2691
|
-
|
|
2692
|
-
for (const entry of entries) {
|
|
2693
|
-
const fullPath = path.join(currentDir, entry);
|
|
2694
|
-
const stat = await fs.stat(fullPath);
|
|
2695
|
-
|
|
2696
|
-
if (stat.isDirectory()) {
|
|
2697
|
-
// Skip certain directories
|
|
2698
|
-
if (!['node_modules', '.git', 'dist', 'build'].includes(entry)) {
|
|
2699
|
-
await scan(fullPath);
|
|
2700
|
-
}
|
|
2701
|
-
} else {
|
|
2702
|
-
files.push(fullPath);
|
|
2703
|
-
}
|
|
2704
|
-
}
|
|
2705
|
-
}
|
|
2706
|
-
|
|
2707
|
-
await scan(dir);
|
|
2708
|
-
return files;
|
|
2709
|
-
}
|
|
2710
|
-
|
|
2711
|
-
/**
|
|
2712
|
-
* Check if file is expected in installation
|
|
2713
|
-
* @param {string} relativePath - Relative path from BMAD dir
|
|
2714
|
-
* @param {Set} manifestFiles - Files from manifest
|
|
2715
|
-
* @returns {boolean} True if expected file
|
|
2716
|
-
*/
|
|
2717
|
-
isExpectedFile(relativePath, manifestFiles) {
|
|
2718
|
-
// Core files in manifest
|
|
2719
|
-
if (manifestFiles.has(relativePath)) {
|
|
2720
|
-
return true;
|
|
2721
|
-
}
|
|
2722
|
-
|
|
2723
|
-
// Configuration files
|
|
2724
|
-
if (relativePath.startsWith('_cfg/') || relativePath === 'config.yaml') {
|
|
2725
|
-
return true;
|
|
2726
|
-
}
|
|
2727
|
-
|
|
2728
|
-
// Custom files
|
|
2729
|
-
if (relativePath.startsWith('custom/') || relativePath === 'manifest.yaml') {
|
|
2730
|
-
return true;
|
|
2731
|
-
}
|
|
2732
|
-
|
|
2733
|
-
// Generated files
|
|
2734
|
-
if (relativePath === 'manifest.csv' || relativePath === 'files-manifest.csv') {
|
|
2735
|
-
return true;
|
|
2736
|
-
}
|
|
2737
|
-
|
|
2738
|
-
// IDE-specific files
|
|
2739
|
-
const ides = ['vscode', 'cursor', 'windsurf', 'claude-code', 'github-copilot', 'zsh', 'bash', 'fish'];
|
|
2740
|
-
if (ides.some((ide) => relativePath.includes(ide))) {
|
|
2741
|
-
return true;
|
|
2742
|
-
}
|
|
2743
|
-
|
|
2744
|
-
// BMAD MODULE STRUCTURES - recognize valid module content
|
|
2745
|
-
const modulePrefixes = ['bmb/', 'bmm/', 'cis/', 'core/', 'bmgd/'];
|
|
2746
|
-
const validExtensions = ['.yaml', '.yml', '.json', '.csv', '.md', '.xml', '.svg', '.png', '.jpg', '.gif', '.excalidraw', '.js'];
|
|
2747
|
-
|
|
2748
|
-
// Check if this file is in a recognized module directory
|
|
2749
|
-
for (const modulePrefix of modulePrefixes) {
|
|
2750
|
-
if (relativePath.startsWith(modulePrefix)) {
|
|
2751
|
-
// Check if it has a valid extension
|
|
2752
|
-
const hasValidExtension = validExtensions.some((ext) => relativePath.endsWith(ext));
|
|
2753
|
-
if (hasValidExtension) {
|
|
2754
|
-
return true;
|
|
2755
|
-
}
|
|
2756
|
-
}
|
|
2757
|
-
}
|
|
2758
|
-
|
|
2759
|
-
// Special case for core module resources
|
|
2760
|
-
if (relativePath.startsWith('core/resources/')) {
|
|
2761
|
-
return true;
|
|
2762
|
-
}
|
|
2763
|
-
|
|
2764
|
-
// Special case for docs directory
|
|
2765
|
-
if (relativePath.startsWith('docs/')) {
|
|
2766
|
-
return true;
|
|
2767
|
-
}
|
|
2768
|
-
|
|
2769
|
-
return false;
|
|
2770
|
-
}
|
|
2771
|
-
|
|
2772
|
-
/**
|
|
2773
|
-
* Check if file is documentation
|
|
2774
|
-
* @param {string} relativePath - Relative path
|
|
2775
|
-
* @returns {boolean} True if documentation
|
|
2776
|
-
*/
|
|
2777
|
-
isDocumentationFile(relativePath) {
|
|
2778
|
-
const docExtensions = ['.md', '.txt', '.pdf'];
|
|
2779
|
-
const docPatterns = ['docs/', 'README', 'CHANGELOG', 'LICENSE'];
|
|
2780
|
-
|
|
2781
|
-
return docExtensions.some((ext) => relativePath.endsWith(ext)) || docPatterns.some((pattern) => relativePath.includes(pattern));
|
|
2782
|
-
}
|
|
2783
|
-
|
|
2784
|
-
/**
|
|
2785
|
-
* Check if file is deprecated task file
|
|
2786
|
-
* @param {string} relativePath - Relative path
|
|
2787
|
-
* @returns {boolean} True if deprecated
|
|
2788
|
-
*/
|
|
2789
|
-
isDeprecatedTaskFile(relativePath) {
|
|
2790
|
-
// Known deprecated files
|
|
2791
|
-
const deprecatedFiles = ['adv-elicit-methods.csv', 'game-resources.json', 'ux-workflow.json'];
|
|
2792
|
-
|
|
2793
|
-
return deprecatedFiles.some((dep) => relativePath.includes(dep));
|
|
2794
|
-
}
|
|
2795
|
-
|
|
2796
|
-
/**
|
|
2797
|
-
* Suggest alternative for deprecated file
|
|
2798
|
-
* @param {string} relativePath - Deprecated file path
|
|
2799
|
-
* @returns {string} Suggested alternative
|
|
2800
|
-
*/
|
|
2801
|
-
suggestAlternative(relativePath) {
|
|
2802
|
-
const alternatives = {
|
|
2803
|
-
'adv-elicit-methods.csv': 'Use the new structured workflows in src/modules/',
|
|
2804
|
-
'game-resources.json': 'Resources are now integrated into modules',
|
|
2805
|
-
'ux-workflow.json': 'UX workflows are now in src/modules/bmm/workflows/',
|
|
2806
|
-
};
|
|
2807
|
-
|
|
2808
|
-
for (const [deprecated, alternative] of Object.entries(alternatives)) {
|
|
2809
|
-
if (relativePath.includes(deprecated)) {
|
|
2810
|
-
return alternative;
|
|
2811
|
-
}
|
|
2812
|
-
}
|
|
2813
|
-
|
|
2814
|
-
return 'Check src/modules/ for new alternatives';
|
|
2815
|
-
}
|
|
2816
|
-
|
|
2817
|
-
/**
|
|
2818
|
-
* Perform interactive cleanup of legacy files
|
|
2819
|
-
* @param {string} bmadDir - BMAD installation directory
|
|
2820
|
-
* @param {boolean} skipInteractive - Skip interactive prompts
|
|
2821
|
-
* @returns {Object} Cleanup results
|
|
2822
|
-
*/
|
|
2823
|
-
async performCleanup(bmadDir, skipInteractive = false) {
|
|
2824
|
-
const inquirer = require('inquirer');
|
|
2825
|
-
const yaml = require('js-yaml');
|
|
2826
|
-
|
|
2827
|
-
// Load user retention preferences
|
|
2828
|
-
const retentionPath = path.join(bmadDir, '_cfg', 'user-retained-files.yaml');
|
|
2829
|
-
let retentionData = { retainedFiles: [], history: [] };
|
|
2830
|
-
|
|
2831
|
-
if (await fs.pathExists(retentionPath)) {
|
|
2832
|
-
const retentionContent = await fs.readFile(retentionPath, 'utf8');
|
|
2833
|
-
retentionData = yaml.load(retentionContent) || retentionData;
|
|
2834
|
-
}
|
|
2835
|
-
|
|
2836
|
-
// Scan for legacy files
|
|
2837
|
-
const legacyFiles = await this.scanForLegacyFiles(bmadDir);
|
|
2838
|
-
const allLegacyFiles = [...legacyFiles.backup, ...legacyFiles.documentation, ...legacyFiles.deprecated_task, ...legacyFiles.unknown];
|
|
2839
|
-
|
|
2840
|
-
if (allLegacyFiles.length === 0) {
|
|
2841
|
-
return { deleted: 0, retained: 0, message: 'No legacy files found' };
|
|
2842
|
-
}
|
|
2843
|
-
|
|
2844
|
-
let deletedCount = 0;
|
|
2845
|
-
let retainedCount = 0;
|
|
2846
|
-
const filesToDelete = [];
|
|
2847
|
-
|
|
2848
|
-
if (skipInteractive) {
|
|
2849
|
-
// Auto-delete all non-retained files
|
|
2850
|
-
for (const file of allLegacyFiles) {
|
|
2851
|
-
if (!retentionData.retainedFiles.includes(file.relativePath)) {
|
|
2852
|
-
filesToDelete.push(file);
|
|
2853
|
-
}
|
|
2854
|
-
}
|
|
2855
|
-
} else {
|
|
2856
|
-
// Interactive cleanup
|
|
2857
|
-
console.log(chalk.cyan('\n🧹 Legacy File Cleanup\n'));
|
|
2858
|
-
console.log(chalk.dim('The following obsolete files were found:\n'));
|
|
2859
|
-
|
|
2860
|
-
// Group files by category
|
|
2861
|
-
const categories = [];
|
|
2862
|
-
if (legacyFiles.backup.length > 0) {
|
|
2863
|
-
categories.push({ name: 'Backup Files (.bak)', files: legacyFiles.backup });
|
|
2864
|
-
}
|
|
2865
|
-
if (legacyFiles.documentation.length > 0) {
|
|
2866
|
-
categories.push({ name: 'Documentation', files: legacyFiles.documentation });
|
|
2867
|
-
}
|
|
2868
|
-
if (legacyFiles.deprecated_task.length > 0) {
|
|
2869
|
-
categories.push({ name: 'Deprecated Task Files', files: legacyFiles.deprecated_task });
|
|
2870
|
-
}
|
|
2871
|
-
if (legacyFiles.unknown.length > 0) {
|
|
2872
|
-
categories.push({ name: 'Unknown Files', files: legacyFiles.unknown });
|
|
2873
|
-
}
|
|
2874
|
-
|
|
2875
|
-
for (const category of categories) {
|
|
2876
|
-
console.log(chalk.yellow(`${category.name}:`));
|
|
2877
|
-
for (const file of category.files) {
|
|
2878
|
-
const size = (file.size / 1024).toFixed(1);
|
|
2879
|
-
const date = file.mtime.toLocaleDateString();
|
|
2880
|
-
let line = ` - ${file.relativePath} (${size}KB, ${date})`;
|
|
2881
|
-
if (file.suggestedAlternative) {
|
|
2882
|
-
line += chalk.dim(` → ${file.suggestedAlternative}`);
|
|
2883
|
-
}
|
|
2884
|
-
console.log(chalk.dim(line));
|
|
2885
|
-
}
|
|
2886
|
-
console.log();
|
|
2887
|
-
}
|
|
2888
|
-
|
|
2889
|
-
const prompt = await inquirer.prompt([
|
|
2890
|
-
{
|
|
2891
|
-
type: 'confirm',
|
|
2892
|
-
name: 'proceed',
|
|
2893
|
-
message: 'Would you like to review these files for cleanup?',
|
|
2894
|
-
default: true,
|
|
2895
|
-
},
|
|
2896
|
-
]);
|
|
2897
|
-
|
|
2898
|
-
if (!prompt.proceed) {
|
|
2899
|
-
return { deleted: 0, retained: allLegacyFiles.length, message: 'Cleanup cancelled by user' };
|
|
2900
|
-
}
|
|
2901
|
-
|
|
2902
|
-
// Show selection interface
|
|
2903
|
-
const selectionPrompt = await inquirer.prompt([
|
|
2904
|
-
{
|
|
2905
|
-
type: 'checkbox',
|
|
2906
|
-
name: 'filesToDelete',
|
|
2907
|
-
message: 'Select files to delete (use SPACEBAR to select, ENTER to continue):',
|
|
2908
|
-
choices: allLegacyFiles.map((file) => {
|
|
2909
|
-
const isRetained = retentionData.retainedFiles.includes(file.relativePath);
|
|
2910
|
-
const description = `${file.relativePath} (${(file.size / 1024).toFixed(1)}KB)`;
|
|
2911
|
-
return {
|
|
2912
|
-
name: description,
|
|
2913
|
-
value: file,
|
|
2914
|
-
checked: !isRetained && !file.relativePath.includes('.bak'),
|
|
2915
|
-
};
|
|
2916
|
-
}),
|
|
2917
|
-
pageSize: Math.min(allLegacyFiles.length, 15),
|
|
2918
|
-
},
|
|
2919
|
-
]);
|
|
2920
|
-
|
|
2921
|
-
filesToDelete.push(...selectionPrompt.filesToDelete);
|
|
2922
|
-
}
|
|
2923
|
-
|
|
2924
|
-
// Delete selected files
|
|
2925
|
-
for (const file of filesToDelete) {
|
|
2926
|
-
try {
|
|
2927
|
-
await fs.remove(file.path);
|
|
2928
|
-
deletedCount++;
|
|
2929
|
-
} catch (error) {
|
|
2930
|
-
console.warn(`Warning: Could not delete ${file.relativePath}: ${error.message}`);
|
|
2931
|
-
}
|
|
2932
|
-
}
|
|
2933
|
-
|
|
2934
|
-
// Count retained files
|
|
2935
|
-
retainedCount = allLegacyFiles.length - deletedCount;
|
|
2936
|
-
|
|
2937
|
-
// Update retention data
|
|
2938
|
-
const newlyRetained = allLegacyFiles.filter((f) => !filesToDelete.includes(f)).map((f) => f.relativePath);
|
|
2939
|
-
|
|
2940
|
-
retentionData.retainedFiles = [...new Set([...retentionData.retainedFiles, ...newlyRetained])];
|
|
2941
|
-
retentionData.history.push({
|
|
2942
|
-
date: new Date().toISOString(),
|
|
2943
|
-
deleted: deletedCount,
|
|
2944
|
-
retained: retainedCount,
|
|
2945
|
-
files: filesToDelete.map((f) => f.relativePath),
|
|
2946
|
-
});
|
|
2947
|
-
|
|
2948
|
-
// Save retention data
|
|
2949
|
-
await fs.ensureDir(path.dirname(retentionPath));
|
|
2950
|
-
await fs.writeFile(retentionPath, yaml.dump(retentionData), 'utf8');
|
|
2951
|
-
|
|
2952
|
-
return { deleted: deletedCount, retained: retainedCount };
|
|
2953
|
-
}
|
|
2954
2719
|
}
|
|
2955
2720
|
|
|
2956
2721
|
module.exports = { Installer };
|