bmad-method 6.0.0-alpha.9 → 6.0.1
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/.augment/code_review_guidelines.yaml +271 -0
- package/.claude/skills/bmad-os-changelog-social/SKILL.md +178 -0
- package/.claude/skills/bmad-os-changelog-social/examples/discord-example.md +53 -0
- package/.claude/skills/bmad-os-changelog-social/examples/linkedin-example.md +49 -0
- package/.claude/skills/bmad-os-changelog-social/examples/twitter-example.md +55 -0
- package/.claude/skills/bmad-os-diataxis-style-fix/SKILL.md +7 -0
- package/.claude/skills/bmad-os-diataxis-style-fix/prompts/instructions.md +229 -0
- package/.claude/skills/bmad-os-draft-changelog/SKILL.md +7 -0
- package/.claude/skills/bmad-os-draft-changelog/prompts/instructions.md +82 -0
- package/.claude/skills/bmad-os-gh-triage/README.md +14 -0
- package/.claude/skills/bmad-os-gh-triage/SKILL.md +12 -0
- package/.claude/skills/bmad-os-gh-triage/prompts/agent-prompt.md +60 -0
- package/.claude/skills/bmad-os-gh-triage/prompts/instructions.md +74 -0
- package/.claude/skills/bmad-os-release-module/README.md +24 -0
- package/.claude/skills/bmad-os-release-module/SKILL.md +7 -0
- package/.claude/skills/bmad-os-release-module/prompts/instructions.md +53 -0
- package/.coderabbit.yaml +85 -0
- package/.github/CODE_OF_CONDUCT.md +128 -0
- package/.github/ISSUE_TEMPLATE/bug-report.yaml +124 -0
- package/.github/ISSUE_TEMPLATE/config.yaml +5 -2
- package/.github/ISSUE_TEMPLATE/documentation.yaml +55 -0
- package/.github/ISSUE_TEMPLATE/feature-request.md +22 -0
- package/.github/ISSUE_TEMPLATE/issue.md +32 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +13 -0
- package/.github/scripts/discord-helpers.sh +34 -0
- package/.github/workflows/coderabbit-review.yaml +22 -0
- package/.github/workflows/discord.yaml +82 -8
- package/.github/workflows/docs.yaml +64 -0
- package/.github/workflows/quality.yaml +40 -2
- package/.husky/pre-commit +13 -0
- package/.markdownlint-cli2.yaml +41 -0
- package/.prettierignore +7 -0
- package/.vscode/settings.json +4 -3
- package/CHANGELOG.md +1074 -674
- package/CNAME +1 -0
- package/CONTRIBUTING.md +97 -189
- package/CONTRIBUTORS.md +32 -0
- package/LICENSE +7 -3
- package/README.md +51 -396
- package/SECURITY.md +85 -0
- package/TRADEMARK.md +55 -0
- package/Wordmark.png +0 -0
- package/banner-bmad-method.png +0 -0
- package/docs/404.md +9 -0
- package/docs/_STYLE_GUIDE.md +370 -0
- package/docs/explanation/advanced-elicitation.md +49 -0
- package/docs/explanation/adversarial-review.md +59 -0
- package/docs/explanation/brainstorming.md +33 -0
- package/docs/explanation/established-projects-faq.md +50 -0
- package/docs/explanation/party-mode.md +59 -0
- package/docs/explanation/preventing-agent-conflicts.md +112 -0
- package/docs/explanation/project-context.md +157 -0
- package/docs/explanation/quick-flow.md +73 -0
- package/docs/explanation/why-solutioning-matters.md +77 -0
- package/docs/how-to/customize-bmad.md +172 -0
- package/docs/how-to/established-projects.md +105 -0
- package/docs/how-to/get-answers-about-bmad.md +103 -0
- package/docs/how-to/install-bmad.md +88 -0
- package/docs/how-to/non-interactive-installation.md +171 -0
- package/docs/how-to/project-context.md +136 -0
- package/docs/how-to/quick-fixes.md +123 -0
- package/docs/how-to/shard-large-documents.md +78 -0
- package/docs/how-to/upgrade-to-v6.md +97 -0
- package/docs/index.md +33 -206
- package/docs/reference/agents.md +28 -0
- package/docs/reference/commands.md +131 -0
- package/docs/reference/modules.md +76 -0
- package/docs/reference/testing.md +106 -0
- package/docs/reference/workflow-map.md +122 -0
- package/docs/tutorials/getting-started.md +219 -0
- package/eslint.config.mjs +26 -16
- package/package.json +35 -28
- package/src/bmm/agents/analyst.agent.yaml +43 -0
- package/src/bmm/agents/architect.agent.yaml +29 -0
- package/src/bmm/agents/dev.agent.yaml +38 -0
- package/src/bmm/agents/pm.agent.yaml +44 -0
- package/src/bmm/agents/qa.agent.yaml +58 -0
- package/src/bmm/agents/quick-flow-solo-dev.agent.yaml +32 -0
- package/src/bmm/agents/sm.agent.yaml +37 -0
- package/src/bmm/agents/tech-writer/tech-writer-sidecar/documentation-standards.md +224 -0
- package/src/bmm/agents/tech-writer/tech-writer.agent.yaml +46 -0
- package/src/bmm/agents/ux-designer.agent.yaml +27 -0
- package/src/bmm/data/project-context-template.md +26 -0
- package/src/bmm/module-help.csv +31 -0
- package/src/bmm/module.yaml +50 -0
- package/src/bmm/teams/default-party.csv +20 -0
- package/src/bmm/workflows/1-analysis/create-product-brief/product-brief.template.md +10 -0
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +177 -0
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +161 -0
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +199 -0
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +202 -0
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +205 -0
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +219 -0
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +162 -0
- package/src/bmm/workflows/1-analysis/create-product-brief/workflow.md +57 -0
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +137 -0
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +229 -0
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +238 -0
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +206 -0
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +234 -0
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +443 -0
- package/src/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +182 -0
- package/src/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +237 -0
- package/src/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +249 -0
- package/src/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +259 -0
- package/src/bmm/workflows/1-analysis/research/market-steps/step-05-competitive-analysis.md +177 -0
- package/src/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +475 -0
- package/src/bmm/workflows/1-analysis/research/research.template.md +29 -0
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +137 -0
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +239 -0
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +248 -0
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +202 -0
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +233 -0
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +486 -0
- package/src/bmm/workflows/1-analysis/research/workflow-domain-research.md +54 -0
- package/src/bmm/workflows/1-analysis/research/workflow-market-research.md +54 -0
- package/src/bmm/workflows/1-analysis/research/workflow-technical-research.md +54 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/data/domain-complexity.csv +15 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md +197 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/data/project-types.csv +11 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01-init.md +191 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01b-continue.md +153 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +224 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +154 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +170 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +226 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +213 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +207 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +226 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +237 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +228 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +231 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +242 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +217 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +124 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +247 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +208 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +249 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +253 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-04-complete.md +168 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +226 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02-format-detection.md +191 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-02b-parity-check.md +209 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-03-density-validation.md +174 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-04-brief-coverage-validation.md +214 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-05-measurability-validation.md +228 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-06-traceability-validation.md +217 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-07-implementation-leakage-validation.md +205 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-08-domain-compliance-validation.md +243 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-09-project-type-validation.md +263 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +209 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +264 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-12-completeness-validation.md +242 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +231 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/templates/prd-template.md +10 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +63 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +65 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +63 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01-init.md +135 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +127 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +190 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +216 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +219 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +234 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +252 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +254 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +224 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +224 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +241 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +248 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +237 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +264 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +171 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/ux-design-template.md +13 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +42 -0
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-01-document-discovery.md +184 -0
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-02-prd-analysis.md +172 -0
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-03-epic-coverage-validation.md +173 -0
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-04-ux-alignment.md +133 -0
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-05-epic-quality-review.md +245 -0
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +129 -0
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/templates/readiness-report-template.md +4 -0
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +54 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/architecture-decision-template.md +12 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/data/domain-complexity.csv +13 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/data/project-types.csv +7 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01-init.md +153 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +164 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +224 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +331 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +318 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +359 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +379 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +359 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +76 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/workflow.md +49 -0
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md +259 -0
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +233 -0
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +272 -0
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +149 -0
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/templates/epics-template.md +57 -0
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +58 -0
- package/src/bmm/workflows/4-implementation/code-review/checklist.md +23 -0
- package/src/bmm/workflows/4-implementation/code-review/instructions.xml +227 -0
- package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +44 -0
- package/src/bmm/workflows/4-implementation/correct-course/checklist.md +288 -0
- package/src/bmm/workflows/4-implementation/correct-course/instructions.md +207 -0
- package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +54 -0
- package/src/bmm/workflows/4-implementation/create-story/checklist.md +358 -0
- package/src/bmm/workflows/4-implementation/create-story/instructions.xml +346 -0
- package/src/bmm/workflows/4-implementation/create-story/template.md +49 -0
- package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +53 -0
- package/src/bmm/workflows/4-implementation/dev-story/checklist.md +80 -0
- package/src/bmm/workflows/4-implementation/dev-story/instructions.xml +410 -0
- package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +21 -0
- package/src/bmm/workflows/4-implementation/retrospective/instructions.md +1444 -0
- package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +53 -0
- package/src/bmm/workflows/4-implementation/sprint-planning/instructions.md +226 -0
- package/src/bmm/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +55 -0
- package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +47 -0
- package/src/bmm/workflows/4-implementation/sprint-status/instructions.md +230 -0
- package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +25 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +174 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +118 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +111 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +111 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +104 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-06-resolve-findings.md +146 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +50 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-01-understand.md +191 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +144 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +127 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +200 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/tech-spec-template.md +74 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +79 -0
- package/src/bmm/workflows/document-project/checklist.md +245 -0
- package/src/bmm/workflows/document-project/instructions.md +130 -0
- package/src/bmm/workflows/document-project/templates/project-scan-report-schema.json +160 -0
- package/src/bmm/workflows/document-project/workflow.yaml +22 -0
- package/src/bmm/workflows/document-project/workflows/deep-dive-instructions.md +298 -0
- package/src/bmm/workflows/document-project/workflows/deep-dive.yaml +31 -0
- package/src/bmm/workflows/document-project/workflows/full-scan-instructions.md +1106 -0
- package/src/bmm/workflows/document-project/workflows/full-scan.yaml +31 -0
- package/src/bmm/workflows/generate-project-context/project-context-template.md +21 -0
- package/src/bmm/workflows/generate-project-context/steps/step-01-discover.md +184 -0
- package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +318 -0
- package/src/bmm/workflows/generate-project-context/steps/step-03-complete.md +278 -0
- package/src/bmm/workflows/generate-project-context/workflow.md +49 -0
- package/src/bmm/workflows/qa/automate/checklist.md +33 -0
- package/src/bmm/workflows/qa/automate/instructions.md +110 -0
- package/src/bmm/workflows/qa/automate/workflow.yaml +44 -0
- package/src/core/agents/bmad-master.agent.yaml +12 -21
- package/src/core/module-help.csv +9 -0
- package/src/core/module.yaml +25 -0
- package/src/core/tasks/editorial-review-prose.xml +102 -0
- package/src/core/tasks/editorial-review-structure.xml +209 -0
- package/src/core/tasks/help.md +85 -0
- package/src/core/tasks/index-docs.xml +2 -2
- package/src/core/tasks/review-adversarial-general.xml +48 -0
- package/src/core/tasks/shard-doc.xml +108 -0
- package/src/core/tasks/workflow.xml +39 -74
- package/src/core/workflows/advanced-elicitation/methods.csv +51 -0
- package/src/core/workflows/advanced-elicitation/workflow.xml +117 -0
- package/src/core/workflows/brainstorming/brain-methods.csv +62 -36
- package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +197 -0
- package/src/core/workflows/brainstorming/steps/step-01b-continue.md +122 -0
- package/src/core/workflows/brainstorming/steps/step-02a-user-selected.md +225 -0
- package/src/core/workflows/brainstorming/steps/step-02b-ai-recommended.md +237 -0
- package/src/core/workflows/brainstorming/steps/step-02c-random-selection.md +209 -0
- package/src/core/workflows/brainstorming/steps/step-02d-progressive-flow.md +264 -0
- package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +399 -0
- package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +303 -0
- package/src/core/workflows/brainstorming/template.md +13 -104
- package/src/core/workflows/brainstorming/workflow.md +58 -0
- package/src/core/workflows/party-mode/steps/step-01-agent-loading.md +138 -0
- package/src/core/workflows/party-mode/steps/step-02-discussion-orchestration.md +187 -0
- package/src/core/workflows/party-mode/steps/step-03-graceful-exit.md +168 -0
- package/src/core/workflows/party-mode/workflow.md +194 -0
- package/src/utility/agent-components/activation-rules.txt +6 -0
- package/src/utility/agent-components/activation-steps.txt +14 -0
- package/src/utility/agent-components/agent-command-header.md +1 -0
- package/src/utility/agent-components/agent.customize.template.yaml +41 -0
- package/src/utility/agent-components/handler-action.txt +4 -0
- package/src/utility/agent-components/handler-exec.txt +6 -0
- package/src/utility/agent-components/handler-multi.txt +14 -0
- package/src/utility/agent-components/handler-tmpl.txt +5 -0
- package/src/utility/agent-components/handler-validate-workflow.txt +7 -0
- package/src/utility/agent-components/handler-workflow.txt +10 -0
- package/src/utility/agent-components/menu-handlers.txt +6 -0
- package/test/README.md +4 -4
- package/test/adversarial-review-tests/README.md +56 -0
- package/test/adversarial-review-tests/sample-content.md +46 -0
- package/test/adversarial-review-tests/test-cases.yaml +103 -0
- package/test/fixtures/agent-schema/invalid/critical-actions/actions-as-string.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/critical-actions/empty-string-in-actions.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/menu/empty-menu.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/menu/missing-menu.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/menu-commands/empty-command-target.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/menu-commands/no-command-target.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/menu-triggers/camel-case.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/menu-triggers/compound-invalid-format.agent.yaml +25 -0
- package/test/fixtures/agent-schema/invalid/menu-triggers/compound-mismatched-kebab.agent.yaml +25 -0
- package/test/fixtures/agent-schema/invalid/menu-triggers/duplicate-triggers.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/menu-triggers/empty-trigger.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/menu-triggers/leading-asterisk.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/menu-triggers/snake-case.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/menu-triggers/trigger-with-spaces.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/metadata/empty-module-string.agent.yaml +1 -1
- package/test/fixtures/agent-schema/invalid/metadata/extra-metadata-fields.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/persona/empty-principles-array.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/persona/empty-string-in-principles.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/persona/extra-persona-fields.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/persona/missing-role.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/prompts/empty-content.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/prompts/extra-prompt-fields.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/prompts/missing-content.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/prompts/missing-id.agent.yaml +1 -0
- package/test/fixtures/agent-schema/invalid/top-level/extra-top-level-keys.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/critical-actions/empty-critical-actions.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/critical-actions/no-critical-actions.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/critical-actions/valid-critical-actions.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/menu/multiple-menu-items.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/menu/single-menu-item.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/menu-commands/all-command-types.agent.yaml +2 -3
- package/test/fixtures/agent-schema/valid/menu-commands/multiple-commands.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/menu-triggers/compound-triggers.agent.yaml +31 -0
- package/test/fixtures/agent-schema/valid/menu-triggers/kebab-case-triggers.agent.yaml +2 -1
- package/test/fixtures/agent-schema/valid/metadata/core-agent-with-module.agent.yaml +24 -0
- package/test/fixtures/agent-schema/valid/metadata/empty-module-name-in-path.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/metadata/malformed-path-treated-as-core.agent.yaml +2 -1
- package/test/fixtures/agent-schema/valid/metadata/module-agent-correct.agent.yaml +2 -1
- package/test/fixtures/agent-schema/valid/metadata/module-agent-missing-module.agent.yaml +23 -0
- package/test/fixtures/agent-schema/valid/metadata/wrong-module-value.agent.yaml +24 -0
- package/test/fixtures/agent-schema/valid/persona/complete-persona.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/prompts/empty-prompts.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/prompts/no-prompts.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/prompts/valid-prompts-minimal.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/prompts/valid-prompts-with-description.agent.yaml +1 -0
- package/test/fixtures/agent-schema/valid/top-level/minimal-core-agent.agent.yaml +1 -0
- package/test/fixtures/file-refs-csv/invalid/all-empty-workflow.csv +3 -0
- package/test/fixtures/file-refs-csv/invalid/empty-data.csv +1 -0
- package/test/fixtures/file-refs-csv/invalid/no-workflow-column.csv +3 -0
- package/test/fixtures/file-refs-csv/invalid/unresolvable-vars.csv +3 -0
- package/test/fixtures/file-refs-csv/valid/bmm-style.csv +3 -0
- package/test/fixtures/file-refs-csv/valid/core-style.csv +3 -0
- package/test/fixtures/file-refs-csv/valid/minimal.csv +2 -0
- package/test/test-agent-schema.js +4 -4
- package/test/test-file-refs-csv.js +133 -0
- package/test/test-installation-components.js +10 -12
- package/test/test-rehype-plugins.mjs +1050 -0
- package/test/unit-test-schema.js +2 -2
- package/tools/build-docs.mjs +463 -0
- package/tools/cli/README.md +41 -589
- package/tools/cli/bmad-cli.js +67 -1
- package/tools/cli/commands/install.js +42 -34
- package/tools/cli/commands/status.js +44 -26
- package/tools/cli/commands/uninstall.js +146 -23
- package/tools/cli/external-official-modules.yaml +53 -0
- package/tools/cli/installers/install-messages.yaml +39 -0
- package/tools/cli/installers/lib/core/config-collector.js +589 -95
- package/tools/cli/installers/lib/core/custom-module-cache.js +260 -0
- package/tools/cli/installers/lib/core/dependency-resolver.js +57 -39
- package/tools/cli/installers/lib/core/detector.js +19 -125
- package/tools/cli/installers/lib/core/ide-config-manager.js +12 -9
- package/tools/cli/installers/lib/core/installer.js +2075 -1161
- package/tools/cli/installers/lib/core/manifest-generator.js +494 -103
- package/tools/cli/installers/lib/core/manifest.js +544 -46
- package/tools/cli/installers/lib/custom/handler.js +358 -0
- package/tools/cli/installers/lib/ide/_base-ide.js +83 -44
- package/tools/cli/installers/lib/ide/_config-driven.js +560 -0
- package/tools/cli/installers/lib/ide/codex.js +277 -54
- package/tools/cli/installers/lib/ide/github-copilot.js +607 -209
- package/tools/cli/installers/lib/ide/kilo.js +169 -75
- package/tools/cli/installers/lib/ide/manager.js +179 -48
- package/tools/cli/installers/lib/ide/platform-codes.js +100 -0
- package/tools/cli/installers/lib/ide/platform-codes.yaml +227 -0
- package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +95 -5
- package/tools/cli/installers/lib/ide/shared/bmad-artifacts.js +51 -20
- package/tools/cli/installers/lib/ide/shared/module-injections.js +6 -3
- package/tools/cli/installers/lib/ide/shared/path-utils.js +299 -0
- package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +262 -14
- package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +108 -27
- package/tools/cli/installers/lib/ide/templates/agent-command-template.md +2 -1
- package/tools/cli/installers/lib/ide/templates/combined/antigravity.md +8 -0
- package/tools/cli/installers/lib/ide/templates/combined/default-agent.md +16 -0
- package/tools/cli/installers/lib/ide/templates/combined/default-task.md +10 -0
- package/tools/cli/installers/lib/ide/templates/combined/default-tool.md +10 -0
- package/tools/cli/installers/lib/ide/templates/combined/default-workflow-yaml.md +15 -0
- package/tools/cli/installers/lib/ide/templates/combined/default-workflow.md +7 -0
- package/tools/cli/installers/lib/ide/templates/combined/gemini-agent.toml +14 -0
- package/tools/cli/installers/lib/ide/templates/combined/gemini-task.toml +11 -0
- package/tools/cli/installers/lib/ide/templates/combined/gemini-tool.toml +11 -0
- package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml +16 -0
- package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml +14 -0
- package/tools/cli/installers/lib/ide/templates/combined/kiro-agent.md +16 -0
- package/tools/cli/installers/lib/ide/templates/combined/kiro-task.md +9 -0
- package/tools/cli/installers/lib/ide/templates/combined/kiro-tool.md +9 -0
- package/tools/cli/installers/lib/ide/templates/combined/kiro-workflow-yaml.md +15 -0
- package/tools/cli/installers/lib/ide/templates/combined/kiro-workflow.md +7 -0
- package/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md +15 -0
- package/tools/cli/installers/lib/ide/templates/combined/opencode-task.md +14 -0
- package/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md +14 -0
- package/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md +17 -0
- package/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md +17 -0
- package/tools/cli/installers/lib/ide/templates/combined/rovodev.md +9 -0
- package/tools/cli/installers/lib/ide/templates/combined/trae.md +9 -0
- package/tools/cli/installers/lib/ide/templates/combined/windsurf-workflow.md +10 -0
- package/tools/cli/installers/lib/ide/templates/workflow-command-template.md +2 -1
- package/tools/cli/installers/lib/ide/templates/workflow-commander.md +6 -0
- package/tools/cli/installers/lib/message-loader.js +83 -0
- package/tools/cli/installers/lib/modules/external-manager.js +136 -0
- package/tools/cli/installers/lib/modules/manager.js +931 -207
- package/tools/cli/lib/activation-builder.js +13 -16
- package/tools/cli/lib/agent/compiler.js +525 -0
- package/tools/cli/lib/agent/installer.js +680 -0
- package/tools/cli/lib/agent/template-engine.js +152 -0
- package/tools/cli/lib/agent-analyzer.js +48 -20
- package/tools/cli/lib/agent-party-generator.js +5 -17
- package/tools/cli/lib/cli-utils.js +76 -104
- package/tools/cli/lib/config.js +4 -3
- package/tools/cli/lib/platform-codes.js +2 -2
- package/tools/cli/lib/project-root.js +6 -0
- package/tools/cli/lib/prompts.js +809 -0
- package/tools/cli/lib/ui.js +1600 -272
- package/tools/cli/lib/xml-handler.js +4 -55
- package/tools/cli/lib/yaml-format.js +4 -6
- package/tools/cli/lib/yaml-xml-builder.js +183 -61
- package/tools/docs/_prompt-external-modules-page.md +59 -0
- package/tools/docs/fix-refs.md +91 -0
- package/tools/fix-doc-links.js +285 -0
- package/tools/lib/xml-utils.js +13 -0
- 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/platform-codes.yaml +24 -0
- package/tools/schema/agent.js +306 -53
- package/tools/validate-agent-schema.js +3 -3
- package/tools/validate-doc-links.js +393 -0
- package/tools/validate-file-refs.js +554 -0
- package/tools/validate-svg-changes.sh +356 -0
- package/website/README.md +75 -0
- package/website/astro.config.mjs +135 -0
- package/website/public/favicon.ico +0 -0
- package/website/public/img/bmad-dark.png +0 -0
- package/website/public/img/bmad-light.png +0 -0
- package/website/public/workflow-map-diagram.html +361 -0
- package/website/src/components/Banner.astro +62 -0
- package/website/src/components/Header.astro +96 -0
- package/website/src/components/MobileMenuFooter.astro +33 -0
- package/website/src/content/config.ts +6 -0
- package/website/src/lib/site-url.mjs +25 -0
- package/website/src/pages/404.astro +11 -0
- package/website/src/pages/robots.txt.ts +48 -0
- package/website/src/rehype-base-paths.js +112 -0
- package/website/src/rehype-markdown-links.js +111 -0
- package/website/src/styles/custom.css +509 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
- package/.github/ISSUE_TEMPLATE/idea_submission.md +0 -109
- package/.github/workflows/bundle-latest.yaml +0 -277
- package/.github/workflows/manual-release.yaml +0 -212
- package/docs/BUNDLE_DISTRIBUTION_SETUP.md +0 -95
- package/docs/agent-customization-guide.md +0 -208
- package/docs/document-sharding-guide.md +0 -447
- package/docs/ide-info/auggie.md +0 -31
- package/docs/ide-info/claude-code.md +0 -25
- package/docs/ide-info/cline.md +0 -31
- package/docs/ide-info/codex.md +0 -21
- package/docs/ide-info/crush.md +0 -30
- package/docs/ide-info/cursor.md +0 -25
- package/docs/ide-info/gemini.md +0 -25
- package/docs/ide-info/github-copilot.md +0 -26
- package/docs/ide-info/iflow.md +0 -33
- package/docs/ide-info/kilo.md +0 -24
- package/docs/ide-info/opencode.md +0 -24
- package/docs/ide-info/qwen.md +0 -25
- package/docs/ide-info/roo.md +0 -27
- package/docs/ide-info/trae.md +0 -25
- package/docs/ide-info/windsurf.md +0 -22
- package/docs/installers-bundlers/ide-injections.md +0 -186
- package/docs/installers-bundlers/installers-modules-platforms-reference.md +0 -388
- package/docs/installers-bundlers/web-bundler-usage.md +0 -54
- package/docs/v4-to-v6-upgrade.md +0 -227
- package/docs/web-bundles-gemini-gpt-guide.md +0 -473
- package/src/core/_module-installer/install-config.yaml +0 -35
- package/src/core/_module-installer/installer.js +0 -60
- package/src/core/agents/bmad-web-orchestrator.agent.xml +0 -113
- package/src/core/tasks/adv-elicit-methods.csv +0 -39
- package/src/core/tasks/advanced-elicitation.xml +0 -106
- package/src/core/tasks/validate-workflow.xml +0 -89
- package/src/core/tools/shard-doc.xml +0 -109
- package/src/core/workflows/brainstorming/README.md +0 -261
- package/src/core/workflows/brainstorming/instructions.md +0 -315
- package/src/core/workflows/brainstorming/workflow.yaml +0 -43
- package/src/core/workflows/party-mode/instructions.md +0 -183
- package/src/core/workflows/party-mode/workflow.yaml +0 -27
- package/src/modules/bmb/README.md +0 -194
- package/src/modules/bmb/_module-installer/install-config.yaml +0 -31
- package/src/modules/bmb/agents/bmad-builder.agent.yaml +0 -59
- package/src/modules/bmb/workflows/audit-workflow/checklist.md +0 -142
- package/src/modules/bmb/workflows/audit-workflow/instructions.md +0 -341
- package/src/modules/bmb/workflows/audit-workflow/template.md +0 -118
- package/src/modules/bmb/workflows/audit-workflow/workflow.yaml +0 -25
- package/src/modules/bmb/workflows/convert-legacy/README.md +0 -262
- package/src/modules/bmb/workflows/convert-legacy/checklist.md +0 -205
- package/src/modules/bmb/workflows/convert-legacy/instructions.md +0 -377
- package/src/modules/bmb/workflows/convert-legacy/workflow.yaml +0 -34
- package/src/modules/bmb/workflows/create-agent/README.md +0 -203
- package/src/modules/bmb/workflows/create-agent/agent-architecture.md +0 -415
- package/src/modules/bmb/workflows/create-agent/agent-command-patterns.md +0 -759
- package/src/modules/bmb/workflows/create-agent/agent-types.md +0 -292
- package/src/modules/bmb/workflows/create-agent/brainstorm-context.md +0 -174
- package/src/modules/bmb/workflows/create-agent/checklist.md +0 -62
- package/src/modules/bmb/workflows/create-agent/communication-styles.md +0 -202
- package/src/modules/bmb/workflows/create-agent/instructions.md +0 -456
- package/src/modules/bmb/workflows/create-agent/workflow.yaml +0 -49
- package/src/modules/bmb/workflows/create-module/README.md +0 -229
- package/src/modules/bmb/workflows/create-module/brainstorm-context.md +0 -137
- package/src/modules/bmb/workflows/create-module/checklist.md +0 -235
- package/src/modules/bmb/workflows/create-module/installer-templates/install-config.yaml +0 -92
- package/src/modules/bmb/workflows/create-module/installer-templates/installer.js +0 -231
- package/src/modules/bmb/workflows/create-module/instructions.md +0 -576
- package/src/modules/bmb/workflows/create-module/module-structure.md +0 -400
- package/src/modules/bmb/workflows/create-module/workflow.yaml +0 -44
- package/src/modules/bmb/workflows/create-workflow/README.md +0 -277
- package/src/modules/bmb/workflows/create-workflow/brainstorm-context.md +0 -197
- package/src/modules/bmb/workflows/create-workflow/checklist.md +0 -94
- package/src/modules/bmb/workflows/create-workflow/instructions.md +0 -724
- package/src/modules/bmb/workflows/create-workflow/workflow-creation-guide.md +0 -1306
- package/src/modules/bmb/workflows/create-workflow/workflow-template/checklist.md +0 -24
- package/src/modules/bmb/workflows/create-workflow/workflow-template/instructions.md +0 -13
- package/src/modules/bmb/workflows/create-workflow/workflow-template/template.md +0 -9
- package/src/modules/bmb/workflows/create-workflow/workflow-template/workflow.yaml +0 -65
- package/src/modules/bmb/workflows/create-workflow/workflow.yaml +0 -42
- package/src/modules/bmb/workflows/edit-agent/README.md +0 -112
- package/src/modules/bmb/workflows/edit-agent/checklist.md +0 -112
- package/src/modules/bmb/workflows/edit-agent/instructions.md +0 -290
- package/src/modules/bmb/workflows/edit-agent/workflow.yaml +0 -35
- package/src/modules/bmb/workflows/edit-module/README.md +0 -187
- package/src/modules/bmb/workflows/edit-module/checklist.md +0 -165
- package/src/modules/bmb/workflows/edit-module/instructions.md +0 -339
- package/src/modules/bmb/workflows/edit-module/workflow.yaml +0 -36
- package/src/modules/bmb/workflows/edit-workflow/README.md +0 -119
- package/src/modules/bmb/workflows/edit-workflow/checklist.md +0 -70
- package/src/modules/bmb/workflows/edit-workflow/instructions.md +0 -342
- package/src/modules/bmb/workflows/edit-workflow/workflow.yaml +0 -29
- package/src/modules/bmb/workflows/module-brief/README.md +0 -264
- package/src/modules/bmb/workflows/module-brief/checklist.md +0 -116
- package/src/modules/bmb/workflows/module-brief/instructions.md +0 -267
- package/src/modules/bmb/workflows/module-brief/template.md +0 -275
- package/src/modules/bmb/workflows/module-brief/workflow.yaml +0 -31
- package/src/modules/bmb/workflows/redoc/README.md +0 -87
- package/src/modules/bmb/workflows/redoc/checklist.md +0 -99
- package/src/modules/bmb/workflows/redoc/instructions.md +0 -265
- package/src/modules/bmb/workflows/redoc/workflow.yaml +0 -34
- package/src/modules/bmgd/README.md +0 -208
- package/src/modules/bmgd/_module-installer/install-config.yaml +0 -54
- package/src/modules/bmgd/agents/game-architect.agent.yaml +0 -33
- package/src/modules/bmgd/agents/game-designer.agent.yaml +0 -40
- package/src/modules/bmgd/agents/game-dev.agent.yaml +0 -40
- package/src/modules/bmgd/agents/game-scrum-master.agent.yaml +0 -75
- package/src/modules/bmgd/teams/default-party.csv +0 -10
- package/src/modules/bmgd/teams/team-gamedev.yaml +0 -18
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/game-brain-methods.csv +0 -26
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/game-context.md +0 -115
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/instructions.md +0 -128
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/workflow.yaml +0 -41
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/checklist.md +0 -128
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/instructions.md +0 -371
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/template.md +0 -205
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/workflow.yaml +0 -44
- package/src/modules/bmgd/workflows/2-design/gdd/checklist.md +0 -148
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/action-platformer.md +0 -45
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/adventure.md +0 -84
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/card-game.md +0 -76
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/fighting.md +0 -89
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/horror.md +0 -86
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/idle-incremental.md +0 -78
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/metroidvania.md +0 -87
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/moba.md +0 -74
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/party-game.md +0 -79
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/puzzle.md +0 -58
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/racing.md +0 -88
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/rhythm.md +0 -79
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/roguelike.md +0 -69
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/rpg.md +0 -70
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/sandbox.md +0 -79
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/shooter.md +0 -62
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/simulation.md +0 -73
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/sports.md +0 -75
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/strategy.md +0 -71
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/survival.md +0 -79
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/text-based.md +0 -91
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/tower-defense.md +0 -79
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/turn-based-tactics.md +0 -88
- package/src/modules/bmgd/workflows/2-design/gdd/game-types/visual-novel.md +0 -89
- package/src/modules/bmgd/workflows/2-design/gdd/game-types.csv +0 -25
- package/src/modules/bmgd/workflows/2-design/gdd/gdd-template.md +0 -153
- package/src/modules/bmgd/workflows/2-design/gdd/instructions-gdd.md +0 -501
- package/src/modules/bmgd/workflows/2-design/gdd/workflow.yaml +0 -81
- package/src/modules/bmgd/workflows/2-design/narrative/checklist.md +0 -139
- package/src/modules/bmgd/workflows/2-design/narrative/instructions-narrative.md +0 -603
- package/src/modules/bmgd/workflows/2-design/narrative/narrative-template.md +0 -195
- package/src/modules/bmgd/workflows/2-design/narrative/workflow.yaml +0 -38
- package/src/modules/bmgd/workflows/3-technical/game-architecture/architecture-patterns.yaml +0 -321
- package/src/modules/bmgd/workflows/3-technical/game-architecture/architecture-template.md +0 -103
- package/src/modules/bmgd/workflows/3-technical/game-architecture/checklist.md +0 -240
- package/src/modules/bmgd/workflows/3-technical/game-architecture/decision-catalog.yaml +0 -222
- package/src/modules/bmgd/workflows/3-technical/game-architecture/instructions.md +0 -699
- package/src/modules/bmgd/workflows/3-technical/game-architecture/pattern-categories.csv +0 -13
- package/src/modules/bmgd/workflows/3-technical/game-architecture/workflow.yaml +0 -67
- package/src/modules/bmgd/workflows/4-production/code-review/backlog_template.md +0 -12
- package/src/modules/bmgd/workflows/4-production/code-review/checklist.md +0 -22
- package/src/modules/bmgd/workflows/4-production/code-review/instructions.md +0 -398
- package/src/modules/bmgd/workflows/4-production/code-review/workflow.yaml +0 -57
- package/src/modules/bmgd/workflows/4-production/correct-course/checklist.md +0 -279
- package/src/modules/bmgd/workflows/4-production/correct-course/instructions.md +0 -206
- package/src/modules/bmgd/workflows/4-production/correct-course/workflow.yaml +0 -52
- package/src/modules/bmgd/workflows/4-production/create-story/checklist.md +0 -240
- package/src/modules/bmgd/workflows/4-production/create-story/instructions.md +0 -256
- package/src/modules/bmgd/workflows/4-production/create-story/template.md +0 -51
- package/src/modules/bmgd/workflows/4-production/create-story/workflow.yaml +0 -68
- package/src/modules/bmgd/workflows/4-production/dev-story/checklist.md +0 -38
- package/src/modules/bmgd/workflows/4-production/dev-story/instructions.md +0 -267
- package/src/modules/bmgd/workflows/4-production/dev-story/workflow.yaml +0 -53
- package/src/modules/bmgd/workflows/4-production/epic-tech-context/checklist.md +0 -17
- package/src/modules/bmgd/workflows/4-production/epic-tech-context/instructions.md +0 -164
- package/src/modules/bmgd/workflows/4-production/epic-tech-context/template.md +0 -76
- package/src/modules/bmgd/workflows/4-production/epic-tech-context/workflow.yaml +0 -52
- package/src/modules/bmgd/workflows/4-production/retrospective/instructions.md +0 -1442
- package/src/modules/bmgd/workflows/4-production/retrospective/workflow.yaml +0 -52
- package/src/modules/bmgd/workflows/4-production/sprint-planning/instructions.md +0 -234
- package/src/modules/bmgd/workflows/4-production/sprint-planning/sprint-status-template.yaml +0 -55
- package/src/modules/bmgd/workflows/4-production/sprint-planning/workflow.yaml +0 -50
- package/src/modules/bmgd/workflows/4-production/story-context/checklist.md +0 -16
- package/src/modules/bmgd/workflows/4-production/story-context/context-template.xml +0 -34
- package/src/modules/bmgd/workflows/4-production/story-context/instructions.md +0 -209
- package/src/modules/bmgd/workflows/4-production/story-context/workflow.yaml +0 -57
- package/src/modules/bmgd/workflows/4-production/story-done/instructions.md +0 -111
- package/src/modules/bmgd/workflows/4-production/story-done/workflow.yaml +0 -28
- package/src/modules/bmgd/workflows/4-production/story-ready/instructions.md +0 -117
- package/src/modules/bmgd/workflows/4-production/story-ready/workflow.yaml +0 -25
- package/src/modules/bmm/README.md +0 -128
- package/src/modules/bmm/_module-installer/assets/bmm-kb.md +0 -1
- package/src/modules/bmm/_module-installer/assets/technical-decisions.md +0 -30
- package/src/modules/bmm/_module-installer/install-config.yaml +0 -60
- package/src/modules/bmm/_module-installer/installer.js +0 -131
- package/src/modules/bmm/_module-installer/platform-specifics/claude-code.js +0 -35
- package/src/modules/bmm/_module-installer/platform-specifics/windsurf.js +0 -32
- package/src/modules/bmm/agents/analyst.agent.yaml +0 -48
- package/src/modules/bmm/agents/architect.agent.yaml +0 -42
- package/src/modules/bmm/agents/dev.agent.yaml +0 -40
- package/src/modules/bmm/agents/pm.agent.yaml +0 -61
- package/src/modules/bmm/agents/sm.agent.yaml +0 -72
- package/src/modules/bmm/agents/tea.agent.yaml +0 -65
- package/src/modules/bmm/agents/tech-writer.agent.yaml +0 -73
- package/src/modules/bmm/agents/ux-designer.agent.yaml +0 -38
- package/src/modules/bmm/docs/README.md +0 -235
- package/src/modules/bmm/docs/agents-guide.md +0 -1056
- package/src/modules/bmm/docs/brownfield-guide.md +0 -754
- package/src/modules/bmm/docs/enterprise-agentic-development.md +0 -680
- package/src/modules/bmm/docs/faq.md +0 -587
- package/src/modules/bmm/docs/glossary.md +0 -320
- package/src/modules/bmm/docs/party-mode.md +0 -224
- package/src/modules/bmm/docs/quick-spec-flow.md +0 -652
- package/src/modules/bmm/docs/quick-start.md +0 -366
- package/src/modules/bmm/docs/scale-adaptive-system.md +0 -599
- package/src/modules/bmm/docs/test-architecture.md +0 -394
- package/src/modules/bmm/docs/workflow-architecture-reference.md +0 -371
- package/src/modules/bmm/docs/workflow-document-project-reference.md +0 -487
- package/src/modules/bmm/docs/workflows-analysis.md +0 -370
- package/src/modules/bmm/docs/workflows-implementation.md +0 -284
- package/src/modules/bmm/docs/workflows-planning.md +0 -601
- package/src/modules/bmm/docs/workflows-solutioning.md +0 -501
- package/src/modules/bmm/teams/default-party.csv +0 -19
- package/src/modules/bmm/testarch/knowledge/ci-burn-in.md +0 -675
- package/src/modules/bmm/testarch/knowledge/component-tdd.md +0 -486
- package/src/modules/bmm/testarch/knowledge/contract-testing.md +0 -957
- package/src/modules/bmm/testarch/knowledge/data-factories.md +0 -500
- package/src/modules/bmm/testarch/knowledge/email-auth.md +0 -721
- package/src/modules/bmm/testarch/knowledge/error-handling.md +0 -725
- package/src/modules/bmm/testarch/knowledge/feature-flags.md +0 -750
- package/src/modules/bmm/testarch/knowledge/fixture-architecture.md +0 -401
- package/src/modules/bmm/testarch/knowledge/network-first.md +0 -486
- package/src/modules/bmm/testarch/knowledge/nfr-criteria.md +0 -670
- package/src/modules/bmm/testarch/knowledge/playwright-config.md +0 -730
- package/src/modules/bmm/testarch/knowledge/probability-impact.md +0 -601
- package/src/modules/bmm/testarch/knowledge/risk-governance.md +0 -615
- package/src/modules/bmm/testarch/knowledge/selective-testing.md +0 -732
- package/src/modules/bmm/testarch/knowledge/selector-resilience.md +0 -527
- package/src/modules/bmm/testarch/knowledge/test-healing-patterns.md +0 -644
- package/src/modules/bmm/testarch/knowledge/test-levels-framework.md +0 -473
- package/src/modules/bmm/testarch/knowledge/test-priorities-matrix.md +0 -373
- package/src/modules/bmm/testarch/knowledge/test-quality.md +0 -664
- package/src/modules/bmm/testarch/knowledge/timing-debugging.md +0 -372
- package/src/modules/bmm/testarch/knowledge/visual-debugging.md +0 -524
- package/src/modules/bmm/testarch/tea-index.csv +0 -22
- package/src/modules/bmm/workflows/1-analysis/brainstorm-project/instructions.md +0 -110
- package/src/modules/bmm/workflows/1-analysis/brainstorm-project/project-context.md +0 -25
- package/src/modules/bmm/workflows/1-analysis/brainstorm-project/workflow.yaml +0 -39
- package/src/modules/bmm/workflows/1-analysis/domain-research/instructions.md +0 -423
- package/src/modules/bmm/workflows/1-analysis/domain-research/template.md +0 -180
- package/src/modules/bmm/workflows/1-analysis/domain-research/workflow.yaml +0 -56
- package/src/modules/bmm/workflows/1-analysis/product-brief/checklist.md +0 -115
- package/src/modules/bmm/workflows/1-analysis/product-brief/instructions.md +0 -522
- package/src/modules/bmm/workflows/1-analysis/product-brief/template.md +0 -181
- package/src/modules/bmm/workflows/1-analysis/product-brief/workflow.yaml +0 -65
- package/src/modules/bmm/workflows/1-analysis/research/checklist-deep-prompt.md +0 -144
- package/src/modules/bmm/workflows/1-analysis/research/checklist-technical.md +0 -249
- package/src/modules/bmm/workflows/1-analysis/research/checklist.md +0 -299
- package/src/modules/bmm/workflows/1-analysis/research/claude-code/injections.yaml +0 -114
- package/src/modules/bmm/workflows/1-analysis/research/instructions-deep-prompt.md +0 -437
- package/src/modules/bmm/workflows/1-analysis/research/instructions-market.md +0 -674
- package/src/modules/bmm/workflows/1-analysis/research/instructions-router.md +0 -133
- package/src/modules/bmm/workflows/1-analysis/research/instructions-technical.md +0 -533
- package/src/modules/bmm/workflows/1-analysis/research/template-deep-prompt.md +0 -94
- package/src/modules/bmm/workflows/1-analysis/research/template-market.md +0 -347
- package/src/modules/bmm/workflows/1-analysis/research/template-technical.md +0 -245
- package/src/modules/bmm/workflows/1-analysis/research/workflow.yaml +0 -62
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/checklist.md +0 -310
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/instructions.md +0 -1306
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/ux-design-template.md +0 -145
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/workflow.yaml +0 -99
- package/src/modules/bmm/workflows/2-plan-workflows/prd/checklist.md +0 -346
- package/src/modules/bmm/workflows/2-plan-workflows/prd/create-epics-and-stories/epics-template.md +0 -80
- package/src/modules/bmm/workflows/2-plan-workflows/prd/create-epics-and-stories/instructions.md +0 -292
- package/src/modules/bmm/workflows/2-plan-workflows/prd/create-epics-and-stories/workflow.yaml +0 -53
- package/src/modules/bmm/workflows/2-plan-workflows/prd/domain-complexity.csv +0 -13
- package/src/modules/bmm/workflows/2-plan-workflows/prd/instructions.md +0 -525
- package/src/modules/bmm/workflows/2-plan-workflows/prd/prd-template.md +0 -237
- package/src/modules/bmm/workflows/2-plan-workflows/prd/project-types.csv +0 -11
- package/src/modules/bmm/workflows/2-plan-workflows/prd/workflow.yaml +0 -76
- package/src/modules/bmm/workflows/2-plan-workflows/tech-spec/checklist.md +0 -217
- package/src/modules/bmm/workflows/2-plan-workflows/tech-spec/epics-template.md +0 -74
- package/src/modules/bmm/workflows/2-plan-workflows/tech-spec/instructions-generate-stories.md +0 -434
- package/src/modules/bmm/workflows/2-plan-workflows/tech-spec/instructions.md +0 -978
- package/src/modules/bmm/workflows/2-plan-workflows/tech-spec/tech-spec-template.md +0 -181
- package/src/modules/bmm/workflows/2-plan-workflows/tech-spec/user-story-template.md +0 -90
- package/src/modules/bmm/workflows/2-plan-workflows/tech-spec/workflow.yaml +0 -57
- package/src/modules/bmm/workflows/3-solutioning/architecture/architecture-patterns.yaml +0 -321
- package/src/modules/bmm/workflows/3-solutioning/architecture/architecture-template.md +0 -103
- package/src/modules/bmm/workflows/3-solutioning/architecture/checklist.md +0 -240
- package/src/modules/bmm/workflows/3-solutioning/architecture/decision-catalog.yaml +0 -222
- package/src/modules/bmm/workflows/3-solutioning/architecture/instructions.md +0 -696
- package/src/modules/bmm/workflows/3-solutioning/architecture/pattern-categories.csv +0 -13
- package/src/modules/bmm/workflows/3-solutioning/architecture/workflow.yaml +0 -96
- package/src/modules/bmm/workflows/3-solutioning/solutioning-gate-check/checklist.md +0 -169
- package/src/modules/bmm/workflows/3-solutioning/solutioning-gate-check/instructions.md +0 -302
- package/src/modules/bmm/workflows/3-solutioning/solutioning-gate-check/template.md +0 -146
- package/src/modules/bmm/workflows/3-solutioning/solutioning-gate-check/workflow.yaml +0 -66
- package/src/modules/bmm/workflows/4-implementation/code-review/backlog_template.md +0 -12
- package/src/modules/bmm/workflows/4-implementation/code-review/checklist.md +0 -22
- package/src/modules/bmm/workflows/4-implementation/code-review/instructions.md +0 -398
- package/src/modules/bmm/workflows/4-implementation/code-review/workflow.yaml +0 -57
- package/src/modules/bmm/workflows/4-implementation/correct-course/checklist.md +0 -279
- package/src/modules/bmm/workflows/4-implementation/correct-course/instructions.md +0 -206
- package/src/modules/bmm/workflows/4-implementation/correct-course/workflow.yaml +0 -52
- package/src/modules/bmm/workflows/4-implementation/create-story/checklist.md +0 -240
- package/src/modules/bmm/workflows/4-implementation/create-story/instructions.md +0 -256
- package/src/modules/bmm/workflows/4-implementation/create-story/template.md +0 -51
- package/src/modules/bmm/workflows/4-implementation/create-story/workflow.yaml +0 -68
- package/src/modules/bmm/workflows/4-implementation/dev-story/checklist.md +0 -38
- package/src/modules/bmm/workflows/4-implementation/dev-story/instructions.md +0 -267
- package/src/modules/bmm/workflows/4-implementation/dev-story/workflow.yaml +0 -53
- package/src/modules/bmm/workflows/4-implementation/epic-tech-context/checklist.md +0 -17
- package/src/modules/bmm/workflows/4-implementation/epic-tech-context/instructions.md +0 -164
- package/src/modules/bmm/workflows/4-implementation/epic-tech-context/template.md +0 -76
- package/src/modules/bmm/workflows/4-implementation/epic-tech-context/workflow.yaml +0 -52
- package/src/modules/bmm/workflows/4-implementation/retrospective/instructions.md +0 -1442
- package/src/modules/bmm/workflows/4-implementation/retrospective/workflow.yaml +0 -52
- package/src/modules/bmm/workflows/4-implementation/sprint-planning/checklist.md +0 -33
- package/src/modules/bmm/workflows/4-implementation/sprint-planning/instructions.md +0 -234
- package/src/modules/bmm/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +0 -55
- package/src/modules/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +0 -50
- package/src/modules/bmm/workflows/4-implementation/story-context/checklist.md +0 -16
- package/src/modules/bmm/workflows/4-implementation/story-context/context-template.xml +0 -34
- package/src/modules/bmm/workflows/4-implementation/story-context/instructions.md +0 -209
- package/src/modules/bmm/workflows/4-implementation/story-context/workflow.yaml +0 -57
- package/src/modules/bmm/workflows/4-implementation/story-done/instructions.md +0 -111
- package/src/modules/bmm/workflows/4-implementation/story-done/workflow.yaml +0 -28
- package/src/modules/bmm/workflows/4-implementation/story-ready/instructions.md +0 -117
- package/src/modules/bmm/workflows/4-implementation/story-ready/workflow.yaml +0 -25
- package/src/modules/bmm/workflows/document-project/checklist.md +0 -245
- package/src/modules/bmm/workflows/document-project/instructions.md +0 -222
- package/src/modules/bmm/workflows/document-project/templates/project-scan-report-schema.json +0 -160
- package/src/modules/bmm/workflows/document-project/workflow.yaml +0 -36
- package/src/modules/bmm/workflows/document-project/workflows/deep-dive-instructions.md +0 -298
- package/src/modules/bmm/workflows/document-project/workflows/deep-dive.yaml +0 -31
- package/src/modules/bmm/workflows/document-project/workflows/full-scan-instructions.md +0 -1106
- package/src/modules/bmm/workflows/document-project/workflows/full-scan.yaml +0 -31
- package/src/modules/bmm/workflows/techdoc/documentation-standards.md +0 -262
- package/src/modules/bmm/workflows/testarch/atdd/atdd-checklist-template.md +0 -363
- package/src/modules/bmm/workflows/testarch/atdd/checklist.md +0 -373
- package/src/modules/bmm/workflows/testarch/atdd/instructions.md +0 -785
- package/src/modules/bmm/workflows/testarch/atdd/workflow.yaml +0 -54
- package/src/modules/bmm/workflows/testarch/automate/checklist.md +0 -580
- package/src/modules/bmm/workflows/testarch/automate/instructions.md +0 -1303
- package/src/modules/bmm/workflows/testarch/automate/workflow.yaml +0 -63
- package/src/modules/bmm/workflows/testarch/ci/checklist.md +0 -246
- package/src/modules/bmm/workflows/testarch/ci/github-actions-template.yaml +0 -165
- package/src/modules/bmm/workflows/testarch/ci/gitlab-ci-template.yaml +0 -128
- package/src/modules/bmm/workflows/testarch/ci/instructions.md +0 -517
- package/src/modules/bmm/workflows/testarch/ci/workflow.yaml +0 -55
- package/src/modules/bmm/workflows/testarch/framework/checklist.md +0 -321
- package/src/modules/bmm/workflows/testarch/framework/instructions.md +0 -455
- package/src/modules/bmm/workflows/testarch/framework/workflow.yaml +0 -55
- package/src/modules/bmm/workflows/testarch/nfr-assess/checklist.md +0 -405
- package/src/modules/bmm/workflows/testarch/nfr-assess/instructions.md +0 -722
- package/src/modules/bmm/workflows/testarch/nfr-assess/nfr-report-template.md +0 -443
- package/src/modules/bmm/workflows/testarch/nfr-assess/workflow.yaml +0 -58
- package/src/modules/bmm/workflows/testarch/test-design/checklist.md +0 -234
- package/src/modules/bmm/workflows/testarch/test-design/instructions.md +0 -782
- package/src/modules/bmm/workflows/testarch/test-design/test-design-template.md +0 -285
- package/src/modules/bmm/workflows/testarch/test-design/workflow.yaml +0 -58
- package/src/modules/bmm/workflows/testarch/test-review/checklist.md +0 -470
- package/src/modules/bmm/workflows/testarch/test-review/instructions.md +0 -608
- package/src/modules/bmm/workflows/testarch/test-review/test-review-template.md +0 -388
- package/src/modules/bmm/workflows/testarch/test-review/workflow.yaml +0 -55
- package/src/modules/bmm/workflows/testarch/trace/checklist.md +0 -654
- package/src/modules/bmm/workflows/testarch/trace/instructions.md +0 -1045
- package/src/modules/bmm/workflows/testarch/trace/trace-template.md +0 -673
- package/src/modules/bmm/workflows/testarch/trace/workflow.yaml +0 -68
- package/src/modules/bmm/workflows/workflow-status/init/instructions.md +0 -823
- package/src/modules/bmm/workflows/workflow-status/init/workflow.yaml +0 -29
- package/src/modules/bmm/workflows/workflow-status/instructions.md +0 -387
- package/src/modules/bmm/workflows/workflow-status/paths/enterprise-brownfield.yaml +0 -120
- package/src/modules/bmm/workflows/workflow-status/paths/enterprise-greenfield.yaml +0 -108
- package/src/modules/bmm/workflows/workflow-status/paths/game-design.yaml +0 -52
- package/src/modules/bmm/workflows/workflow-status/paths/method-brownfield.yaml +0 -104
- package/src/modules/bmm/workflows/workflow-status/paths/method-greenfield.yaml +0 -95
- package/src/modules/bmm/workflows/workflow-status/paths/quick-flow-brownfield.yaml +0 -58
- package/src/modules/bmm/workflows/workflow-status/paths/quick-flow-greenfield.yaml +0 -47
- package/src/modules/bmm/workflows/workflow-status/project-levels.yaml +0 -59
- package/src/modules/bmm/workflows/workflow-status/workflow-status-template.yaml +0 -24
- package/src/modules/bmm/workflows/workflow-status/workflow.yaml +0 -30
- package/src/modules/cis/README.md +0 -153
- package/src/modules/cis/_module-installer/install-config.yaml +0 -16
- package/src/modules/cis/_module-installer/installer.js +0 -92
- package/src/modules/cis/agents/README.md +0 -104
- package/src/modules/cis/agents/brainstorming-coach.agent.yaml +0 -28
- package/src/modules/cis/agents/creative-problem-solver.agent.yaml +0 -28
- package/src/modules/cis/agents/design-thinking-coach.agent.yaml +0 -28
- package/src/modules/cis/agents/innovation-strategist.agent.yaml +0 -28
- package/src/modules/cis/agents/storyteller.agent.yaml +0 -28
- package/src/modules/cis/teams/creative-squad.yaml +0 -7
- package/src/modules/cis/teams/default-party.csv +0 -11
- package/src/modules/cis/workflows/README.md +0 -139
- package/src/modules/cis/workflows/design-thinking/README.md +0 -56
- package/src/modules/cis/workflows/design-thinking/design-methods.csv +0 -31
- package/src/modules/cis/workflows/design-thinking/instructions.md +0 -200
- package/src/modules/cis/workflows/design-thinking/template.md +0 -111
- package/src/modules/cis/workflows/design-thinking/workflow.yaml +0 -43
- package/src/modules/cis/workflows/innovation-strategy/README.md +0 -56
- package/src/modules/cis/workflows/innovation-strategy/innovation-frameworks.csv +0 -31
- package/src/modules/cis/workflows/innovation-strategy/instructions.md +0 -274
- package/src/modules/cis/workflows/innovation-strategy/template.md +0 -189
- package/src/modules/cis/workflows/innovation-strategy/workflow.yaml +0 -43
- package/src/modules/cis/workflows/problem-solving/README.md +0 -56
- package/src/modules/cis/workflows/problem-solving/instructions.md +0 -250
- package/src/modules/cis/workflows/problem-solving/solving-methods.csv +0 -31
- package/src/modules/cis/workflows/problem-solving/template.md +0 -165
- package/src/modules/cis/workflows/problem-solving/workflow.yaml +0 -43
- package/src/modules/cis/workflows/storytelling/README.md +0 -58
- package/src/modules/cis/workflows/storytelling/instructions.md +0 -291
- package/src/modules/cis/workflows/storytelling/story-types.csv +0 -26
- package/src/modules/cis/workflows/storytelling/template.md +0 -113
- package/src/modules/cis/workflows/storytelling/workflow.yaml +0 -43
- package/src/utility/models/agent-activation-ide.xml +0 -51
- package/src/utility/models/agent-activation-web.xml +0 -60
- package/src/utility/models/agent-command-header.md +0 -1
- package/src/utility/models/agent-config-template.md +0 -23
- package/src/utility/models/agent-in-team-activation.xml +0 -3
- package/src/utility/models/fragments/activation-rules.xml +0 -8
- package/src/utility/models/fragments/activation-steps.xml +0 -16
- package/src/utility/models/fragments/handler-action.xml +0 -4
- package/src/utility/models/fragments/handler-exec.xml +0 -5
- package/src/utility/models/fragments/handler-tmpl.xml +0 -5
- package/src/utility/models/fragments/handler-validate-workflow.xml +0 -7
- package/src/utility/models/fragments/handler-workflow.xml +0 -9
- package/src/utility/models/fragments/menu-handlers.xml +0 -6
- package/src/utility/models/fragments/web-bundle-activation-steps.xml +0 -32
- package/src/utility/templates/agent.customize.template.yaml +0 -42
- package/test/fixtures/agent-schema/invalid/metadata/core-agent-with-module.agent.yaml +0 -26
- package/test/fixtures/agent-schema/invalid/metadata/module-agent-missing-module.agent.yaml +0 -25
- package/test/fixtures/agent-schema/invalid/metadata/wrong-module-value.agent.yaml +0 -26
- package/tools/cli/bundlers/bundle-web.js +0 -179
- package/tools/cli/bundlers/test-analyst.js +0 -28
- package/tools/cli/bundlers/test-bundler.js +0 -118
- package/tools/cli/bundlers/web-bundler.js +0 -1667
- package/tools/cli/commands/build.js +0 -458
- package/tools/cli/commands/list.js +0 -28
- package/tools/cli/commands/update.js +0 -28
- package/tools/cli/installers/lib/ide/auggie.js +0 -179
- package/tools/cli/installers/lib/ide/claude-code.js +0 -471
- package/tools/cli/installers/lib/ide/cline.js +0 -220
- package/tools/cli/installers/lib/ide/crush.js +0 -240
- package/tools/cli/installers/lib/ide/cursor.js +0 -352
- package/tools/cli/installers/lib/ide/gemini.js +0 -206
- package/tools/cli/installers/lib/ide/iflow.js +0 -125
- package/tools/cli/installers/lib/ide/opencode.js +0 -212
- package/tools/cli/installers/lib/ide/qwen.js +0 -318
- package/tools/cli/installers/lib/ide/roo.js +0 -253
- package/tools/cli/installers/lib/ide/templates/gemini-agent-command.toml +0 -14
- package/tools/cli/installers/lib/ide/templates/gemini-task-command.toml +0 -12
- package/tools/cli/installers/lib/ide/trae.js +0 -266
- package/tools/cli/installers/lib/ide/windsurf.js +0 -211
- package/tools/cli/lib/replace-project-root.js +0 -239
- package/tools/cli/regenerate-manifests.js +0 -28
- package/tools/cli/test-yaml-builder.js +0 -43
- package/tools/flattener/aggregate.js +0 -76
- package/tools/flattener/binary.js +0 -80
- package/tools/flattener/discovery.js +0 -71
- package/tools/flattener/files.js +0 -35
- package/tools/flattener/ignoreRules.js +0 -172
- package/tools/flattener/main.js +0 -483
- package/tools/flattener/projectRoot.js +0 -201
- package/tools/flattener/prompts.js +0 -44
- package/tools/flattener/stats.helpers.js +0 -368
- package/tools/flattener/stats.js +0 -75
- package/tools/flattener/test-matrix.js +0 -409
- package/tools/flattener/xml.js +0 -88
- package/tools/validate-bundles.js +0 -87
- package/v6-open-items.md +0 -17
- /package/src/{modules/bmm → bmm}/teams/team-fullstack.yaml +0 -0
- /package/src/{modules/bmgd/workflows/4-production → bmm/workflows/4-implementation}/sprint-planning/checklist.md +0 -0
- /package/src/{modules/bmm → bmm}/workflows/document-project/documentation-requirements.csv +0 -0
- /package/src/{modules/bmm → bmm}/workflows/document-project/templates/deep-dive-template.md +0 -0
- /package/src/{modules/bmm → bmm}/workflows/document-project/templates/index-template.md +0 -0
- /package/src/{modules/bmm → bmm}/workflows/document-project/templates/project-overview-template.md +0 -0
- /package/src/{modules/bmm → bmm}/workflows/document-project/templates/source-tree-template.md +0 -0
- /package/src/utility/{models/fragments/handler-data.xml → agent-components/handler-data.txt} +0 -0
- /package/{src/utility/models/action-command-header.md → tools/cli/installers/lib/ide/templates/split/.gitkeep} +0 -0
package/tools/cli/lib/ui.js
CHANGED
|
@@ -1,26 +1,55 @@
|
|
|
1
|
-
const chalk = require('chalk');
|
|
2
|
-
const inquirer = require('inquirer');
|
|
3
1
|
const path = require('node:path');
|
|
4
2
|
const os = require('node:os');
|
|
5
3
|
const fs = require('fs-extra');
|
|
6
4
|
const { CLIUtils } = require('./cli-utils');
|
|
5
|
+
const { CustomHandler } = require('../installers/lib/custom/handler');
|
|
6
|
+
const { ExternalModuleManager } = require('../installers/lib/modules/external-manager');
|
|
7
|
+
const prompts = require('./prompts');
|
|
8
|
+
|
|
9
|
+
// Separator class for visual grouping in select/multiselect prompts
|
|
10
|
+
// Note: @clack/prompts doesn't support separators natively, they are filtered out
|
|
11
|
+
class Separator {
|
|
12
|
+
constructor(text = '────────') {
|
|
13
|
+
this.line = text;
|
|
14
|
+
this.name = text;
|
|
15
|
+
}
|
|
16
|
+
type = 'separator';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Separator for choice lists (compatible interface)
|
|
20
|
+
const choiceUtils = { Separator };
|
|
7
21
|
|
|
8
22
|
/**
|
|
9
23
|
* UI utilities for the installer
|
|
10
24
|
*/
|
|
11
25
|
class UI {
|
|
12
|
-
constructor() {}
|
|
13
|
-
|
|
14
26
|
/**
|
|
15
27
|
* Prompt for installation configuration
|
|
28
|
+
* @param {Object} options - Command-line options from install command
|
|
16
29
|
* @returns {Object} Installation configuration
|
|
17
30
|
*/
|
|
18
|
-
async promptInstall() {
|
|
19
|
-
CLIUtils.displayLogo();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
31
|
+
async promptInstall(options = {}) {
|
|
32
|
+
await CLIUtils.displayLogo();
|
|
33
|
+
|
|
34
|
+
// Display version-specific start message from install-messages.yaml
|
|
35
|
+
const { MessageLoader } = require('../installers/lib/message-loader');
|
|
36
|
+
const messageLoader = new MessageLoader();
|
|
37
|
+
await messageLoader.displayStartMessage();
|
|
38
|
+
|
|
39
|
+
// Get directory from options or prompt
|
|
40
|
+
let confirmedDirectory;
|
|
41
|
+
if (options.directory) {
|
|
42
|
+
// Use provided directory from command-line
|
|
43
|
+
const expandedDir = this.expandUserPath(options.directory);
|
|
44
|
+
const validation = this.validateDirectorySync(expandedDir);
|
|
45
|
+
if (validation) {
|
|
46
|
+
throw new Error(`Invalid directory: ${validation}`);
|
|
47
|
+
}
|
|
48
|
+
confirmedDirectory = expandedDir;
|
|
49
|
+
await prompts.log.info(`Using directory from command-line: ${confirmedDirectory}`);
|
|
50
|
+
} else {
|
|
51
|
+
confirmedDirectory = await this.getConfirmedDirectory();
|
|
52
|
+
}
|
|
24
53
|
|
|
25
54
|
// Preflight: Check for legacy BMAD v4 footprints immediately after getting directory
|
|
26
55
|
const { Detector } = require('../installers/lib/core/detector');
|
|
@@ -32,188 +61,718 @@ class UI {
|
|
|
32
61
|
await installer.handleLegacyV4Migration(confirmedDirectory, legacyV4);
|
|
33
62
|
}
|
|
34
63
|
|
|
35
|
-
// Check
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
64
|
+
// Check for legacy folders and prompt for rename before showing any menus
|
|
65
|
+
let hasLegacyCfg = false;
|
|
66
|
+
let hasLegacyBmadFolder = false;
|
|
67
|
+
let bmadDir = null;
|
|
68
|
+
let legacyBmadPath = null;
|
|
69
|
+
|
|
70
|
+
// First check for legacy .bmad folder (instead of _bmad)
|
|
71
|
+
// Only check if directory exists
|
|
72
|
+
if (await fs.pathExists(confirmedDirectory)) {
|
|
73
|
+
const entries = await fs.readdir(confirmedDirectory, { withFileTypes: true });
|
|
74
|
+
for (const entry of entries) {
|
|
75
|
+
if (entry.isDirectory() && (entry.name === '.bmad' || entry.name === 'bmad')) {
|
|
76
|
+
hasLegacyBmadFolder = true;
|
|
77
|
+
legacyBmadPath = path.join(confirmedDirectory, entry.name);
|
|
78
|
+
bmadDir = legacyBmadPath;
|
|
79
|
+
|
|
80
|
+
// Check if it has _cfg folder
|
|
81
|
+
const cfgPath = path.join(legacyBmadPath, '_cfg');
|
|
82
|
+
if (await fs.pathExists(cfgPath)) {
|
|
83
|
+
hasLegacyCfg = true;
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// If no .bmad or bmad found, check for current installations _bmad
|
|
91
|
+
if (!hasLegacyBmadFolder) {
|
|
92
|
+
const bmadResult = await installer.findBmadDir(confirmedDirectory);
|
|
93
|
+
bmadDir = bmadResult.bmadDir;
|
|
94
|
+
hasLegacyCfg = bmadResult.hasLegacyCfg;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Handle legacy .bmad or _cfg folder - these are very old (v4 or alpha)
|
|
98
|
+
// Show version warning instead of offering conversion
|
|
99
|
+
if (hasLegacyBmadFolder || hasLegacyCfg) {
|
|
100
|
+
await prompts.log.warn('LEGACY INSTALLATION DETECTED');
|
|
101
|
+
await prompts.note(
|
|
102
|
+
'Found a ".bmad"/"bmad" folder, or a legacy "_cfg" folder under the bmad folder -\n' +
|
|
103
|
+
'this is from an old BMAD version that is out of date for automatic upgrade,\n' +
|
|
104
|
+
'manual intervention required.\n\n' +
|
|
105
|
+
'You have a legacy version installed (v4 or alpha).\n' +
|
|
106
|
+
'Legacy installations may have compatibility issues.\n\n' +
|
|
107
|
+
'For the best experience, we strongly recommend:\n' +
|
|
108
|
+
' 1. Delete your current BMAD installation folder (.bmad or bmad)\n' +
|
|
109
|
+
' 2. Run a fresh installation\n\n' +
|
|
110
|
+
'If you do not want to start fresh, you can attempt to proceed beyond this\n' +
|
|
111
|
+
'point IF you have ensured the bmad folder is named _bmad, and under it there\n' +
|
|
112
|
+
'is a _config folder. If you have a folder under your bmad folder named _cfg,\n' +
|
|
113
|
+
'you would need to rename it _config, and then restart the installer.\n\n' +
|
|
114
|
+
'Benefits of a fresh install:\n' +
|
|
115
|
+
' \u2022 Cleaner configuration without legacy artifacts\n' +
|
|
116
|
+
' \u2022 All new features properly configured\n' +
|
|
117
|
+
' \u2022 Fewer potential conflicts\n\n' +
|
|
118
|
+
'If you have already produced output from an earlier alpha version, you can\n' +
|
|
119
|
+
'still retain those artifacts. After installation, ensure you configured during\n' +
|
|
120
|
+
'install the proper file locations for artifacts depending on the module you\n' +
|
|
121
|
+
'are using, or move the files to the proper locations.',
|
|
122
|
+
'Legacy Installation Detected',
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const proceed = await prompts.select({
|
|
126
|
+
message: 'How would you like to proceed?',
|
|
127
|
+
choices: [
|
|
128
|
+
{
|
|
129
|
+
name: 'Cancel and do a fresh install (recommended)',
|
|
130
|
+
value: 'cancel',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'Proceed anyway (will attempt update, potentially may fail or have unstable behavior)',
|
|
134
|
+
value: 'proceed',
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
default: 'cancel',
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (proceed === 'cancel') {
|
|
141
|
+
await prompts.note('1. Delete the existing bmad folder in your project\n' + "2. Run 'bmad install' again", 'To do a fresh install');
|
|
142
|
+
process.exit(0);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const s = await prompts.spinner();
|
|
147
|
+
s.start('Updating folder structure...');
|
|
148
|
+
try {
|
|
149
|
+
// Handle .bmad folder
|
|
150
|
+
if (hasLegacyBmadFolder) {
|
|
151
|
+
const newBmadPath = path.join(confirmedDirectory, '_bmad');
|
|
152
|
+
await fs.move(legacyBmadPath, newBmadPath);
|
|
153
|
+
bmadDir = newBmadPath;
|
|
154
|
+
s.stop(`Renamed "${path.basename(legacyBmadPath)}" to "_bmad"`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Handle _cfg folder (either from .bmad or standalone)
|
|
158
|
+
const cfgPath = path.join(bmadDir, '_cfg');
|
|
159
|
+
if (await fs.pathExists(cfgPath)) {
|
|
160
|
+
s.start('Renaming configuration folder...');
|
|
161
|
+
const newCfgPath = path.join(bmadDir, '_config');
|
|
162
|
+
await fs.move(cfgPath, newCfgPath);
|
|
163
|
+
s.stop('Renamed "_cfg" to "_config"');
|
|
164
|
+
}
|
|
165
|
+
} catch (error) {
|
|
166
|
+
s.stop('Failed to update folder structure');
|
|
167
|
+
await prompts.log.error(`Error: ${error.message}`);
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Check if there's an existing BMAD installation (after any folder renames)
|
|
40
173
|
const hasExistingInstall = await fs.pathExists(bmadDir);
|
|
41
174
|
|
|
175
|
+
let customContentConfig = { hasCustomContent: false };
|
|
176
|
+
if (!hasExistingInstall) {
|
|
177
|
+
customContentConfig._shouldAsk = true;
|
|
178
|
+
}
|
|
179
|
+
|
|
42
180
|
// Track action type (only set if there's an existing installation)
|
|
43
181
|
let actionType;
|
|
44
182
|
|
|
45
183
|
// Only show action menu if there's an existing installation
|
|
46
184
|
if (hasExistingInstall) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
185
|
+
// Get version information
|
|
186
|
+
const { existingInstall, bmadDir } = await this.getExistingInstallation(confirmedDirectory);
|
|
187
|
+
const packageJsonPath = path.join(__dirname, '../../../package.json');
|
|
188
|
+
const currentVersion = require(packageJsonPath).version;
|
|
189
|
+
const installedVersion = existingInstall.version || 'unknown';
|
|
190
|
+
|
|
191
|
+
// Check if version is pre beta
|
|
192
|
+
const shouldProceed = await this.showLegacyVersionWarning(installedVersion, currentVersion, path.basename(bmadDir), options);
|
|
193
|
+
|
|
194
|
+
// If user chose to cancel, exit the installer
|
|
195
|
+
if (!shouldProceed) {
|
|
196
|
+
process.exit(0);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Build menu choices dynamically
|
|
201
|
+
const choices = [];
|
|
202
|
+
|
|
203
|
+
// Always show Quick Update first (allows refreshing installation even on same version)
|
|
204
|
+
if (installedVersion !== 'unknown') {
|
|
205
|
+
choices.push({
|
|
206
|
+
name: `Quick Update (v${installedVersion} → v${currentVersion})`,
|
|
207
|
+
value: 'quick-update',
|
|
208
|
+
});
|
|
209
|
+
}
|
|
62
210
|
|
|
63
|
-
//
|
|
64
|
-
|
|
211
|
+
// Add custom agent compilation option
|
|
212
|
+
if (installedVersion !== 'unknown') {
|
|
213
|
+
choices.push({
|
|
214
|
+
name: 'Recompile Agents (apply customizations only)',
|
|
215
|
+
value: 'compile-agents',
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Common actions
|
|
220
|
+
choices.push({ name: 'Modify BMAD Installation', value: 'update' });
|
|
221
|
+
|
|
222
|
+
// Check if action is provided via command-line
|
|
223
|
+
if (options.action) {
|
|
224
|
+
const validActions = choices.map((c) => c.value);
|
|
225
|
+
if (!validActions.includes(options.action)) {
|
|
226
|
+
throw new Error(`Invalid action: ${options.action}. Valid actions: ${validActions.join(', ')}`);
|
|
227
|
+
}
|
|
228
|
+
actionType = options.action;
|
|
229
|
+
await prompts.log.info(`Using action from command-line: ${actionType}`);
|
|
230
|
+
} else if (options.yes) {
|
|
231
|
+
// Default to quick-update if available, otherwise first available choice
|
|
232
|
+
if (choices.length === 0) {
|
|
233
|
+
throw new Error('No valid actions available for this installation');
|
|
234
|
+
}
|
|
235
|
+
const hasQuickUpdate = choices.some((c) => c.value === 'quick-update');
|
|
236
|
+
actionType = hasQuickUpdate ? 'quick-update' : choices[0].value;
|
|
237
|
+
await prompts.log.info(`Non-interactive mode (--yes): defaulting to ${actionType}`);
|
|
238
|
+
} else {
|
|
239
|
+
actionType = await prompts.select({
|
|
240
|
+
message: 'How would you like to proceed?',
|
|
241
|
+
choices: choices,
|
|
242
|
+
default: choices[0].value,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
65
245
|
|
|
66
246
|
// Handle quick update separately
|
|
67
247
|
if (actionType === 'quick-update') {
|
|
248
|
+
// Pass --custom-content through so installer can re-cache if cache is missing
|
|
249
|
+
let customContentForQuickUpdate = { hasCustomContent: false };
|
|
250
|
+
if (options.customContent) {
|
|
251
|
+
const paths = options.customContent
|
|
252
|
+
.split(',')
|
|
253
|
+
.map((p) => p.trim())
|
|
254
|
+
.filter(Boolean);
|
|
255
|
+
if (paths.length > 0) {
|
|
256
|
+
const customPaths = [];
|
|
257
|
+
const selectedModuleIds = [];
|
|
258
|
+
const sources = [];
|
|
259
|
+
for (const customPath of paths) {
|
|
260
|
+
const expandedPath = this.expandUserPath(customPath);
|
|
261
|
+
const validation = this.validateCustomContentPathSync(expandedPath);
|
|
262
|
+
if (validation) continue;
|
|
263
|
+
let moduleMeta;
|
|
264
|
+
try {
|
|
265
|
+
const moduleYamlPath = path.join(expandedPath, 'module.yaml');
|
|
266
|
+
moduleMeta = require('yaml').parse(await fs.readFile(moduleYamlPath, 'utf-8'));
|
|
267
|
+
} catch {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (!moduleMeta?.code) continue;
|
|
271
|
+
customPaths.push(expandedPath);
|
|
272
|
+
selectedModuleIds.push(moduleMeta.code);
|
|
273
|
+
sources.push({ path: expandedPath, id: moduleMeta.code, name: moduleMeta.name || moduleMeta.code });
|
|
274
|
+
}
|
|
275
|
+
if (customPaths.length > 0) {
|
|
276
|
+
customContentForQuickUpdate = {
|
|
277
|
+
hasCustomContent: true,
|
|
278
|
+
selected: true,
|
|
279
|
+
sources,
|
|
280
|
+
selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')),
|
|
281
|
+
selectedModuleIds,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
68
286
|
return {
|
|
69
287
|
actionType: 'quick-update',
|
|
70
288
|
directory: confirmedDirectory,
|
|
289
|
+
customContent: customContentForQuickUpdate,
|
|
290
|
+
skipPrompts: options.yes || false,
|
|
71
291
|
};
|
|
72
292
|
}
|
|
73
293
|
|
|
74
|
-
// Handle
|
|
75
|
-
if (actionType === 'compile') {
|
|
294
|
+
// Handle compile agents separately
|
|
295
|
+
if (actionType === 'compile-agents') {
|
|
296
|
+
// Only recompile agents with customizations, don't update any files
|
|
76
297
|
return {
|
|
77
|
-
actionType: 'compile',
|
|
298
|
+
actionType: 'compile-agents',
|
|
78
299
|
directory: confirmedDirectory,
|
|
300
|
+
customContent: { hasCustomContent: false },
|
|
301
|
+
skipPrompts: options.yes || false,
|
|
79
302
|
};
|
|
80
303
|
}
|
|
81
304
|
|
|
82
|
-
//
|
|
83
|
-
|
|
305
|
+
// If actionType === 'update', handle it with the new flow
|
|
306
|
+
// Return early with modify configuration
|
|
307
|
+
if (actionType === 'update') {
|
|
308
|
+
// Get existing installation info
|
|
309
|
+
const { installedModuleIds } = await this.getExistingInstallation(confirmedDirectory);
|
|
310
|
+
|
|
311
|
+
await prompts.log.message(`Found existing modules: ${[...installedModuleIds].join(', ')}`);
|
|
312
|
+
|
|
313
|
+
// Unified module selection - all modules in one grouped multiselect
|
|
314
|
+
let selectedModules;
|
|
315
|
+
if (options.modules) {
|
|
316
|
+
// Use modules from command-line
|
|
317
|
+
selectedModules = options.modules
|
|
318
|
+
.split(',')
|
|
319
|
+
.map((m) => m.trim())
|
|
320
|
+
.filter(Boolean);
|
|
321
|
+
await prompts.log.info(`Using modules from command-line: ${selectedModules.join(', ')}`);
|
|
322
|
+
} else if (options.yes) {
|
|
323
|
+
selectedModules = await this.getDefaultModules(installedModuleIds);
|
|
324
|
+
await prompts.log.info(
|
|
325
|
+
`Non-interactive mode (--yes): using default modules (installed + defaults): ${selectedModules.join(', ')}`,
|
|
326
|
+
);
|
|
327
|
+
} else {
|
|
328
|
+
selectedModules = await this.selectAllModules(installedModuleIds);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// After module selection, ask about custom modules
|
|
332
|
+
let customModuleResult = { selectedCustomModules: [], customContentConfig: { hasCustomContent: false } };
|
|
333
|
+
|
|
334
|
+
if (options.customContent) {
|
|
335
|
+
// Use custom content from command-line
|
|
336
|
+
const paths = options.customContent
|
|
337
|
+
.split(',')
|
|
338
|
+
.map((p) => p.trim())
|
|
339
|
+
.filter(Boolean);
|
|
340
|
+
await prompts.log.info(`Using custom content from command-line: ${paths.join(', ')}`);
|
|
341
|
+
|
|
342
|
+
// Build custom content config similar to promptCustomContentSource
|
|
343
|
+
const customPaths = [];
|
|
344
|
+
const selectedModuleIds = [];
|
|
345
|
+
const sources = [];
|
|
346
|
+
|
|
347
|
+
for (const customPath of paths) {
|
|
348
|
+
const expandedPath = this.expandUserPath(customPath);
|
|
349
|
+
const validation = this.validateCustomContentPathSync(expandedPath);
|
|
350
|
+
if (validation) {
|
|
351
|
+
await prompts.log.warn(`Skipping invalid custom content path: ${customPath} - ${validation}`);
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Read module metadata
|
|
356
|
+
let moduleMeta;
|
|
357
|
+
try {
|
|
358
|
+
const moduleYamlPath = path.join(expandedPath, 'module.yaml');
|
|
359
|
+
const moduleYaml = await fs.readFile(moduleYamlPath, 'utf-8');
|
|
360
|
+
const yaml = require('yaml');
|
|
361
|
+
moduleMeta = yaml.parse(moduleYaml);
|
|
362
|
+
} catch (error) {
|
|
363
|
+
await prompts.log.warn(`Skipping custom content path: ${customPath} - failed to read module.yaml: ${error.message}`);
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (!moduleMeta) {
|
|
368
|
+
await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml is empty`);
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (!moduleMeta.code) {
|
|
373
|
+
await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`);
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
customPaths.push(expandedPath);
|
|
378
|
+
selectedModuleIds.push(moduleMeta.code);
|
|
379
|
+
sources.push({
|
|
380
|
+
path: expandedPath,
|
|
381
|
+
id: moduleMeta.code,
|
|
382
|
+
name: moduleMeta.name || moduleMeta.code,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (customPaths.length > 0) {
|
|
387
|
+
customModuleResult = {
|
|
388
|
+
selectedCustomModules: selectedModuleIds,
|
|
389
|
+
customContentConfig: {
|
|
390
|
+
hasCustomContent: true,
|
|
391
|
+
selected: true,
|
|
392
|
+
sources,
|
|
393
|
+
selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')),
|
|
394
|
+
selectedModuleIds: selectedModuleIds,
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
} else if (options.yes) {
|
|
399
|
+
// Non-interactive mode: preserve existing custom modules (matches default: false)
|
|
400
|
+
const cacheDir = path.join(bmadDir, '_config', 'custom');
|
|
401
|
+
if (await fs.pathExists(cacheDir)) {
|
|
402
|
+
const entries = await fs.readdir(cacheDir, { withFileTypes: true });
|
|
403
|
+
for (const entry of entries) {
|
|
404
|
+
if (entry.isDirectory()) {
|
|
405
|
+
customModuleResult.selectedCustomModules.push(entry.name);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
await prompts.log.info(
|
|
409
|
+
`Non-interactive mode (--yes): preserving ${customModuleResult.selectedCustomModules.length} existing custom module(s)`,
|
|
410
|
+
);
|
|
411
|
+
} else {
|
|
412
|
+
await prompts.log.info('Non-interactive mode (--yes): no existing custom modules found');
|
|
413
|
+
}
|
|
414
|
+
} else {
|
|
415
|
+
const changeCustomModules = await prompts.confirm({
|
|
416
|
+
message: 'Modify custom modules, agents, or workflows?',
|
|
417
|
+
default: false,
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
if (changeCustomModules) {
|
|
421
|
+
customModuleResult = await this.handleCustomModulesInModifyFlow(confirmedDirectory, selectedModules);
|
|
422
|
+
} else {
|
|
423
|
+
// Preserve existing custom modules if user doesn't want to modify them
|
|
424
|
+
const { Installer } = require('../installers/lib/core/installer');
|
|
425
|
+
const installer = new Installer();
|
|
426
|
+
const { bmadDir } = await installer.findBmadDir(confirmedDirectory);
|
|
427
|
+
|
|
428
|
+
const cacheDir = path.join(bmadDir, '_config', 'custom');
|
|
429
|
+
if (await fs.pathExists(cacheDir)) {
|
|
430
|
+
const entries = await fs.readdir(cacheDir, { withFileTypes: true });
|
|
431
|
+
for (const entry of entries) {
|
|
432
|
+
if (entry.isDirectory()) {
|
|
433
|
+
customModuleResult.selectedCustomModules.push(entry.name);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Merge any selected custom modules
|
|
441
|
+
if (customModuleResult.selectedCustomModules.length > 0) {
|
|
442
|
+
selectedModules.push(...customModuleResult.selectedCustomModules);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Filter out core - it's always installed via installCore flag
|
|
446
|
+
selectedModules = selectedModules.filter((m) => m !== 'core');
|
|
447
|
+
|
|
448
|
+
// Get tool selection
|
|
449
|
+
const toolSelection = await this.promptToolSelection(confirmedDirectory, options);
|
|
450
|
+
|
|
451
|
+
const coreConfig = await this.collectCoreConfig(confirmedDirectory, options);
|
|
452
|
+
|
|
84
453
|
return {
|
|
85
|
-
actionType: '
|
|
454
|
+
actionType: 'update',
|
|
86
455
|
directory: confirmedDirectory,
|
|
456
|
+
installCore: true,
|
|
457
|
+
modules: selectedModules,
|
|
458
|
+
ides: toolSelection.ides,
|
|
459
|
+
skipIde: toolSelection.skipIde,
|
|
460
|
+
coreConfig: coreConfig,
|
|
461
|
+
customContent: customModuleResult.customContentConfig,
|
|
462
|
+
skipPrompts: options.yes || false,
|
|
87
463
|
};
|
|
88
464
|
}
|
|
465
|
+
}
|
|
89
466
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// For now, just note that we're in reinstall mode and continue below
|
|
467
|
+
// This section is only for new installations (update returns early above)
|
|
468
|
+
const { installedModuleIds } = await this.getExistingInstallation(confirmedDirectory);
|
|
93
469
|
|
|
94
|
-
|
|
470
|
+
// Unified module selection - all modules in one grouped multiselect
|
|
471
|
+
let selectedModules;
|
|
472
|
+
if (options.modules) {
|
|
473
|
+
// Use modules from command-line
|
|
474
|
+
selectedModules = options.modules
|
|
475
|
+
.split(',')
|
|
476
|
+
.map((m) => m.trim())
|
|
477
|
+
.filter(Boolean);
|
|
478
|
+
await prompts.log.info(`Using modules from command-line: ${selectedModules.join(', ')}`);
|
|
479
|
+
} else if (options.yes) {
|
|
480
|
+
// Use default modules when --yes flag is set
|
|
481
|
+
selectedModules = await this.getDefaultModules(installedModuleIds);
|
|
482
|
+
await prompts.log.info(`Using default modules (--yes flag): ${selectedModules.join(', ')}`);
|
|
483
|
+
} else {
|
|
484
|
+
selectedModules = await this.selectAllModules(installedModuleIds);
|
|
95
485
|
}
|
|
96
486
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
487
|
+
// Ask about custom content (local modules/agents/workflows)
|
|
488
|
+
if (options.customContent) {
|
|
489
|
+
// Use custom content from command-line
|
|
490
|
+
const paths = options.customContent
|
|
491
|
+
.split(',')
|
|
492
|
+
.map((p) => p.trim())
|
|
493
|
+
.filter(Boolean);
|
|
494
|
+
await prompts.log.info(`Using custom content from command-line: ${paths.join(', ')}`);
|
|
495
|
+
|
|
496
|
+
// Build custom content config similar to promptCustomContentSource
|
|
497
|
+
const customPaths = [];
|
|
498
|
+
const selectedModuleIds = [];
|
|
499
|
+
const sources = [];
|
|
500
|
+
|
|
501
|
+
for (const customPath of paths) {
|
|
502
|
+
const expandedPath = this.expandUserPath(customPath);
|
|
503
|
+
const validation = this.validateCustomContentPathSync(expandedPath);
|
|
504
|
+
if (validation) {
|
|
505
|
+
await prompts.log.warn(`Skipping invalid custom content path: ${customPath} - ${validation}`);
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
101
508
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
509
|
+
// Read module metadata
|
|
510
|
+
let moduleMeta;
|
|
511
|
+
try {
|
|
512
|
+
const moduleYamlPath = path.join(expandedPath, 'module.yaml');
|
|
513
|
+
const moduleYaml = await fs.readFile(moduleYamlPath, 'utf-8');
|
|
514
|
+
const yaml = require('yaml');
|
|
515
|
+
moduleMeta = yaml.parse(moduleYaml);
|
|
516
|
+
} catch (error) {
|
|
517
|
+
await prompts.log.warn(`Skipping custom content path: ${customPath} - failed to read module.yaml: ${error.message}`);
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
105
520
|
|
|
106
|
-
|
|
521
|
+
if (!moduleMeta) {
|
|
522
|
+
await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml is empty`);
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if (!moduleMeta.code) {
|
|
527
|
+
await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`);
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
customPaths.push(expandedPath);
|
|
532
|
+
selectedModuleIds.push(moduleMeta.code);
|
|
533
|
+
sources.push({
|
|
534
|
+
path: expandedPath,
|
|
535
|
+
id: moduleMeta.code,
|
|
536
|
+
name: moduleMeta.name || moduleMeta.code,
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (customPaths.length > 0) {
|
|
541
|
+
customContentConfig = {
|
|
542
|
+
hasCustomContent: true,
|
|
543
|
+
selected: true,
|
|
544
|
+
sources,
|
|
545
|
+
selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')),
|
|
546
|
+
selectedModuleIds: selectedModuleIds,
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
} else if (!options.yes) {
|
|
550
|
+
const wantsCustomContent = await prompts.confirm({
|
|
551
|
+
message: 'Add custom modules, agents, or workflows from your computer?',
|
|
552
|
+
default: false,
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
if (wantsCustomContent) {
|
|
556
|
+
customContentConfig = await this.promptCustomContentSource();
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Add custom content modules if any were selected
|
|
561
|
+
if (customContentConfig && customContentConfig.selectedModuleIds) {
|
|
562
|
+
selectedModules.push(...customContentConfig.selectedModuleIds);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
selectedModules = selectedModules.filter((m) => m !== 'core');
|
|
566
|
+
let toolSelection = await this.promptToolSelection(confirmedDirectory, options);
|
|
567
|
+
const coreConfig = await this.collectCoreConfig(confirmedDirectory, options);
|
|
107
568
|
|
|
108
569
|
return {
|
|
109
|
-
actionType:
|
|
570
|
+
actionType: 'install',
|
|
110
571
|
directory: confirmedDirectory,
|
|
111
|
-
installCore: true,
|
|
572
|
+
installCore: true,
|
|
112
573
|
modules: selectedModules,
|
|
113
|
-
// IDE selection collected after config, will be configured later
|
|
114
574
|
ides: toolSelection.ides,
|
|
115
575
|
skipIde: toolSelection.skipIde,
|
|
116
|
-
coreConfig: coreConfig,
|
|
576
|
+
coreConfig: coreConfig,
|
|
577
|
+
customContent: customContentConfig,
|
|
578
|
+
skipPrompts: options.yes || false,
|
|
117
579
|
};
|
|
118
580
|
}
|
|
119
581
|
|
|
120
582
|
/**
|
|
121
583
|
* Prompt for tool/IDE selection (called after module configuration)
|
|
584
|
+
* Uses a split prompt approach:
|
|
585
|
+
* 1. Recommended tools - standard multiselect for 3 preferred tools
|
|
586
|
+
* 2. Additional tools - autocompleteMultiselect with search capability
|
|
122
587
|
* @param {string} projectDir - Project directory to check for existing IDEs
|
|
123
|
-
* @param {
|
|
588
|
+
* @param {Object} options - Command-line options
|
|
124
589
|
* @returns {Object} Tool configuration
|
|
125
590
|
*/
|
|
126
|
-
async promptToolSelection(projectDir,
|
|
591
|
+
async promptToolSelection(projectDir, options = {}) {
|
|
127
592
|
// Check for existing configured IDEs - use findBmadDir to detect custom folder names
|
|
128
593
|
const { Detector } = require('../installers/lib/core/detector');
|
|
129
594
|
const { Installer } = require('../installers/lib/core/installer');
|
|
130
595
|
const detector = new Detector();
|
|
131
596
|
const installer = new Installer();
|
|
132
|
-
const
|
|
597
|
+
const bmadResult = await installer.findBmadDir(projectDir || process.cwd());
|
|
598
|
+
const bmadDir = bmadResult.bmadDir;
|
|
133
599
|
const existingInstall = await detector.detect(bmadDir);
|
|
134
600
|
const configuredIdes = existingInstall.ides || [];
|
|
135
601
|
|
|
136
602
|
// Get IDE manager to fetch available IDEs dynamically
|
|
137
603
|
const { IdeManager } = require('../installers/lib/ide/manager');
|
|
138
604
|
const ideManager = new IdeManager();
|
|
605
|
+
await ideManager.ensureInitialized(); // IMPORTANT: Must initialize before getting IDEs
|
|
139
606
|
|
|
140
607
|
const preferredIdes = ideManager.getPreferredIdes();
|
|
141
608
|
const otherIdes = ideManager.getOtherIdes();
|
|
142
609
|
|
|
143
|
-
//
|
|
144
|
-
const
|
|
145
|
-
const
|
|
610
|
+
// Determine which configured IDEs are in "preferred" vs "other" categories
|
|
611
|
+
const configuredPreferred = configuredIdes.filter((id) => preferredIdes.some((ide) => ide.value === id));
|
|
612
|
+
const configuredOther = configuredIdes.filter((id) => otherIdes.some((ide) => ide.value === id));
|
|
613
|
+
|
|
614
|
+
// Warn about previously configured tools that are no longer available
|
|
615
|
+
const allKnownValues = new Set([...preferredIdes, ...otherIdes].map((ide) => ide.value));
|
|
616
|
+
const unknownTools = configuredIdes.filter((id) => id && typeof id === 'string' && !allKnownValues.has(id));
|
|
617
|
+
if (unknownTools.length > 0) {
|
|
618
|
+
await prompts.log.warn(`Previously configured tools are no longer available: ${unknownTools.join(', ')}`);
|
|
619
|
+
}
|
|
146
620
|
|
|
147
|
-
//
|
|
621
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
622
|
+
// UPGRADE PATH: If tools already configured, show all tools with configured at top
|
|
623
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
148
624
|
if (configuredIdes.length > 0) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
625
|
+
const allTools = [...preferredIdes, ...otherIdes];
|
|
626
|
+
|
|
627
|
+
// Non-interactive: handle --tools and --yes flags before interactive prompt
|
|
628
|
+
if (options.tools) {
|
|
629
|
+
if (options.tools.toLowerCase() === 'none') {
|
|
630
|
+
await prompts.log.info('Skipping tool configuration (--tools none)');
|
|
631
|
+
return { ides: [], skipIde: true };
|
|
154
632
|
}
|
|
633
|
+
const selectedIdes = options.tools
|
|
634
|
+
.split(',')
|
|
635
|
+
.map((t) => t.trim())
|
|
636
|
+
.filter(Boolean);
|
|
637
|
+
await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`);
|
|
638
|
+
await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
|
|
639
|
+
return { ides: selectedIdes, skipIde: false };
|
|
640
|
+
}
|
|
155
641
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
642
|
+
if (options.yes) {
|
|
643
|
+
await prompts.log.info(`Non-interactive mode (--yes): keeping configured tools: ${configuredIdes.join(', ')}`);
|
|
644
|
+
await this.displaySelectedTools(configuredIdes, preferredIdes, allTools);
|
|
645
|
+
return { ides: configuredIdes, skipIde: false };
|
|
646
|
+
}
|
|
160
647
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
648
|
+
// Sort: configured tools first, then preferred, then others
|
|
649
|
+
const sortedTools = [
|
|
650
|
+
...allTools.filter((ide) => configuredIdes.includes(ide.value)),
|
|
651
|
+
...allTools.filter((ide) => !configuredIdes.includes(ide.value)),
|
|
652
|
+
];
|
|
653
|
+
|
|
654
|
+
const upgradeOptions = sortedTools.map((ide) => {
|
|
655
|
+
const isConfigured = configuredIdes.includes(ide.value);
|
|
656
|
+
const isPreferred = preferredIdes.some((p) => p.value === ide.value);
|
|
657
|
+
let label = ide.name;
|
|
658
|
+
if (isPreferred) label += ' ⭐';
|
|
659
|
+
if (isConfigured) label += ' ✅';
|
|
660
|
+
return { label, value: ide.value };
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
// Sort initialValues to match display order
|
|
664
|
+
const sortedInitialValues = sortedTools.filter((ide) => configuredIdes.includes(ide.value)).map((ide) => ide.value);
|
|
665
|
+
|
|
666
|
+
const upgradeSelected = await prompts.autocompleteMultiselect({
|
|
667
|
+
message: 'Integrate with',
|
|
668
|
+
options: upgradeOptions,
|
|
669
|
+
initialValues: sortedInitialValues,
|
|
670
|
+
required: false,
|
|
671
|
+
maxItems: 8,
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
const selectedIdes = upgradeSelected || [];
|
|
675
|
+
|
|
676
|
+
if (selectedIdes.length === 0) {
|
|
677
|
+
const confirmNoTools = await prompts.confirm({
|
|
678
|
+
message: 'No tools selected. Continue without installing any tools?',
|
|
679
|
+
default: false,
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
if (!confirmNoTools) {
|
|
683
|
+
return this.promptToolSelection(projectDir, options);
|
|
171
684
|
}
|
|
685
|
+
|
|
686
|
+
return { ides: [], skipIde: true };
|
|
172
687
|
}
|
|
688
|
+
|
|
689
|
+
// Display selected tools
|
|
690
|
+
await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
|
|
691
|
+
|
|
692
|
+
return { ides: selectedIdes, skipIde: false };
|
|
173
693
|
}
|
|
174
694
|
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
695
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
696
|
+
// NEW INSTALL: Show all tools with search
|
|
697
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
698
|
+
const allTools = [...preferredIdes, ...otherIdes];
|
|
699
|
+
|
|
700
|
+
const allToolOptions = allTools.map((ide) => {
|
|
701
|
+
const isPreferred = preferredIdes.some((p) => p.value === ide.value);
|
|
702
|
+
let label = ide.name;
|
|
703
|
+
if (isPreferred) label += ' ⭐';
|
|
704
|
+
return {
|
|
705
|
+
label,
|
|
706
|
+
value: ide.value,
|
|
707
|
+
};
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
let selectedIdes = [];
|
|
711
|
+
|
|
712
|
+
// Check if tools are provided via command-line
|
|
713
|
+
if (options.tools) {
|
|
714
|
+
// Check for explicit "none" value to skip tool installation
|
|
715
|
+
if (options.tools.toLowerCase() === 'none') {
|
|
716
|
+
await prompts.log.info('Skipping tool configuration (--tools none)');
|
|
717
|
+
return { ides: [], skipIde: true };
|
|
718
|
+
} else {
|
|
719
|
+
selectedIdes = options.tools
|
|
720
|
+
.split(',')
|
|
721
|
+
.map((t) => t.trim())
|
|
722
|
+
.filter(Boolean);
|
|
723
|
+
await prompts.log.info(`Using tools from command-line: ${selectedIdes.join(', ')}`);
|
|
724
|
+
await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
|
|
725
|
+
return { ides: selectedIdes, skipIde: false };
|
|
726
|
+
}
|
|
727
|
+
} else if (options.yes) {
|
|
728
|
+
// If --yes flag is set, skip tool prompt and use previously configured tools or empty
|
|
729
|
+
if (configuredIdes.length > 0) {
|
|
730
|
+
await prompts.log.info(`Using previously configured tools (--yes flag): ${configuredIdes.join(', ')}`);
|
|
731
|
+
await this.displaySelectedTools(configuredIdes, preferredIdes, allTools);
|
|
732
|
+
return { ides: configuredIdes, skipIde: false };
|
|
733
|
+
} else {
|
|
734
|
+
await prompts.log.info('Skipping tool configuration (--yes flag, no previous tools)');
|
|
735
|
+
return { ides: [], skipIde: true };
|
|
186
736
|
}
|
|
187
737
|
}
|
|
188
738
|
|
|
189
|
-
//
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
739
|
+
// Interactive mode
|
|
740
|
+
const interactiveSelectedIdes = await prompts.autocompleteMultiselect({
|
|
741
|
+
message: 'Integrate with:',
|
|
742
|
+
options: allToolOptions,
|
|
743
|
+
initialValues: configuredIdes.length > 0 ? configuredIdes : undefined,
|
|
744
|
+
required: false,
|
|
745
|
+
maxItems: 8,
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
selectedIdes = interactiveSelectedIdes || [];
|
|
749
|
+
|
|
750
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
751
|
+
// STEP 3: Confirm if no tools selected
|
|
752
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
753
|
+
if (selectedIdes.length === 0) {
|
|
754
|
+
const confirmNoTools = await prompts.confirm({
|
|
755
|
+
message: 'No tools selected. Continue without installing any tools?',
|
|
756
|
+
default: false,
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
if (!confirmNoTools) {
|
|
760
|
+
// User wants to select tools - recurse
|
|
761
|
+
return this.promptToolSelection(projectDir, options);
|
|
199
762
|
}
|
|
200
|
-
}
|
|
201
763
|
|
|
202
|
-
|
|
764
|
+
return {
|
|
765
|
+
ides: [],
|
|
766
|
+
skipIde: true,
|
|
767
|
+
};
|
|
768
|
+
}
|
|
203
769
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
type: 'checkbox',
|
|
207
|
-
name: 'ides',
|
|
208
|
-
message: 'Select tools to configure:',
|
|
209
|
-
choices: ideChoices,
|
|
210
|
-
pageSize: 15,
|
|
211
|
-
},
|
|
212
|
-
]);
|
|
770
|
+
// Display selected tools
|
|
771
|
+
await this.displaySelectedTools(selectedIdes, preferredIdes, allTools);
|
|
213
772
|
|
|
214
773
|
return {
|
|
215
|
-
ides:
|
|
216
|
-
skipIde:
|
|
774
|
+
ides: selectedIdes,
|
|
775
|
+
skipIde: selectedIdes.length === 0,
|
|
217
776
|
};
|
|
218
777
|
}
|
|
219
778
|
|
|
@@ -222,52 +781,17 @@ class UI {
|
|
|
222
781
|
* @returns {Object} Update configuration
|
|
223
782
|
*/
|
|
224
783
|
async promptUpdate() {
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
message: 'Create backup before updating?',
|
|
230
|
-
default: true,
|
|
231
|
-
},
|
|
232
|
-
{
|
|
233
|
-
type: 'confirm',
|
|
234
|
-
name: 'preserveCustomizations',
|
|
235
|
-
message: 'Preserve local customizations?',
|
|
236
|
-
default: true,
|
|
237
|
-
},
|
|
238
|
-
]);
|
|
239
|
-
|
|
240
|
-
return answers;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Prompt for module selection
|
|
245
|
-
* @param {Array} modules - Available modules
|
|
246
|
-
* @returns {Array} Selected modules
|
|
247
|
-
*/
|
|
248
|
-
async promptModules(modules) {
|
|
249
|
-
const choices = modules.map((mod) => ({
|
|
250
|
-
name: `${mod.name} - ${mod.description}`,
|
|
251
|
-
value: mod.id,
|
|
252
|
-
checked: false,
|
|
253
|
-
}));
|
|
784
|
+
const backupFirst = await prompts.confirm({
|
|
785
|
+
message: 'Create backup before updating?',
|
|
786
|
+
default: true,
|
|
787
|
+
});
|
|
254
788
|
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
message: 'Select modules to add:',
|
|
260
|
-
choices,
|
|
261
|
-
validate: (answer) => {
|
|
262
|
-
if (answer.length === 0) {
|
|
263
|
-
return 'You must choose at least one module.';
|
|
264
|
-
}
|
|
265
|
-
return true;
|
|
266
|
-
},
|
|
267
|
-
},
|
|
268
|
-
]);
|
|
789
|
+
const preserveCustomizations = await prompts.confirm({
|
|
790
|
+
message: 'Preserve local customizations?',
|
|
791
|
+
default: true,
|
|
792
|
+
});
|
|
269
793
|
|
|
270
|
-
return
|
|
794
|
+
return { backupFirst, preserveCustomizations };
|
|
271
795
|
}
|
|
272
796
|
|
|
273
797
|
/**
|
|
@@ -277,37 +801,10 @@ class UI {
|
|
|
277
801
|
* @returns {boolean} User confirmation
|
|
278
802
|
*/
|
|
279
803
|
async confirm(message, defaultValue = false) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
name: 'confirmed',
|
|
284
|
-
message,
|
|
285
|
-
default: defaultValue,
|
|
286
|
-
},
|
|
287
|
-
]);
|
|
288
|
-
|
|
289
|
-
return confirmed;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Display installation summary
|
|
294
|
-
* @param {Object} result - Installation result
|
|
295
|
-
*/
|
|
296
|
-
showInstallSummary(result) {
|
|
297
|
-
CLIUtils.displaySection('Installation Complete', 'BMAD™ has been successfully installed');
|
|
298
|
-
|
|
299
|
-
const summary = [
|
|
300
|
-
`📁 Installation Path: ${result.path}`,
|
|
301
|
-
`📦 Modules Installed: ${result.modules?.length > 0 ? result.modules.join(', ') : 'core only'}`,
|
|
302
|
-
`🔧 Tools Configured: ${result.ides?.length > 0 ? result.ides.join(', ') : 'none'}`,
|
|
303
|
-
];
|
|
304
|
-
|
|
305
|
-
CLIUtils.displayBox(summary.join('\n\n'), {
|
|
306
|
-
borderColor: 'green',
|
|
307
|
-
borderStyle: 'round',
|
|
804
|
+
return await prompts.confirm({
|
|
805
|
+
message,
|
|
806
|
+
default: defaultValue,
|
|
308
807
|
});
|
|
309
|
-
|
|
310
|
-
console.log('\n' + chalk.green.bold('✨ BMAD is ready to use!'));
|
|
311
808
|
}
|
|
312
809
|
|
|
313
810
|
/**
|
|
@@ -330,95 +827,330 @@ class UI {
|
|
|
330
827
|
/**
|
|
331
828
|
* Get existing installation info and installed modules
|
|
332
829
|
* @param {string} directory - Installation directory
|
|
333
|
-
* @returns {Object} Object with existingInstall and
|
|
830
|
+
* @returns {Object} Object with existingInstall, installedModuleIds, and bmadDir
|
|
334
831
|
*/
|
|
335
832
|
async getExistingInstallation(directory) {
|
|
336
833
|
const { Detector } = require('../installers/lib/core/detector');
|
|
337
834
|
const { Installer } = require('../installers/lib/core/installer');
|
|
338
835
|
const detector = new Detector();
|
|
339
836
|
const installer = new Installer();
|
|
340
|
-
const
|
|
837
|
+
const bmadDirResult = await installer.findBmadDir(directory);
|
|
838
|
+
const bmadDir = bmadDirResult.bmadDir;
|
|
341
839
|
const existingInstall = await detector.detect(bmadDir);
|
|
342
840
|
const installedModuleIds = new Set(existingInstall.modules.map((mod) => mod.id));
|
|
343
841
|
|
|
344
|
-
return { existingInstall, installedModuleIds };
|
|
842
|
+
return { existingInstall, installedModuleIds, bmadDir };
|
|
345
843
|
}
|
|
346
844
|
|
|
347
845
|
/**
|
|
348
846
|
* Collect core configuration
|
|
349
847
|
* @param {string} directory - Installation directory
|
|
848
|
+
* @param {Object} options - Command-line options
|
|
350
849
|
* @returns {Object} Core configuration
|
|
351
850
|
*/
|
|
352
|
-
async collectCoreConfig(directory) {
|
|
851
|
+
async collectCoreConfig(directory, options = {}) {
|
|
353
852
|
const { ConfigCollector } = require('../installers/lib/core/config-collector');
|
|
354
853
|
const configCollector = new ConfigCollector();
|
|
355
|
-
// Load existing configs first if they exist
|
|
356
|
-
await configCollector.loadExistingConfig(directory);
|
|
357
|
-
// Now collect with existing values as defaults (false = don't skip loading, true = skip completion message)
|
|
358
|
-
await configCollector.collectModuleConfig('core', directory, false, true);
|
|
359
854
|
|
|
360
|
-
|
|
855
|
+
// If options are provided, set them directly
|
|
856
|
+
if (options.userName || options.communicationLanguage || options.documentOutputLanguage || options.outputFolder) {
|
|
857
|
+
const coreConfig = {};
|
|
858
|
+
if (options.userName) {
|
|
859
|
+
coreConfig.user_name = options.userName;
|
|
860
|
+
await prompts.log.info(`Using user name from command-line: ${options.userName}`);
|
|
861
|
+
}
|
|
862
|
+
if (options.communicationLanguage) {
|
|
863
|
+
coreConfig.communication_language = options.communicationLanguage;
|
|
864
|
+
await prompts.log.info(`Using communication language from command-line: ${options.communicationLanguage}`);
|
|
865
|
+
}
|
|
866
|
+
if (options.documentOutputLanguage) {
|
|
867
|
+
coreConfig.document_output_language = options.documentOutputLanguage;
|
|
868
|
+
await prompts.log.info(`Using document output language from command-line: ${options.documentOutputLanguage}`);
|
|
869
|
+
}
|
|
870
|
+
if (options.outputFolder) {
|
|
871
|
+
coreConfig.output_folder = options.outputFolder;
|
|
872
|
+
await prompts.log.info(`Using output folder from command-line: ${options.outputFolder}`);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// Load existing config to merge with provided options
|
|
876
|
+
await configCollector.loadExistingConfig(directory);
|
|
877
|
+
|
|
878
|
+
// Merge provided options with existing config (or defaults)
|
|
879
|
+
const existingConfig = configCollector.collectedConfig.core || {};
|
|
880
|
+
configCollector.collectedConfig.core = { ...existingConfig, ...coreConfig };
|
|
881
|
+
|
|
882
|
+
// If not all options are provided, collect the missing ones interactively (unless --yes flag)
|
|
883
|
+
if (
|
|
884
|
+
!options.yes &&
|
|
885
|
+
(!options.userName || !options.communicationLanguage || !options.documentOutputLanguage || !options.outputFolder)
|
|
886
|
+
) {
|
|
887
|
+
await configCollector.collectModuleConfig('core', directory, false, true);
|
|
888
|
+
}
|
|
889
|
+
} else if (options.yes) {
|
|
890
|
+
// Use all defaults when --yes flag is set
|
|
891
|
+
await configCollector.loadExistingConfig(directory);
|
|
892
|
+
const existingConfig = configCollector.collectedConfig.core || {};
|
|
893
|
+
|
|
894
|
+
// If no existing config, use defaults
|
|
895
|
+
if (Object.keys(existingConfig).length === 0) {
|
|
896
|
+
let safeUsername;
|
|
897
|
+
try {
|
|
898
|
+
safeUsername = os.userInfo().username;
|
|
899
|
+
} catch {
|
|
900
|
+
safeUsername = process.env.USER || process.env.USERNAME || 'User';
|
|
901
|
+
}
|
|
902
|
+
const defaultUsername = safeUsername.charAt(0).toUpperCase() + safeUsername.slice(1);
|
|
903
|
+
configCollector.collectedConfig.core = {
|
|
904
|
+
user_name: defaultUsername,
|
|
905
|
+
communication_language: 'English',
|
|
906
|
+
document_output_language: 'English',
|
|
907
|
+
output_folder: '_bmad-output',
|
|
908
|
+
};
|
|
909
|
+
await prompts.log.info('Using default configuration (--yes flag)');
|
|
910
|
+
}
|
|
911
|
+
} else {
|
|
912
|
+
// Load existing configs first if they exist
|
|
913
|
+
await configCollector.loadExistingConfig(directory);
|
|
914
|
+
// Now collect with existing values as defaults (false = don't skip loading, true = skip completion message)
|
|
915
|
+
await configCollector.collectModuleConfig('core', directory, false, true);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
const coreConfig = configCollector.collectedConfig.core;
|
|
919
|
+
// Ensure we always have a core config object, even if empty
|
|
920
|
+
return coreConfig || {};
|
|
361
921
|
}
|
|
362
922
|
|
|
363
923
|
/**
|
|
364
924
|
* Get module choices for selection
|
|
365
925
|
* @param {Set} installedModuleIds - Currently installed module IDs
|
|
366
|
-
* @
|
|
926
|
+
* @param {Object} customContentConfig - Custom content configuration
|
|
927
|
+
* @returns {Array} Module choices for prompt
|
|
367
928
|
*/
|
|
368
|
-
async getModuleChoices(installedModuleIds) {
|
|
929
|
+
async getModuleChoices(installedModuleIds, customContentConfig = null) {
|
|
930
|
+
const color = await prompts.getColor();
|
|
931
|
+
const moduleChoices = [];
|
|
932
|
+
const isNewInstallation = installedModuleIds.size === 0;
|
|
933
|
+
|
|
934
|
+
const customContentItems = [];
|
|
935
|
+
|
|
936
|
+
// Add custom content items
|
|
937
|
+
if (customContentConfig && customContentConfig.hasCustomContent && customContentConfig.customPath) {
|
|
938
|
+
// Existing installation - show from directory
|
|
939
|
+
const customHandler = new CustomHandler();
|
|
940
|
+
const customFiles = await customHandler.findCustomContent(customContentConfig.customPath);
|
|
941
|
+
|
|
942
|
+
for (const customFile of customFiles) {
|
|
943
|
+
const customInfo = await customHandler.getCustomInfo(customFile);
|
|
944
|
+
if (customInfo) {
|
|
945
|
+
customContentItems.push({
|
|
946
|
+
name: `${color.cyan('\u2713')} ${customInfo.name} ${color.dim(`(${customInfo.relativePath})`)}`,
|
|
947
|
+
value: `__CUSTOM_CONTENT__${customFile}`, // Unique value for each custom content
|
|
948
|
+
checked: true, // Default to selected since user chose to provide custom content
|
|
949
|
+
path: customInfo.path, // Track path to avoid duplicates
|
|
950
|
+
hint: customInfo.description || undefined,
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// Add official modules
|
|
369
957
|
const { ModuleManager } = require('../installers/lib/modules/manager');
|
|
370
958
|
const moduleManager = new ModuleManager();
|
|
371
|
-
const availableModules = await moduleManager.listAvailable();
|
|
959
|
+
const { modules: availableModules, customModules: customModulesFromCache } = await moduleManager.listAvailable();
|
|
372
960
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
961
|
+
// First, add all items to appropriate sections
|
|
962
|
+
const allCustomModules = [];
|
|
963
|
+
|
|
964
|
+
// Add custom content items from directory
|
|
965
|
+
allCustomModules.push(...customContentItems);
|
|
966
|
+
|
|
967
|
+
// Add custom modules from cache
|
|
968
|
+
for (const mod of customModulesFromCache) {
|
|
969
|
+
// Skip if this module is already in customContentItems (by path)
|
|
970
|
+
const isDuplicate = allCustomModules.some((item) => item.path && mod.path && path.resolve(item.path) === path.resolve(mod.path));
|
|
971
|
+
|
|
972
|
+
if (!isDuplicate) {
|
|
973
|
+
allCustomModules.push({
|
|
974
|
+
name: `${color.cyan('\u2713')} ${mod.name} ${color.dim('(cached)')}`,
|
|
975
|
+
value: mod.id,
|
|
976
|
+
checked: isNewInstallation ? mod.defaultSelected || false : installedModuleIds.has(mod.id),
|
|
977
|
+
hint: mod.description || undefined,
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Add separators and modules in correct order
|
|
983
|
+
if (allCustomModules.length > 0) {
|
|
984
|
+
// Add separator for custom content, all custom modules, and official content separator
|
|
985
|
+
moduleChoices.push(
|
|
986
|
+
new choiceUtils.Separator('── Custom Content ──'),
|
|
987
|
+
...allCustomModules,
|
|
988
|
+
new choiceUtils.Separator('── Official Content ──'),
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
// Add official modules (only non-custom ones)
|
|
993
|
+
for (const mod of availableModules) {
|
|
994
|
+
if (!mod.isCustom) {
|
|
995
|
+
moduleChoices.push({
|
|
996
|
+
name: mod.name,
|
|
997
|
+
value: mod.id,
|
|
998
|
+
checked: isNewInstallation ? mod.defaultSelected || false : installedModuleIds.has(mod.id),
|
|
999
|
+
hint: mod.description || undefined,
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
return moduleChoices;
|
|
379
1005
|
}
|
|
380
1006
|
|
|
381
1007
|
/**
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
* @
|
|
1008
|
+
* Select all modules (official + community) using grouped multiselect.
|
|
1009
|
+
* Core is shown as locked but filtered from the result since it's always installed separately.
|
|
1010
|
+
* @param {Set} installedModuleIds - Currently installed module IDs
|
|
1011
|
+
* @returns {Array} Selected module codes (excluding core)
|
|
385
1012
|
*/
|
|
386
|
-
async
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
]
|
|
397
|
-
|
|
398
|
-
|
|
1013
|
+
async selectAllModules(installedModuleIds = new Set()) {
|
|
1014
|
+
const { ModuleManager } = require('../installers/lib/modules/manager');
|
|
1015
|
+
const moduleManager = new ModuleManager();
|
|
1016
|
+
const { modules: localModules } = await moduleManager.listAvailable();
|
|
1017
|
+
|
|
1018
|
+
// Get external modules
|
|
1019
|
+
const externalManager = new ExternalModuleManager();
|
|
1020
|
+
const externalModules = await externalManager.listAvailable();
|
|
1021
|
+
|
|
1022
|
+
// Build flat options list with group hints for autocompleteMultiselect
|
|
1023
|
+
const allOptions = [];
|
|
1024
|
+
const initialValues = [];
|
|
1025
|
+
const lockedValues = ['core'];
|
|
1026
|
+
|
|
1027
|
+
// Core module is always installed — show it locked at the top
|
|
1028
|
+
allOptions.push({ label: 'BMad Core Module', value: 'core', hint: 'Core configuration and shared resources' });
|
|
1029
|
+
initialValues.push('core');
|
|
1030
|
+
|
|
1031
|
+
// Helper to build module entry with proper sorting and selection
|
|
1032
|
+
const buildModuleEntry = (mod, value, group) => {
|
|
1033
|
+
const isInstalled = installedModuleIds.has(value);
|
|
1034
|
+
return {
|
|
1035
|
+
label: mod.name,
|
|
1036
|
+
value,
|
|
1037
|
+
hint: mod.description || group,
|
|
1038
|
+
// Pre-select only if already installed (not on fresh install)
|
|
1039
|
+
selected: isInstalled,
|
|
1040
|
+
};
|
|
1041
|
+
};
|
|
1042
|
+
|
|
1043
|
+
// Local modules (BMM, BMB, etc.)
|
|
1044
|
+
const localEntries = [];
|
|
1045
|
+
for (const mod of localModules) {
|
|
1046
|
+
if (!mod.isCustom && mod.id !== 'core') {
|
|
1047
|
+
const entry = buildModuleEntry(mod, mod.id, 'Local');
|
|
1048
|
+
localEntries.push(entry);
|
|
1049
|
+
if (entry.selected) {
|
|
1050
|
+
initialValues.push(mod.id);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
allOptions.push(...localEntries.map(({ label, value, hint }) => ({ label, value, hint })));
|
|
1055
|
+
|
|
1056
|
+
// Group 2: BMad Official Modules (type: bmad-org)
|
|
1057
|
+
const officialModules = [];
|
|
1058
|
+
for (const mod of externalModules) {
|
|
1059
|
+
if (mod.type === 'bmad-org') {
|
|
1060
|
+
const entry = buildModuleEntry(mod, mod.code, 'Official');
|
|
1061
|
+
officialModules.push(entry);
|
|
1062
|
+
if (entry.selected) {
|
|
1063
|
+
initialValues.push(mod.code);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
allOptions.push(...officialModules.map(({ label, value, hint }) => ({ label, value, hint })));
|
|
1068
|
+
|
|
1069
|
+
// Group 3: Community Modules (type: community)
|
|
1070
|
+
const communityModules = [];
|
|
1071
|
+
for (const mod of externalModules) {
|
|
1072
|
+
if (mod.type === 'community') {
|
|
1073
|
+
const entry = buildModuleEntry(mod, mod.code, 'Community');
|
|
1074
|
+
communityModules.push(entry);
|
|
1075
|
+
if (entry.selected) {
|
|
1076
|
+
initialValues.push(mod.code);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
allOptions.push(...communityModules.map(({ label, value, hint }) => ({ label, value, hint })));
|
|
1081
|
+
|
|
1082
|
+
const selected = await prompts.autocompleteMultiselect({
|
|
1083
|
+
message: 'Select modules to install:',
|
|
1084
|
+
options: allOptions,
|
|
1085
|
+
initialValues: initialValues.length > 0 ? initialValues : undefined,
|
|
1086
|
+
lockedValues,
|
|
1087
|
+
required: true,
|
|
1088
|
+
maxItems: allOptions.length,
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
const result = selected ? selected.filter((m) => m !== 'core') : [];
|
|
1092
|
+
|
|
1093
|
+
// Display selected modules as bulleted list
|
|
1094
|
+
if (result.length > 0) {
|
|
1095
|
+
const moduleLines = result.map((moduleId) => {
|
|
1096
|
+
const opt = allOptions.find((o) => o.value === moduleId);
|
|
1097
|
+
return ` \u2022 ${opt?.label || moduleId}`;
|
|
1098
|
+
});
|
|
1099
|
+
await prompts.log.message('Selected modules:\n' + moduleLines.join('\n'));
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
return result;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/**
|
|
1106
|
+
* Get default modules for non-interactive mode
|
|
1107
|
+
* @param {Set} installedModuleIds - Already installed module IDs
|
|
1108
|
+
* @returns {Array} Default module codes
|
|
1109
|
+
*/
|
|
1110
|
+
async getDefaultModules(installedModuleIds = new Set()) {
|
|
1111
|
+
const { ModuleManager } = require('../installers/lib/modules/manager');
|
|
1112
|
+
const moduleManager = new ModuleManager();
|
|
1113
|
+
const { modules: localModules } = await moduleManager.listAvailable();
|
|
1114
|
+
|
|
1115
|
+
const defaultModules = [];
|
|
1116
|
+
|
|
1117
|
+
// Add default-selected local modules (typically BMM)
|
|
1118
|
+
for (const mod of localModules) {
|
|
1119
|
+
if (mod.defaultSelected === true || installedModuleIds.has(mod.id)) {
|
|
1120
|
+
defaultModules.push(mod.id);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// If no defaults found, use 'bmm' as the fallback default
|
|
1125
|
+
if (defaultModules.length === 0) {
|
|
1126
|
+
defaultModules.push('bmm');
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
return defaultModules;
|
|
399
1130
|
}
|
|
400
1131
|
|
|
401
1132
|
/**
|
|
402
1133
|
* Prompt for directory selection
|
|
403
|
-
* @returns {Object} Directory answer from
|
|
1134
|
+
* @returns {Object} Directory answer from prompt
|
|
404
1135
|
*/
|
|
405
1136
|
async promptForDirectory() {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
1137
|
+
// Use sync validation because @clack/prompts doesn't support async validate
|
|
1138
|
+
const directory = await prompts.text({
|
|
1139
|
+
message: 'Installation directory:',
|
|
1140
|
+
default: process.cwd(),
|
|
1141
|
+
placeholder: process.cwd(),
|
|
1142
|
+
validate: (input) => this.validateDirectorySync(input),
|
|
1143
|
+
});
|
|
1144
|
+
|
|
1145
|
+
// Apply filter logic
|
|
1146
|
+
let filteredDir = directory;
|
|
1147
|
+
if (!filteredDir || filteredDir.trim() === '') {
|
|
1148
|
+
filteredDir = process.cwd();
|
|
1149
|
+
} else {
|
|
1150
|
+
filteredDir = this.expandUserPath(filteredDir);
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
return { directory: filteredDir };
|
|
422
1154
|
}
|
|
423
1155
|
|
|
424
1156
|
/**
|
|
@@ -426,7 +1158,7 @@ class UI {
|
|
|
426
1158
|
* @param {string} directory - The directory path
|
|
427
1159
|
*/
|
|
428
1160
|
async displayDirectoryInfo(directory) {
|
|
429
|
-
|
|
1161
|
+
await prompts.log.info(`Resolved installation path: ${directory}`);
|
|
430
1162
|
|
|
431
1163
|
const dirExists = await fs.pathExists(directory);
|
|
432
1164
|
if (dirExists) {
|
|
@@ -435,18 +1167,17 @@ class UI {
|
|
|
435
1167
|
if (stats.isDirectory()) {
|
|
436
1168
|
const files = await fs.readdir(directory);
|
|
437
1169
|
if (files.length > 0) {
|
|
438
|
-
// Check for any bmad installation (any folder with
|
|
1170
|
+
// Check for any bmad installation (any folder with _config/manifest.yaml)
|
|
439
1171
|
const { Installer } = require('../installers/lib/core/installer');
|
|
440
1172
|
const installer = new Installer();
|
|
441
|
-
const
|
|
442
|
-
const hasBmadInstall =
|
|
1173
|
+
const bmadResult = await installer.findBmadDir(directory);
|
|
1174
|
+
const hasBmadInstall =
|
|
1175
|
+
(await fs.pathExists(bmadResult.bmadDir)) && (await fs.pathExists(path.join(bmadResult.bmadDir, '_config', 'manifest.yaml')));
|
|
443
1176
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
(hasBmadInstall ? chalk.yellow(` including existing BMAD installation (${path.basename(bmadDir)})`) : ''),
|
|
447
|
-
);
|
|
1177
|
+
const bmadNote = hasBmadInstall ? ` including existing BMAD installation (${path.basename(bmadResult.bmadDir)})` : '';
|
|
1178
|
+
await prompts.log.message(`Directory exists and contains ${files.length} item(s)${bmadNote}`);
|
|
448
1179
|
} else {
|
|
449
|
-
|
|
1180
|
+
await prompts.log.message('Directory exists and is empty');
|
|
450
1181
|
}
|
|
451
1182
|
}
|
|
452
1183
|
}
|
|
@@ -461,41 +1192,89 @@ class UI {
|
|
|
461
1192
|
const dirExists = await fs.pathExists(directory);
|
|
462
1193
|
|
|
463
1194
|
if (dirExists) {
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
message: `Install to this directory?`,
|
|
469
|
-
default: true,
|
|
470
|
-
},
|
|
471
|
-
]);
|
|
1195
|
+
const proceed = await prompts.confirm({
|
|
1196
|
+
message: 'Install to this directory?',
|
|
1197
|
+
default: true,
|
|
1198
|
+
});
|
|
472
1199
|
|
|
473
|
-
if (!
|
|
474
|
-
|
|
1200
|
+
if (!proceed) {
|
|
1201
|
+
await prompts.log.warn("Let's try again with a different path.");
|
|
475
1202
|
}
|
|
476
1203
|
|
|
477
|
-
return
|
|
1204
|
+
return proceed;
|
|
478
1205
|
} else {
|
|
479
1206
|
// Ask for confirmation to create the directory
|
|
480
|
-
const
|
|
481
|
-
{
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
1207
|
+
const create = await prompts.confirm({
|
|
1208
|
+
message: `Create directory: ${directory}?`,
|
|
1209
|
+
default: false,
|
|
1210
|
+
});
|
|
1211
|
+
|
|
1212
|
+
if (!create) {
|
|
1213
|
+
await prompts.log.warn("Let's try again with a different path.");
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
return create;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Validate directory path for installation (sync version for clack prompts)
|
|
1222
|
+
* @param {string} input - User input path
|
|
1223
|
+
* @returns {string|undefined} Error message or undefined if valid
|
|
1224
|
+
*/
|
|
1225
|
+
validateDirectorySync(input) {
|
|
1226
|
+
// Allow empty input to use the default
|
|
1227
|
+
if (!input || input.trim() === '') {
|
|
1228
|
+
return; // Empty means use default, undefined = valid for clack
|
|
1229
|
+
}
|
|
488
1230
|
|
|
489
|
-
|
|
490
|
-
|
|
1231
|
+
let expandedPath;
|
|
1232
|
+
try {
|
|
1233
|
+
expandedPath = this.expandUserPath(input.trim());
|
|
1234
|
+
} catch (error) {
|
|
1235
|
+
return error.message;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
// Check if the path exists
|
|
1239
|
+
const pathExists = fs.pathExistsSync(expandedPath);
|
|
1240
|
+
|
|
1241
|
+
if (!pathExists) {
|
|
1242
|
+
// Find the first existing parent directory
|
|
1243
|
+
const existingParent = this.findExistingParentSync(expandedPath);
|
|
1244
|
+
|
|
1245
|
+
if (!existingParent) {
|
|
1246
|
+
return 'Cannot create directory: no existing parent directory found';
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
// Check if the existing parent is writable
|
|
1250
|
+
try {
|
|
1251
|
+
fs.accessSync(existingParent, fs.constants.W_OK);
|
|
1252
|
+
// Path doesn't exist but can be created - will prompt for confirmation later
|
|
1253
|
+
return;
|
|
1254
|
+
} catch {
|
|
1255
|
+
// Provide a detailed error message explaining both issues
|
|
1256
|
+
return `Directory '${expandedPath}' does not exist and cannot be created: parent directory '${existingParent}' is not writable`;
|
|
491
1257
|
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// If it exists, validate it's a directory and writable
|
|
1261
|
+
const stat = fs.statSync(expandedPath);
|
|
1262
|
+
if (!stat.isDirectory()) {
|
|
1263
|
+
return `Path exists but is not a directory: ${expandedPath}`;
|
|
1264
|
+
}
|
|
492
1265
|
|
|
493
|
-
|
|
1266
|
+
// Check write permissions
|
|
1267
|
+
try {
|
|
1268
|
+
fs.accessSync(expandedPath, fs.constants.W_OK);
|
|
1269
|
+
} catch {
|
|
1270
|
+
return `Directory is not writable: ${expandedPath}`;
|
|
494
1271
|
}
|
|
1272
|
+
|
|
1273
|
+
return;
|
|
495
1274
|
}
|
|
496
1275
|
|
|
497
1276
|
/**
|
|
498
|
-
* Validate directory path for installation
|
|
1277
|
+
* Validate directory path for installation (async version)
|
|
499
1278
|
* @param {string} input - User input path
|
|
500
1279
|
* @returns {string|true} Error message or true if valid
|
|
501
1280
|
*/
|
|
@@ -551,7 +1330,28 @@ class UI {
|
|
|
551
1330
|
}
|
|
552
1331
|
|
|
553
1332
|
/**
|
|
554
|
-
* Find the first existing parent directory
|
|
1333
|
+
* Find the first existing parent directory (sync version)
|
|
1334
|
+
* @param {string} targetPath - The path to check
|
|
1335
|
+
* @returns {string|null} The first existing parent directory, or null if none found
|
|
1336
|
+
*/
|
|
1337
|
+
findExistingParentSync(targetPath) {
|
|
1338
|
+
let currentPath = path.resolve(targetPath);
|
|
1339
|
+
|
|
1340
|
+
// Walk up the directory tree until we find an existing directory
|
|
1341
|
+
while (currentPath !== path.dirname(currentPath)) {
|
|
1342
|
+
// Stop at root
|
|
1343
|
+
const parent = path.dirname(currentPath);
|
|
1344
|
+
if (fs.pathExistsSync(parent)) {
|
|
1345
|
+
return parent;
|
|
1346
|
+
}
|
|
1347
|
+
currentPath = parent;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
return null; // No existing parent found (shouldn't happen in practice)
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
/**
|
|
1354
|
+
* Find the first existing parent directory (async version)
|
|
555
1355
|
* @param {string} targetPath - The path to check
|
|
556
1356
|
* @returns {string|null} The first existing parent directory, or null if none found
|
|
557
1357
|
*/
|
|
@@ -603,6 +1403,534 @@ class UI {
|
|
|
603
1403
|
// Resolve to the absolute path relative to the current working directory
|
|
604
1404
|
return path.resolve(expanded);
|
|
605
1405
|
}
|
|
1406
|
+
|
|
1407
|
+
/**
|
|
1408
|
+
* Load existing configurations to use as defaults
|
|
1409
|
+
* @param {string} directory - Installation directory
|
|
1410
|
+
* @returns {Object} Existing configurations
|
|
1411
|
+
*/
|
|
1412
|
+
async loadExistingConfigurations(directory) {
|
|
1413
|
+
const configs = {
|
|
1414
|
+
hasCustomContent: false,
|
|
1415
|
+
coreConfig: {},
|
|
1416
|
+
ideConfig: { ides: [], skipIde: false },
|
|
1417
|
+
};
|
|
1418
|
+
|
|
1419
|
+
try {
|
|
1420
|
+
// Load core config
|
|
1421
|
+
configs.coreConfig = await this.collectCoreConfig(directory);
|
|
1422
|
+
|
|
1423
|
+
// Load IDE configuration
|
|
1424
|
+
const configuredIdes = await this.getConfiguredIdes(directory);
|
|
1425
|
+
if (configuredIdes.length > 0) {
|
|
1426
|
+
configs.ideConfig.ides = configuredIdes;
|
|
1427
|
+
configs.ideConfig.skipIde = false;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
return configs;
|
|
1431
|
+
} catch {
|
|
1432
|
+
// If loading fails, return empty configs
|
|
1433
|
+
await prompts.log.warn('Could not load existing configurations');
|
|
1434
|
+
return configs;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
/**
|
|
1439
|
+
* Get configured IDEs from existing installation
|
|
1440
|
+
* @param {string} directory - Installation directory
|
|
1441
|
+
* @returns {Array} List of configured IDEs
|
|
1442
|
+
*/
|
|
1443
|
+
async getConfiguredIdes(directory) {
|
|
1444
|
+
const { Detector } = require('../installers/lib/core/detector');
|
|
1445
|
+
const { Installer } = require('../installers/lib/core/installer');
|
|
1446
|
+
const detector = new Detector();
|
|
1447
|
+
const installer = new Installer();
|
|
1448
|
+
const bmadResult = await installer.findBmadDir(directory);
|
|
1449
|
+
const existingInstall = await detector.detect(bmadResult.bmadDir);
|
|
1450
|
+
return existingInstall.ides || [];
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
/**
|
|
1454
|
+
* Validate custom content path synchronously
|
|
1455
|
+
* @param {string} input - User input path
|
|
1456
|
+
* @returns {string|undefined} Error message or undefined if valid
|
|
1457
|
+
*/
|
|
1458
|
+
validateCustomContentPathSync(input) {
|
|
1459
|
+
// Allow empty input to cancel
|
|
1460
|
+
if (!input || input.trim() === '') {
|
|
1461
|
+
return; // Allow empty to exit
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
try {
|
|
1465
|
+
// Expand the path
|
|
1466
|
+
const expandedPath = this.expandUserPath(input.trim());
|
|
1467
|
+
|
|
1468
|
+
// Check if path exists
|
|
1469
|
+
if (!fs.pathExistsSync(expandedPath)) {
|
|
1470
|
+
return 'Path does not exist';
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
// Check if it's a directory
|
|
1474
|
+
const stat = fs.statSync(expandedPath);
|
|
1475
|
+
if (!stat.isDirectory()) {
|
|
1476
|
+
return 'Path must be a directory';
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
// Check for module.yaml in the root
|
|
1480
|
+
const moduleYamlPath = path.join(expandedPath, 'module.yaml');
|
|
1481
|
+
if (!fs.pathExistsSync(moduleYamlPath)) {
|
|
1482
|
+
return 'Directory must contain a module.yaml file in the root';
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// Try to parse the module.yaml to get the module ID
|
|
1486
|
+
try {
|
|
1487
|
+
const yaml = require('yaml');
|
|
1488
|
+
const content = fs.readFileSync(moduleYamlPath, 'utf8');
|
|
1489
|
+
const moduleData = yaml.parse(content);
|
|
1490
|
+
if (!moduleData.code) {
|
|
1491
|
+
return 'module.yaml must contain a "code" field for the module ID';
|
|
1492
|
+
}
|
|
1493
|
+
} catch (error) {
|
|
1494
|
+
return 'Invalid module.yaml file: ' + error.message;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
return; // Valid
|
|
1498
|
+
} catch (error) {
|
|
1499
|
+
return 'Error validating path: ' + error.message;
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
/**
|
|
1504
|
+
* Prompt user for custom content source location
|
|
1505
|
+
* @returns {Object} Custom content configuration
|
|
1506
|
+
*/
|
|
1507
|
+
async promptCustomContentSource() {
|
|
1508
|
+
const customContentConfig = { hasCustomContent: true, sources: [] };
|
|
1509
|
+
|
|
1510
|
+
// Keep asking for more sources until user is done
|
|
1511
|
+
while (true) {
|
|
1512
|
+
// First ask if user wants to add another module or continue
|
|
1513
|
+
if (customContentConfig.sources.length > 0) {
|
|
1514
|
+
const action = await prompts.select({
|
|
1515
|
+
message: 'Would you like to:',
|
|
1516
|
+
choices: [
|
|
1517
|
+
{ name: 'Add another custom module', value: 'add' },
|
|
1518
|
+
{ name: 'Continue with installation', value: 'continue' },
|
|
1519
|
+
],
|
|
1520
|
+
default: 'continue',
|
|
1521
|
+
});
|
|
1522
|
+
|
|
1523
|
+
if (action === 'continue') {
|
|
1524
|
+
break;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
let sourcePath;
|
|
1529
|
+
let isValid = false;
|
|
1530
|
+
|
|
1531
|
+
while (!isValid) {
|
|
1532
|
+
// Use sync validation because @clack/prompts doesn't support async validate
|
|
1533
|
+
const inputPath = await prompts.text({
|
|
1534
|
+
message: 'Path to custom module folder (press Enter to skip):',
|
|
1535
|
+
validate: (input) => this.validateCustomContentPathSync(input),
|
|
1536
|
+
});
|
|
1537
|
+
|
|
1538
|
+
// If user pressed Enter without typing anything, exit the loop
|
|
1539
|
+
if (!inputPath || inputPath.trim() === '') {
|
|
1540
|
+
// If we have no modules yet, return false for no custom content
|
|
1541
|
+
if (customContentConfig.sources.length === 0) {
|
|
1542
|
+
return { hasCustomContent: false };
|
|
1543
|
+
}
|
|
1544
|
+
return customContentConfig;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
sourcePath = this.expandUserPath(inputPath);
|
|
1548
|
+
isValid = true;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
// Read module.yaml to get module info
|
|
1552
|
+
const yaml = require('yaml');
|
|
1553
|
+
const moduleYamlPath = path.join(sourcePath, 'module.yaml');
|
|
1554
|
+
const moduleContent = await fs.readFile(moduleYamlPath, 'utf8');
|
|
1555
|
+
const moduleData = yaml.parse(moduleContent);
|
|
1556
|
+
|
|
1557
|
+
// Add to sources
|
|
1558
|
+
customContentConfig.sources.push({
|
|
1559
|
+
path: sourcePath,
|
|
1560
|
+
id: moduleData.code,
|
|
1561
|
+
name: moduleData.name || moduleData.code,
|
|
1562
|
+
});
|
|
1563
|
+
|
|
1564
|
+
await prompts.log.success(`Confirmed local custom module: ${moduleData.name || moduleData.code}`);
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
// Ask if user wants to add these to the installation
|
|
1568
|
+
const shouldInstall = await prompts.confirm({
|
|
1569
|
+
message: `Install these ${customContentConfig.sources.length} custom modules?`,
|
|
1570
|
+
default: true,
|
|
1571
|
+
});
|
|
1572
|
+
|
|
1573
|
+
if (shouldInstall) {
|
|
1574
|
+
customContentConfig.selected = true;
|
|
1575
|
+
// Store paths to module.yaml files, not directories
|
|
1576
|
+
customContentConfig.selectedFiles = customContentConfig.sources.map((s) => path.join(s.path, 'module.yaml'));
|
|
1577
|
+
// Also include module IDs for installation
|
|
1578
|
+
customContentConfig.selectedModuleIds = customContentConfig.sources.map((s) => s.id);
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
return customContentConfig;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
/**
|
|
1585
|
+
* Handle custom modules in the modify flow
|
|
1586
|
+
* @param {string} directory - Installation directory
|
|
1587
|
+
* @param {Array} selectedModules - Currently selected modules
|
|
1588
|
+
* @returns {Object} Result with selected custom modules and custom content config
|
|
1589
|
+
*/
|
|
1590
|
+
async handleCustomModulesInModifyFlow(directory, selectedModules) {
|
|
1591
|
+
// Get existing installation to find custom modules
|
|
1592
|
+
const { existingInstall } = await this.getExistingInstallation(directory);
|
|
1593
|
+
|
|
1594
|
+
// Check if there are any custom modules in cache
|
|
1595
|
+
const { Installer } = require('../installers/lib/core/installer');
|
|
1596
|
+
const installer = new Installer();
|
|
1597
|
+
const { bmadDir } = await installer.findBmadDir(directory);
|
|
1598
|
+
|
|
1599
|
+
const cacheDir = path.join(bmadDir, '_config', 'custom');
|
|
1600
|
+
const cachedCustomModules = [];
|
|
1601
|
+
|
|
1602
|
+
if (await fs.pathExists(cacheDir)) {
|
|
1603
|
+
const entries = await fs.readdir(cacheDir, { withFileTypes: true });
|
|
1604
|
+
for (const entry of entries) {
|
|
1605
|
+
if (entry.isDirectory()) {
|
|
1606
|
+
const moduleYamlPath = path.join(cacheDir, entry.name, 'module.yaml');
|
|
1607
|
+
if (await fs.pathExists(moduleYamlPath)) {
|
|
1608
|
+
const yaml = require('yaml');
|
|
1609
|
+
const content = await fs.readFile(moduleYamlPath, 'utf8');
|
|
1610
|
+
const moduleData = yaml.parse(content);
|
|
1611
|
+
|
|
1612
|
+
cachedCustomModules.push({
|
|
1613
|
+
id: entry.name,
|
|
1614
|
+
name: moduleData.name || entry.name,
|
|
1615
|
+
description: moduleData.description || 'Custom module from cache',
|
|
1616
|
+
checked: selectedModules.includes(entry.name),
|
|
1617
|
+
fromCache: true,
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
const result = {
|
|
1625
|
+
selectedCustomModules: [],
|
|
1626
|
+
customContentConfig: { hasCustomContent: false },
|
|
1627
|
+
};
|
|
1628
|
+
|
|
1629
|
+
// Ask user about custom modules
|
|
1630
|
+
await prompts.log.info('Custom Modules');
|
|
1631
|
+
if (cachedCustomModules.length > 0) {
|
|
1632
|
+
await prompts.log.message('Found custom modules in your installation:');
|
|
1633
|
+
} else {
|
|
1634
|
+
await prompts.log.message('No custom modules currently installed.');
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
// Build choices dynamically based on whether we have existing modules
|
|
1638
|
+
const choices = [];
|
|
1639
|
+
if (cachedCustomModules.length > 0) {
|
|
1640
|
+
choices.push(
|
|
1641
|
+
{ name: 'Keep all existing custom modules', value: 'keep' },
|
|
1642
|
+
{ name: 'Select which custom modules to keep', value: 'select' },
|
|
1643
|
+
{ name: 'Add new custom modules', value: 'add' },
|
|
1644
|
+
{ name: 'Remove all custom modules', value: 'remove' },
|
|
1645
|
+
);
|
|
1646
|
+
} else {
|
|
1647
|
+
choices.push({ name: 'Add new custom modules', value: 'add' }, { name: 'Cancel (no custom modules)', value: 'cancel' });
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
const customAction = await prompts.select({
|
|
1651
|
+
message: cachedCustomModules.length > 0 ? 'Manage custom modules?' : 'Add custom modules?',
|
|
1652
|
+
choices: choices,
|
|
1653
|
+
default: cachedCustomModules.length > 0 ? 'keep' : 'add',
|
|
1654
|
+
});
|
|
1655
|
+
|
|
1656
|
+
switch (customAction) {
|
|
1657
|
+
case 'keep': {
|
|
1658
|
+
// Keep all existing custom modules
|
|
1659
|
+
result.selectedCustomModules = cachedCustomModules.map((m) => m.id);
|
|
1660
|
+
await prompts.log.message(`Keeping ${result.selectedCustomModules.length} custom module(s)`);
|
|
1661
|
+
break;
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
case 'select': {
|
|
1665
|
+
// Let user choose which to keep
|
|
1666
|
+
const selectChoices = cachedCustomModules.map((m) => ({
|
|
1667
|
+
name: `${m.name} (${m.id})`,
|
|
1668
|
+
value: m.id,
|
|
1669
|
+
checked: m.checked,
|
|
1670
|
+
}));
|
|
1671
|
+
|
|
1672
|
+
// Add "None / I changed my mind" option at the end
|
|
1673
|
+
const choicesWithSkip = [
|
|
1674
|
+
...selectChoices,
|
|
1675
|
+
{
|
|
1676
|
+
name: '⚠ None / I changed my mind - keep no custom modules',
|
|
1677
|
+
value: '__NONE__',
|
|
1678
|
+
checked: false,
|
|
1679
|
+
},
|
|
1680
|
+
];
|
|
1681
|
+
|
|
1682
|
+
const keepModules = await prompts.multiselect({
|
|
1683
|
+
message: 'Select custom modules to keep (use arrow keys, space to toggle):',
|
|
1684
|
+
choices: choicesWithSkip,
|
|
1685
|
+
required: true,
|
|
1686
|
+
});
|
|
1687
|
+
|
|
1688
|
+
// If user selected both "__NONE__" and other modules, honor the "None" choice
|
|
1689
|
+
if (keepModules && keepModules.includes('__NONE__') && keepModules.length > 1) {
|
|
1690
|
+
await prompts.log.warn('"None / I changed my mind" was selected, so no custom modules will be kept.');
|
|
1691
|
+
result.selectedCustomModules = [];
|
|
1692
|
+
} else {
|
|
1693
|
+
// Filter out the special '__NONE__' value
|
|
1694
|
+
result.selectedCustomModules = keepModules ? keepModules.filter((m) => m !== '__NONE__') : [];
|
|
1695
|
+
}
|
|
1696
|
+
break;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
case 'add': {
|
|
1700
|
+
// By default, keep existing modules when adding new ones
|
|
1701
|
+
// User chose "Add new" not "Replace", so we assume they want to keep existing
|
|
1702
|
+
result.selectedCustomModules = cachedCustomModules.map((m) => m.id);
|
|
1703
|
+
|
|
1704
|
+
// Then prompt for new ones (reuse existing method)
|
|
1705
|
+
const newCustomContent = await this.promptCustomContentSource();
|
|
1706
|
+
if (newCustomContent.hasCustomContent && newCustomContent.selected) {
|
|
1707
|
+
result.selectedCustomModules.push(...newCustomContent.selectedModuleIds);
|
|
1708
|
+
result.customContentConfig = newCustomContent;
|
|
1709
|
+
}
|
|
1710
|
+
break;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
case 'remove': {
|
|
1714
|
+
// Remove all custom modules
|
|
1715
|
+
await prompts.log.warn('All custom modules will be removed from the installation');
|
|
1716
|
+
break;
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
case 'cancel': {
|
|
1720
|
+
// User cancelled - no custom modules
|
|
1721
|
+
await prompts.log.message('No custom modules will be added');
|
|
1722
|
+
break;
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
return result;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
/**
|
|
1730
|
+
* Check if installed version is a legacy version that needs fresh install
|
|
1731
|
+
* @param {string} installedVersion - The installed version
|
|
1732
|
+
* @returns {boolean} True if legacy (v4 or any alpha)
|
|
1733
|
+
*/
|
|
1734
|
+
isLegacyVersion(installedVersion) {
|
|
1735
|
+
if (!installedVersion || installedVersion === 'unknown') {
|
|
1736
|
+
return true; // Treat unknown as legacy for safety
|
|
1737
|
+
}
|
|
1738
|
+
// Check if version string contains -alpha or -Alpha (any v6 alpha)
|
|
1739
|
+
return /-alpha\./i.test(installedVersion);
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
/**
|
|
1743
|
+
* Show warning for legacy version (v4 or alpha) and ask if user wants to proceed
|
|
1744
|
+
* @param {string} installedVersion - The installed version
|
|
1745
|
+
* @param {string} currentVersion - The current version
|
|
1746
|
+
* @param {string} bmadFolderName - Name of the BMAD folder
|
|
1747
|
+
* @returns {Promise<boolean>} True if user wants to proceed, false if they cancel
|
|
1748
|
+
*/
|
|
1749
|
+
async showLegacyVersionWarning(installedVersion, currentVersion, bmadFolderName, options = {}) {
|
|
1750
|
+
if (!this.isLegacyVersion(installedVersion)) {
|
|
1751
|
+
return true; // Not legacy, proceed
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
let warningContent;
|
|
1755
|
+
if (installedVersion === 'unknown') {
|
|
1756
|
+
warningContent = 'Unable to detect your installed BMAD version.\n' + 'This appears to be a legacy or unsupported installation.';
|
|
1757
|
+
} else {
|
|
1758
|
+
warningContent =
|
|
1759
|
+
`You are updating from ${installedVersion} to ${currentVersion}.\n` + 'You have a legacy version installed (v4 or alpha).';
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
warningContent +=
|
|
1763
|
+
'\n\nFor the best experience, we recommend:\n' +
|
|
1764
|
+
' 1. Delete your current BMAD installation folder\n' +
|
|
1765
|
+
` (the "${bmadFolderName}/" folder in your project)\n` +
|
|
1766
|
+
' 2. Run a fresh installation\n\n' +
|
|
1767
|
+
'Benefits of a fresh install:\n' +
|
|
1768
|
+
' \u2022 Cleaner configuration without legacy artifacts\n' +
|
|
1769
|
+
' \u2022 All new features properly configured\n' +
|
|
1770
|
+
' \u2022 Fewer potential conflicts';
|
|
1771
|
+
|
|
1772
|
+
await prompts.log.warn('VERSION WARNING');
|
|
1773
|
+
await prompts.note(warningContent, 'Version Warning');
|
|
1774
|
+
|
|
1775
|
+
if (options.yes) {
|
|
1776
|
+
await prompts.log.warn('Non-interactive mode (--yes): auto-proceeding with legacy update');
|
|
1777
|
+
return true;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
const proceed = await prompts.select({
|
|
1781
|
+
message: 'How would you like to proceed?',
|
|
1782
|
+
choices: [
|
|
1783
|
+
{
|
|
1784
|
+
name: 'Proceed with update anyway (may have issues)',
|
|
1785
|
+
value: 'proceed',
|
|
1786
|
+
},
|
|
1787
|
+
{
|
|
1788
|
+
name: 'Cancel (recommended - do a fresh install instead)',
|
|
1789
|
+
value: 'cancel',
|
|
1790
|
+
},
|
|
1791
|
+
],
|
|
1792
|
+
default: 'cancel',
|
|
1793
|
+
});
|
|
1794
|
+
|
|
1795
|
+
if (proceed === 'cancel') {
|
|
1796
|
+
await prompts.note(
|
|
1797
|
+
`1. Delete the "${bmadFolderName}/" folder in your project\n` + "2. Run 'bmad install' again",
|
|
1798
|
+
'To do a fresh install',
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
return proceed === 'proceed';
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
/**
|
|
1806
|
+
* Display module versions with update availability
|
|
1807
|
+
* @param {Array} modules - Array of module info objects with version info
|
|
1808
|
+
* @param {Array} availableUpdates - Array of available updates
|
|
1809
|
+
*/
|
|
1810
|
+
async displayModuleVersions(modules, availableUpdates = []) {
|
|
1811
|
+
// Group modules by source
|
|
1812
|
+
const builtIn = modules.filter((m) => m.source === 'built-in');
|
|
1813
|
+
const external = modules.filter((m) => m.source === 'external');
|
|
1814
|
+
const custom = modules.filter((m) => m.source === 'custom');
|
|
1815
|
+
const unknown = modules.filter((m) => m.source === 'unknown');
|
|
1816
|
+
|
|
1817
|
+
const lines = [];
|
|
1818
|
+
const formatGroup = (group, title) => {
|
|
1819
|
+
if (group.length === 0) return;
|
|
1820
|
+
lines.push(title);
|
|
1821
|
+
for (const mod of group) {
|
|
1822
|
+
const updateInfo = availableUpdates.find((u) => u.name === mod.name);
|
|
1823
|
+
const versionDisplay = mod.version || 'unknown';
|
|
1824
|
+
if (updateInfo) {
|
|
1825
|
+
lines.push(` ${mod.name.padEnd(20)} ${versionDisplay} \u2192 ${updateInfo.latestVersion} \u2191`);
|
|
1826
|
+
} else {
|
|
1827
|
+
lines.push(` ${mod.name.padEnd(20)} ${versionDisplay} \u2713`);
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
};
|
|
1831
|
+
|
|
1832
|
+
formatGroup(builtIn, 'Built-in Modules');
|
|
1833
|
+
formatGroup(external, 'External Modules (Official)');
|
|
1834
|
+
formatGroup(custom, 'Custom Modules');
|
|
1835
|
+
formatGroup(unknown, 'Other Modules');
|
|
1836
|
+
|
|
1837
|
+
await prompts.note(lines.join('\n'), 'Module Versions');
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
/**
|
|
1841
|
+
* Prompt user to select which modules to update
|
|
1842
|
+
* @param {Array} availableUpdates - Array of available updates
|
|
1843
|
+
* @returns {Array} Selected module names to update
|
|
1844
|
+
*/
|
|
1845
|
+
async promptUpdateSelection(availableUpdates) {
|
|
1846
|
+
if (availableUpdates.length === 0) {
|
|
1847
|
+
return [];
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
await prompts.log.info('Available Updates');
|
|
1851
|
+
|
|
1852
|
+
const choices = availableUpdates.map((update) => ({
|
|
1853
|
+
name: `${update.name} (v${update.installedVersion} \u2192 v${update.latestVersion})`,
|
|
1854
|
+
value: update.name,
|
|
1855
|
+
checked: true, // Default to selecting all updates
|
|
1856
|
+
}));
|
|
1857
|
+
|
|
1858
|
+
// Add "Update All" and "Cancel" options
|
|
1859
|
+
const action = await prompts.select({
|
|
1860
|
+
message: 'How would you like to proceed?',
|
|
1861
|
+
choices: [
|
|
1862
|
+
{ name: 'Update all available modules', value: 'all' },
|
|
1863
|
+
{ name: 'Select specific modules to update', value: 'select' },
|
|
1864
|
+
{ name: 'Skip updates for now', value: 'skip' },
|
|
1865
|
+
],
|
|
1866
|
+
default: 'all',
|
|
1867
|
+
});
|
|
1868
|
+
|
|
1869
|
+
if (action === 'all') {
|
|
1870
|
+
return availableUpdates.map((u) => u.name);
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
if (action === 'skip') {
|
|
1874
|
+
return [];
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
// Allow specific selection
|
|
1878
|
+
const selected = await prompts.multiselect({
|
|
1879
|
+
message: 'Select modules to update (use arrow keys, space to toggle):',
|
|
1880
|
+
choices: choices,
|
|
1881
|
+
required: true,
|
|
1882
|
+
});
|
|
1883
|
+
|
|
1884
|
+
return selected || [];
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
/**
|
|
1888
|
+
* Display status of all installed modules
|
|
1889
|
+
* @param {Object} statusData - Status data with modules, installation info, and available updates
|
|
1890
|
+
*/
|
|
1891
|
+
async displayStatus(statusData) {
|
|
1892
|
+
const { installation, modules, availableUpdates, bmadDir } = statusData;
|
|
1893
|
+
|
|
1894
|
+
// Installation info
|
|
1895
|
+
const infoLines = [
|
|
1896
|
+
`Version: ${installation.version || 'unknown'}`,
|
|
1897
|
+
`Location: ${bmadDir}`,
|
|
1898
|
+
`Installed: ${new Date(installation.installDate).toLocaleDateString()}`,
|
|
1899
|
+
`Last Updated: ${installation.lastUpdated ? new Date(installation.lastUpdated).toLocaleDateString() : 'unknown'}`,
|
|
1900
|
+
];
|
|
1901
|
+
|
|
1902
|
+
await prompts.note(infoLines.join('\n'), 'BMAD Status');
|
|
1903
|
+
|
|
1904
|
+
// Module versions
|
|
1905
|
+
await this.displayModuleVersions(modules, availableUpdates);
|
|
1906
|
+
|
|
1907
|
+
// Update summary
|
|
1908
|
+
if (availableUpdates.length > 0) {
|
|
1909
|
+
await prompts.log.warn(`${availableUpdates.length} update(s) available`);
|
|
1910
|
+
await prompts.log.message('Run \'bmad install\' and select "Quick Update" to update');
|
|
1911
|
+
} else {
|
|
1912
|
+
await prompts.log.success('All modules are up to date');
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
/**
|
|
1917
|
+
* Display list of selected tools after IDE selection
|
|
1918
|
+
* @param {Array} selectedIdes - Array of selected IDE values
|
|
1919
|
+
* @param {Array} preferredIdes - Array of preferred IDE objects
|
|
1920
|
+
* @param {Array} allTools - Array of all tool objects
|
|
1921
|
+
*/
|
|
1922
|
+
async displaySelectedTools(selectedIdes, preferredIdes, allTools) {
|
|
1923
|
+
if (selectedIdes.length === 0) return;
|
|
1924
|
+
|
|
1925
|
+
const preferredValues = new Set(preferredIdes.map((ide) => ide.value));
|
|
1926
|
+
const toolLines = selectedIdes.map((ideValue) => {
|
|
1927
|
+
const tool = allTools.find((t) => t.value === ideValue);
|
|
1928
|
+
const name = tool?.name || ideValue;
|
|
1929
|
+
const marker = preferredValues.has(ideValue) ? ' \u2B50' : '';
|
|
1930
|
+
return ` \u2022 ${name}${marker}`;
|
|
1931
|
+
});
|
|
1932
|
+
await prompts.log.message('Selected tools:\n' + toolLines.join('\n'));
|
|
1933
|
+
}
|
|
606
1934
|
}
|
|
607
1935
|
|
|
608
1936
|
module.exports = { UI };
|