bmad-method 6.0.0-alpha.15 → 6.0.0-alpha.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.coderabbit.yaml +8 -4
- package/.github/scripts/discord-helpers.sh +21 -2
- package/.github/workflows/discord.yaml +31 -7
- package/.github/workflows/manual-release.yaml +12 -42
- package/.markdownlint-cli2.yaml +2 -2
- package/.prettierignore +2 -2
- package/.vscode/settings.json +1 -1
- package/CHANGELOG.md +126 -1
- package/LICENSE +1 -1
- package/README.md +29 -2
- package/docs/agent-customization-guide.md +10 -10
- package/docs/custom-content-installation.md +100 -196
- package/docs/custom-content.md +122 -0
- package/docs/ide-info/crush.md +1 -1
- package/docs/ide-info/cursor.md +7 -7
- package/docs/ide-info/iflow.md +3 -3
- package/docs/ide-info/opencode.md +1 -1
- package/docs/ide-info/rovo-dev.md +1 -1
- package/docs/index.md +2 -2
- package/docs/installers-bundlers/ide-injections.md +2 -2
- package/docs/installers-bundlers/installers-modules-platforms-reference.md +25 -25
- package/docs/sample-custom-modules/README.md +11 -0
- package/docs/sample-custom-modules/sample-unitary-module/README.md +8 -0
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/agents/commit-poet/commit-poet.agent.yaml +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/agents/toolsmith/toolsmith.agent.yaml +14 -14
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/module.yaml +5 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-01-init.md +2 -2
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-02-q1.md +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-03-q2.md +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-04-q3.md +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-05-q4.md +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-06-q5.md +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-07-q6.md +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-08-q7.md +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-09-q8.md +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-10-q9.md +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-11-q10.md +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/steps/step-12-results.md +1 -1
- package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/workflow.md +1 -1
- package/docs/sample-custom-modules/sample-wellness-module/README.md +6 -0
- package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/agents/meditation-guide.agent.yaml +37 -39
- package/docs/sample-custom-modules/sample-wellness-module/agents/wellness-companion/foo.md +3 -0
- package/docs/sample-custom-modules/sample-wellness-module/agents/wellness-companion/wellness-companion-sidecar/addition1.md +1 -0
- package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/agents/wellness-companion/wellness-companion.agent.yaml +8 -13
- package/docs/sample-custom-modules/sample-wellness-module/module.yaml +17 -0
- package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/workflows/wellness-journal/workflow.md +3 -3
- package/docs/v4-to-v6-upgrade.md +27 -27
- package/docs/web-bundles-gemini-gpt-guide.md +6 -458
- package/eslint.config.mjs +2 -2
- package/package.json +1 -1
- package/src/core/agents/bmad-master.agent.yaml +6 -11
- package/src/core/module.yaml +10 -24
- package/src/core/resources/excalidraw/README.md +6 -6
- package/src/core/tasks/advanced-elicitation.xml +3 -3
- package/src/core/tasks/index-docs.xml +1 -1
- package/src/core/tasks/validate-workflow.xml +1 -1
- package/src/core/tasks/workflow.xml +4 -4
- package/src/core/tools/shard-doc.xml +12 -12
- package/src/core/workflows/brainstorming/workflow.md +3 -3
- package/src/core/workflows/party-mode/steps/step-01-agent-loading.md +2 -2
- package/src/core/workflows/party-mode/workflow.md +4 -4
- package/src/modules/bmb/agents/bmad-builder.agent.yaml +15 -15
- package/src/modules/bmb/{README.md → docs/README.md} +15 -27
- package/src/modules/bmb/docs/agents/agent-compilation.md +3 -3
- package/src/modules/bmb/docs/agents/agent-menu-patterns.md +23 -24
- package/src/modules/bmb/docs/agents/expert-agent-architecture.md +21 -22
- package/src/modules/bmb/docs/agents/index.md +1 -1
- package/src/modules/bmb/docs/agents/simple-agent-architecture.md +17 -52
- package/src/modules/bmb/docs/agents/understanding-agent-types.md +6 -6
- package/src/modules/bmb/docs/workflows/architecture.md +1 -1
- package/src/modules/bmb/docs/workflows/common-workflow-tools.csv +3 -3
- package/src/modules/bmb/docs/workflows/templates/step-01-init-continuable-template.md +1 -1
- package/src/modules/bmb/docs/workflows/templates/step-1b-template.md +1 -1
- package/src/modules/bmb/docs/workflows/templates/step-file.md +3 -3
- package/src/modules/bmb/docs/workflows/templates/step-template.md +3 -3
- package/src/modules/bmb/docs/workflows/templates/workflow-template.md +2 -2
- package/src/modules/bmb/docs/workflows/templates/workflow.md +1 -1
- package/src/modules/bmb/module.yaml +6 -16
- package/src/modules/bmb/reference/agents/expert-examples/journal-keeper/journal-keeper.agent.yaml +7 -7
- package/src/modules/bmb/reference/agents/module-examples/README.md +3 -4
- package/src/modules/bmb/reference/agents/module-examples/security-engineer.agent.yaml +5 -5
- package/src/modules/bmb/reference/agents/module-examples/trend-analyst.agent.yaml +7 -7
- package/src/modules/bmb/reference/agents/simple-examples/README.md +1 -1
- package/src/modules/bmb/reference/agents/simple-examples/commit-poet.agent.yaml +1 -1
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-01-init.md +1 -1
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-01b-continue.md +1 -1
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-02-profile.md +3 -3
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-03-assessment.md +3 -3
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-04-strategy.md +5 -5
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-05-shopping.md +5 -5
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/steps/step-06-prep-schedule.md +5 -5
- package/src/modules/bmb/reference/workflows/meal-prep-nutrition/workflow.md +2 -2
- package/src/modules/bmb/workflows/create-agent/data/reference/agents/module-examples/README.md +1 -3
- package/src/modules/bmb/workflows/create-agent/data/reference/agents/module-examples/security-engineer.agent.yaml +6 -6
- package/src/modules/bmb/workflows/create-agent/data/reference/agents/module-examples/trend-analyst.agent.yaml +7 -7
- package/src/modules/bmb/workflows/create-agent/data/reference/agents/simple-examples/README.md +1 -1
- package/src/modules/bmb/workflows/create-agent/data/reference/agents/simple-examples/commit-poet.agent.yaml +1 -1
- package/src/modules/bmb/workflows/create-agent/data/reference/workflows/meal-prep-nutrition/steps/step-01-init.md +1 -1
- package/src/modules/bmb/workflows/create-agent/data/reference/workflows/meal-prep-nutrition/steps/step-01b-continue.md +1 -1
- package/src/modules/bmb/workflows/create-agent/data/reference/workflows/meal-prep-nutrition/steps/step-02-profile.md +3 -3
- package/src/modules/bmb/workflows/create-agent/data/reference/workflows/meal-prep-nutrition/steps/step-03-assessment.md +3 -3
- package/src/modules/bmb/workflows/create-agent/data/reference/workflows/meal-prep-nutrition/steps/step-04-strategy.md +5 -5
- package/src/modules/bmb/workflows/create-agent/data/reference/workflows/meal-prep-nutrition/steps/step-05-shopping.md +5 -5
- package/src/modules/bmb/workflows/create-agent/data/reference/workflows/meal-prep-nutrition/steps/step-06-prep-schedule.md +5 -5
- package/src/modules/bmb/workflows/create-agent/data/reference/workflows/meal-prep-nutrition/workflow.md +2 -2
- package/src/modules/bmb/workflows/create-agent/data/validation-complete.md +5 -5
- package/src/modules/bmb/workflows/create-agent/steps/step-01-brainstorm.md +5 -5
- package/src/modules/bmb/workflows/create-agent/steps/step-02-discover.md +7 -11
- package/src/modules/bmb/workflows/create-agent/steps/step-03-persona.md +7 -7
- package/src/modules/bmb/workflows/create-agent/steps/step-04-commands.md +10 -10
- package/src/modules/bmb/workflows/create-agent/steps/step-05-name.md +7 -6
- package/src/modules/bmb/workflows/create-agent/steps/step-06-build.md +20 -58
- package/src/modules/bmb/workflows/create-agent/steps/step-07-validate.md +6 -6
- package/src/modules/bmb/workflows/create-agent/steps/{step-11-celebrate.md → step-08-celebrate.md} +3 -7
- package/src/modules/bmb/workflows/create-agent/templates/agent-plan.template.md +3 -0
- package/src/modules/bmb/workflows/create-agent/templates/expert-agent.template.md +364 -0
- package/src/modules/bmb/workflows/create-agent/templates/simple-agent.template.md +257 -0
- package/src/modules/bmb/workflows/create-agent/workflow.md +2 -35
- package/src/modules/bmb/workflows/create-module/steps/step-01-init.md +4 -4
- package/src/modules/bmb/workflows/create-module/steps/step-01b-continue.md +2 -2
- package/src/modules/bmb/workflows/create-module/steps/step-02-concept.md +5 -5
- package/src/modules/bmb/workflows/create-module/steps/step-03-components.md +5 -5
- package/src/modules/bmb/workflows/create-module/steps/step-04-structure.md +6 -6
- package/src/modules/bmb/workflows/create-module/steps/step-05-config.md +5 -5
- package/src/modules/bmb/workflows/create-module/steps/step-06-agents.md +9 -9
- package/src/modules/bmb/workflows/create-module/steps/step-07-workflows.md +5 -5
- package/src/modules/bmb/workflows/create-module/steps/step-08-installer.md +8 -8
- package/src/modules/bmb/workflows/create-module/steps/step-09-documentation.md +7 -7
- package/src/modules/bmb/workflows/create-module/steps/step-10-roadmap.md +7 -7
- package/src/modules/bmb/workflows/create-module/steps/step-11-validate.md +6 -6
- package/src/modules/bmb/workflows/create-module/templates/agent.template.md +15 -19
- package/src/modules/bmb/workflows/create-module/templates/module.template.yaml +1 -1
- package/src/modules/bmb/workflows/create-module/workflow.md +3 -3
- package/src/modules/bmb/workflows/create-workflow/steps/step-01-init.md +4 -4
- package/src/modules/bmb/workflows/create-workflow/steps/step-02-gather.md +6 -6
- package/src/modules/bmb/workflows/create-workflow/steps/step-03-tools-configuration.md +5 -5
- package/src/modules/bmb/workflows/create-workflow/steps/step-04-plan-review.md +4 -4
- package/src/modules/bmb/workflows/create-workflow/steps/step-05-output-format-design.md +4 -4
- package/src/modules/bmb/workflows/create-workflow/steps/step-06-design.md +11 -11
- package/src/modules/bmb/workflows/create-workflow/steps/step-07-build.md +14 -14
- package/src/modules/bmb/workflows/create-workflow/steps/step-08-review.md +4 -4
- package/src/modules/bmb/workflows/create-workflow/steps/step-09-complete.md +2 -2
- package/src/modules/bmb/workflows/create-workflow/workflow.md +2 -2
- package/src/modules/bmb/workflows/edit-agent/steps/step-01-discover-intent.md +3 -3
- package/src/modules/bmb/workflows/edit-agent/steps/step-02-analyze-agent.md +13 -13
- package/src/modules/bmb/workflows/edit-agent/steps/step-03-propose-changes.md +5 -5
- package/src/modules/bmb/workflows/edit-agent/steps/step-04-apply-changes.md +3 -3
- package/src/modules/bmb/workflows/edit-agent/steps/step-05-validate.md +5 -5
- package/src/modules/bmb/workflows/edit-agent/workflow.md +1 -1
- package/src/modules/bmb/workflows/edit-workflow/steps/step-01-analyze.md +4 -4
- package/src/modules/bmb/workflows/edit-workflow/steps/step-02-discover.md +3 -3
- package/src/modules/bmb/workflows/edit-workflow/steps/step-03-improve.md +6 -6
- package/src/modules/bmb/workflows/edit-workflow/steps/step-04-validate.md +3 -3
- package/src/modules/bmb/workflows/edit-workflow/steps/step-05-compliance-check.md +3 -3
- package/src/modules/bmb/workflows/edit-workflow/workflow.md +1 -1
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-01-validate-goal.md +3 -3
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-02-workflow-validation.md +5 -5
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-03-step-validation.md +6 -6
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-04-file-validation.md +4 -4
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-05-intent-spectrum-validation.md +4 -4
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-06-web-subprocess-validation.md +4 -4
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-07-holistic-analysis.md +4 -4
- package/src/modules/bmb/workflows/workflow-compliance-check/steps/step-08-generate-report.md +3 -3
- package/src/modules/bmb/workflows/workflow-compliance-check/workflow.md +1 -1
- package/src/modules/bmb/workflows-legacy/edit-module/README.md +1 -17
- package/src/modules/bmb/workflows-legacy/edit-module/checklist.md +3 -4
- package/src/modules/bmb/workflows-legacy/edit-module/instructions.md +4 -5
- package/src/modules/bmb/workflows-legacy/edit-module/workflow.yaml +10 -10
- package/src/modules/bmb/workflows-legacy/module-brief/README.md +2 -2
- package/src/modules/bmb/workflows-legacy/module-brief/instructions.md +2 -2
- package/src/modules/bmb/workflows-legacy/module-brief/workflow.yaml +4 -4
- package/src/modules/bmgd/README.md +1 -1
- package/src/modules/bmgd/agents/game-architect.agent.yaml +6 -6
- package/src/modules/bmgd/agents/game-designer.agent.yaml +7 -7
- package/src/modules/bmgd/agents/game-dev.agent.yaml +10 -10
- package/src/modules/bmgd/agents/game-scrum-master.agent.yaml +21 -21
- package/src/modules/bmgd/module.yaml +2 -8
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/instructions.md +1 -1
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/workflow.yaml +9 -9
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/instructions.md +1 -1
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/workflow.yaml +8 -8
- package/src/modules/bmgd/workflows/2-design/gdd/instructions-gdd.md +4 -4
- package/src/modules/bmgd/workflows/2-design/gdd/workflow.yaml +30 -30
- package/src/modules/bmgd/workflows/2-design/narrative/instructions-narrative.md +1 -1
- package/src/modules/bmgd/workflows/2-design/narrative/workflow.yaml +5 -5
- package/src/modules/bmgd/workflows/3-technical/game-architecture/instructions.md +1 -1
- package/src/modules/bmgd/workflows/3-technical/game-architecture/workflow.yaml +2 -2
- package/src/modules/bmgd/workflows/4-production/code-review/instructions.md +4 -4
- package/src/modules/bmgd/workflows/4-production/code-review/workflow.yaml +2 -2
- package/src/modules/bmgd/workflows/4-production/correct-course/checklist.md +1 -1
- package/src/modules/bmgd/workflows/4-production/correct-course/instructions.md +2 -2
- package/src/modules/bmgd/workflows/4-production/correct-course/workflow.yaml +2 -2
- package/src/modules/bmgd/workflows/4-production/create-story/instructions.md +2 -2
- package/src/modules/bmgd/workflows/4-production/create-story/workflow.yaml +2 -2
- package/src/modules/bmgd/workflows/4-production/dev-story/instructions.md +2 -2
- package/src/modules/bmgd/workflows/4-production/dev-story/workflow.yaml +2 -2
- package/src/modules/bmgd/workflows/4-production/epic-tech-context/checklist.md +1 -1
- package/src/modules/bmgd/workflows/4-production/epic-tech-context/instructions.md +2 -2
- package/src/modules/bmgd/workflows/4-production/epic-tech-context/workflow.yaml +2 -2
- package/src/modules/bmgd/workflows/4-production/retrospective/instructions.md +2 -2
- package/src/modules/bmgd/workflows/4-production/retrospective/workflow.yaml +3 -3
- package/src/modules/bmgd/workflows/4-production/sprint-planning/instructions.md +2 -2
- package/src/modules/bmgd/workflows/4-production/sprint-planning/workflow.yaml +2 -2
- package/src/modules/bmgd/workflows/4-production/story-context/checklist.md +1 -1
- package/src/modules/bmgd/workflows/4-production/story-context/context-template.xml +2 -2
- package/src/modules/bmgd/workflows/4-production/story-context/instructions.md +2 -2
- package/src/modules/bmgd/workflows/4-production/story-context/workflow.yaml +2 -2
- package/src/modules/bmgd/workflows/4-production/story-done/instructions.md +1 -1
- package/src/modules/bmgd/workflows/4-production/story-done/workflow.yaml +2 -2
- package/src/modules/bmgd/workflows/4-production/story-ready/instructions.md +1 -1
- package/src/modules/bmgd/workflows/4-production/story-ready/workflow.yaml +2 -2
- package/src/modules/bmm/README.md +1 -1
- package/src/modules/bmm/agents/analyst.agent.yaml +9 -9
- package/src/modules/bmm/agents/architect.agent.yaml +8 -8
- package/src/modules/bmm/agents/dev.agent.yaml +5 -5
- package/src/modules/bmm/agents/pm.agent.yaml +8 -8
- package/src/modules/bmm/agents/quick-flow-solo-dev.agent.yaml +5 -5
- package/src/modules/bmm/agents/sm.agent.yaml +11 -11
- package/src/modules/bmm/agents/tea.agent.yaml +13 -13
- package/src/modules/bmm/agents/tech-writer.agent.yaml +9 -9
- package/src/modules/bmm/agents/ux-designer.agent.yaml +6 -6
- package/src/modules/bmm/docs/README.md +0 -25
- package/src/modules/bmm/docs/agents-guide.md +16 -14
- package/src/modules/bmm/docs/brownfield-guide.md +6 -6
- package/src/modules/bmm/docs/enterprise-agentic-development.md +3 -3
- package/src/modules/bmm/docs/faq.md +5 -18
- package/src/modules/bmm/docs/glossary.md +3 -4
- package/src/modules/bmm/docs/images/README.md +1 -1
- package/src/modules/bmm/docs/images/workflow-method-greenfield.excalidraw +8 -8
- package/src/modules/bmm/docs/party-mode.md +3 -3
- package/src/modules/bmm/docs/quick-flow-solo-dev.md +5 -5
- package/src/modules/bmm/docs/quick-spec-flow.md +2 -16
- package/src/modules/bmm/docs/quick-start.md +3 -3
- package/src/modules/bmm/docs/test-architecture.md +15 -23
- package/src/modules/bmm/docs/troubleshooting.md +6 -25
- package/src/modules/bmm/docs/workflow-document-project-reference.md +1 -1
- package/src/modules/bmm/docs/workflows-implementation.md +3 -104
- package/src/modules/bmm/module.yaml +25 -24
- package/src/modules/bmm/testarch/knowledge/overview.md +0 -1
- package/src/modules/bmm/workflows/1-analysis/{product-brief → create-product-brief}/steps/step-01-init.md +1 -1
- package/src/modules/bmm/workflows/1-analysis/{product-brief → create-product-brief}/steps/step-01b-continue.md +1 -1
- package/src/modules/bmm/workflows/1-analysis/{product-brief → create-product-brief}/steps/step-02-vision.md +3 -3
- package/src/modules/bmm/workflows/1-analysis/{product-brief → create-product-brief}/steps/step-03-users.md +3 -3
- package/src/modules/bmm/workflows/1-analysis/{product-brief → create-product-brief}/steps/step-04-metrics.md +3 -3
- package/src/modules/bmm/workflows/1-analysis/{product-brief → create-product-brief}/steps/step-05-scope.md +3 -3
- package/src/modules/bmm/workflows/1-analysis/{product-brief → create-product-brief}/steps/step-06-complete.md +5 -3
- package/src/modules/bmm/workflows/1-analysis/{product-brief → create-product-brief}/workflow.md +2 -2
- package/src/modules/bmm/workflows/1-analysis/research/workflow.md +2 -2
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +4 -4
- package/src/modules/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +2 -2
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-01-init.md +1 -1
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-01b-continue.md +1 -1
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-02-discovery.md +3 -3
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-03-success.md +7 -7
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-04-journeys.md +8 -8
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-05-domain.md +12 -12
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-06-innovation.md +12 -12
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-07-project-type.md +10 -10
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-08-scoping.md +7 -7
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-09-functional.md +9 -9
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-10-nonfunctional.md +9 -9
- package/src/modules/bmm/workflows/2-plan-workflows/prd/steps/step-11-complete.md +1 -1
- package/src/modules/bmm/workflows/2-plan-workflows/prd/workflow.md +2 -2
- package/src/modules/bmm/workflows/3-solutioning/{implementation-readiness → check-implementation-readiness}/steps/step-01-document-discovery.md +1 -1
- package/src/modules/bmm/workflows/3-solutioning/{implementation-readiness → check-implementation-readiness}/steps/step-02-prd-analysis.md +1 -1
- package/src/modules/bmm/workflows/3-solutioning/{implementation-readiness → check-implementation-readiness}/steps/step-03-epic-coverage-validation.md +6 -6
- package/src/modules/bmm/workflows/3-solutioning/{implementation-readiness → check-implementation-readiness}/steps/step-04-ux-alignment.md +1 -1
- package/src/modules/bmm/workflows/3-solutioning/{implementation-readiness → check-implementation-readiness}/steps/step-05-epic-quality-review.md +2 -2
- package/src/modules/bmm/workflows/3-solutioning/{implementation-readiness → check-implementation-readiness}/steps/step-06-final-assessment.md +1 -1
- package/src/modules/bmm/workflows/3-solutioning/{implementation-readiness → check-implementation-readiness}/workflow.md +1 -1
- package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/steps/step-01-init.md +1 -1
- package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/steps/step-02-context.md +4 -4
- package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/steps/step-03-starter.md +4 -4
- package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/steps/step-04-decisions.md +4 -4
- package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/steps/step-05-patterns.md +4 -4
- package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/steps/step-06-structure.md +4 -4
- package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/steps/step-07-validation.md +4 -4
- package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/steps/step-08-complete.md +3 -3
- package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/workflow.md +2 -2
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md +3 -3
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +3 -3
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +3 -3
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +3 -3
- package/src/modules/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +3 -3
- package/src/modules/bmm/workflows/4-implementation/code-review/instructions.xml +4 -3
- package/src/modules/bmm/workflows/4-implementation/code-review/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/4-implementation/correct-course/checklist.md +1 -1
- package/src/modules/bmm/workflows/4-implementation/correct-course/instructions.md +2 -2
- package/src/modules/bmm/workflows/4-implementation/correct-course/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/4-implementation/create-story/checklist.md +2 -2
- package/src/modules/bmm/workflows/4-implementation/create-story/instructions.xml +5 -5
- package/src/modules/bmm/workflows/4-implementation/create-story/template.md +3 -5
- package/src/modules/bmm/workflows/4-implementation/create-story/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/4-implementation/dev-story/checklist.md +2 -2
- package/src/modules/bmm/workflows/4-implementation/dev-story/instructions.xml +11 -8
- package/src/modules/bmm/workflows/4-implementation/dev-story/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/4-implementation/retrospective/instructions.md +3 -3
- package/src/modules/bmm/workflows/4-implementation/retrospective/workflow.yaml +3 -3
- package/src/modules/bmm/workflows/4-implementation/sprint-planning/instructions.md +15 -22
- package/src/modules/bmm/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +4 -5
- package/src/modules/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/4-implementation/sprint-status/instructions.md +90 -35
- package/src/modules/bmm/workflows/4-implementation/sprint-status/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/bmad-quick-flow/create-tech-spec/workflow.yaml +5 -5
- package/src/modules/bmm/workflows/bmad-quick-flow/quick-dev/workflow.yaml +7 -7
- package/src/modules/bmm/workflows/document-project/instructions.md +5 -5
- package/src/modules/bmm/workflows/document-project/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/document-project/workflows/deep-dive.yaml +5 -5
- package/src/modules/bmm/workflows/document-project/workflows/full-scan.yaml +5 -5
- package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-dataflow/instructions.md +1 -1
- package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-dataflow/workflow.yaml +6 -6
- package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-diagram/instructions.md +2 -2
- package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-diagram/workflow.yaml +6 -6
- package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-flowchart/instructions.md +2 -2
- package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-flowchart/workflow.yaml +6 -6
- package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-wireframe/instructions.md +1 -1
- package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-wireframe/workflow.yaml +6 -6
- package/src/modules/bmm/workflows/generate-project-context/steps/step-01-discover.md +2 -2
- package/src/modules/bmm/workflows/generate-project-context/steps/step-02-generate.md +3 -3
- package/src/modules/bmm/workflows/generate-project-context/steps/step-03-complete.md +2 -2
- package/src/modules/bmm/workflows/generate-project-context/workflow.md +5 -5
- package/src/modules/bmm/workflows/testarch/atdd/instructions.md +2 -2
- package/src/modules/bmm/workflows/testarch/atdd/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/testarch/automate/instructions.md +2 -2
- package/src/modules/bmm/workflows/testarch/automate/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/testarch/ci/instructions.md +1 -1
- package/src/modules/bmm/workflows/testarch/ci/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/testarch/framework/instructions.md +3 -3
- package/src/modules/bmm/workflows/testarch/framework/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/testarch/nfr-assess/instructions.md +1 -1
- package/src/modules/bmm/workflows/testarch/nfr-assess/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/testarch/test-design/instructions.md +3 -3
- package/src/modules/bmm/workflows/testarch/test-design/test-design-template.md +1 -1
- package/src/modules/bmm/workflows/testarch/test-design/workflow.yaml +10 -4
- package/src/modules/bmm/workflows/testarch/test-review/instructions.md +1 -1
- package/src/modules/bmm/workflows/testarch/test-review/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/testarch/trace/instructions.md +6 -6
- package/src/modules/bmm/workflows/testarch/trace/workflow.yaml +2 -2
- package/src/modules/bmm/workflows/workflow-status/init/instructions.md +1 -1
- package/src/modules/bmm/workflows/workflow-status/init/workflow.yaml +4 -4
- package/src/modules/bmm/workflows/workflow-status/instructions.md +3 -3
- package/src/modules/bmm/workflows/workflow-status/project-levels.yaml +1 -1
- package/src/modules/bmm/workflows/workflow-status/workflow.yaml +2 -2
- package/src/modules/cis/agents/brainstorming-coach.agent.yaml +4 -4
- package/src/modules/cis/agents/creative-problem-solver.agent.yaml +4 -4
- package/src/modules/cis/agents/design-thinking-coach.agent.yaml +4 -4
- package/src/modules/cis/agents/innovation-strategist.agent.yaml +4 -4
- package/src/modules/cis/agents/presentation-master.agent.yaml +3 -3
- package/src/modules/cis/agents/storyteller/storyteller-sidecar/stories-told.md +7 -0
- package/src/modules/cis/agents/storyteller/storyteller-sidecar/story-preferences.md +7 -0
- package/src/modules/cis/agents/{storyteller.agent.yaml → storyteller/storyteller.agent.yaml} +9 -4
- package/src/modules/cis/module.yaml +3 -8
- package/src/modules/cis/{README.md → readme.md} +1 -1
- package/src/modules/cis/workflows/README.md +1 -1
- package/src/modules/cis/workflows/design-thinking/instructions.md +2 -2
- package/src/modules/cis/workflows/design-thinking/workflow.yaml +7 -7
- package/src/modules/cis/workflows/innovation-strategy/instructions.md +2 -2
- package/src/modules/cis/workflows/innovation-strategy/workflow.yaml +7 -7
- package/src/modules/cis/workflows/problem-solving/instructions.md +2 -2
- package/src/modules/cis/workflows/problem-solving/workflow.yaml +7 -7
- package/src/modules/cis/workflows/storytelling/instructions.md +2 -2
- package/src/modules/cis/workflows/storytelling/workflow.yaml +7 -7
- package/src/utility/agent-components/activation-rules.txt +7 -0
- package/src/utility/agent-components/activation-steps.txt +13 -0
- package/src/utility/agent-components/agent-command-header.md +1 -0
- package/src/utility/{templates → agent-components}/agent.customize.template.yaml +0 -1
- 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 +1 -1
- package/test/test-agent-schema.js +2 -2
- package/tools/cli/README.md +1 -607
- package/tools/cli/commands/build.js +7 -7
- package/tools/cli/commands/install.js +9 -20
- package/tools/cli/commands/list.js +13 -1
- package/tools/cli/installers/lib/core/config-collector.js +243 -73
- package/tools/cli/installers/lib/core/custom-module-cache.js +36 -16
- package/tools/cli/installers/lib/core/dependency-resolver.js +2 -2
- package/tools/cli/installers/lib/core/detector.js +16 -16
- package/tools/cli/installers/lib/core/ide-config-manager.js +9 -7
- package/tools/cli/installers/lib/core/installer.js +595 -1006
- package/tools/cli/installers/lib/core/manifest-generator.js +43 -40
- package/tools/cli/installers/lib/core/manifest.js +23 -20
- package/tools/cli/installers/lib/custom/handler.js +16 -49
- package/tools/cli/installers/lib/ide/_base-ide.js +26 -33
- package/tools/cli/installers/lib/ide/antigravity.js +3 -3
- package/tools/cli/installers/lib/ide/claude-code.js +3 -3
- package/tools/cli/installers/lib/ide/codex.js +2 -2
- package/tools/cli/installers/lib/ide/gemini.js +6 -6
- package/tools/cli/installers/lib/ide/kiro-cli.js +2 -2
- package/tools/cli/installers/lib/ide/opencode.js +2 -2
- package/tools/cli/installers/lib/ide/roo.js +15 -5
- package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +2 -2
- package/tools/cli/installers/lib/ide/shared/module-injections.js +2 -2
- package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +2 -2
- package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +4 -4
- package/tools/cli/installers/lib/ide/templates/agent-command-template.md +1 -1
- package/tools/cli/installers/lib/ide/templates/gemini-agent-command.toml +3 -3
- package/tools/cli/installers/lib/ide/templates/gemini-task-command.toml +3 -3
- package/tools/cli/installers/lib/ide/templates/workflow-command-template.md +1 -1
- package/tools/cli/installers/lib/modules/manager.js +304 -313
- package/tools/cli/lib/activation-builder.js +8 -13
- package/tools/cli/lib/agent/compiler.js +68 -168
- package/tools/cli/lib/agent/installer.js +8 -128
- package/tools/cli/lib/agent-analyzer.js +2 -2
- package/tools/cli/lib/agent-party-generator.js +5 -17
- package/tools/cli/lib/config.js +2 -2
- package/tools/cli/lib/platform-codes.js +2 -2
- package/tools/cli/lib/ui.js +610 -551
- package/tools/cli/lib/xml-handler.js +3 -55
- package/tools/cli/lib/yaml-format.js +4 -6
- package/tools/cli/lib/yaml-xml-builder.js +14 -26
- package/tools/flattener/ignoreRules.js +1 -1
- package/tools/flattener/xml.js +1 -7
- package/tools/lib/xml-utils.js +13 -0
- package/tools/migrate-custom-module-paths.js +2 -2
- package/tools/validate-agent-schema.js +2 -2
- package/docs/v6-open-items.md +0 -17
- package/example-custom-content/README.md +0 -8
- package/example-custom-module/mwm/README.md +0 -9
- package/example-custom-module/mwm/agents/cbt-coach/cbt-coach-sidecar/cognitive-distortions.md +0 -47
- package/example-custom-module/mwm/agents/cbt-coach/cbt-coach-sidecar/thought-records.md +0 -17
- package/example-custom-module/mwm/agents/cbt-coach/cbt-coach.agent.yaml +0 -151
- package/example-custom-module/mwm/agents/crisis-navigator.agent.yaml +0 -138
- package/example-custom-module/mwm/module.yaml +0 -28
- package/example-custom-module/mwm/workflows/cbt-thought-record/README.md +0 -31
- package/example-custom-module/mwm/workflows/cbt-thought-record/workflow.md +0 -45
- package/example-custom-module/mwm/workflows/crisis-support/README.md +0 -31
- package/example-custom-module/mwm/workflows/crisis-support/workflow.md +0 -45
- package/src/core/agents/bmad-web-orchestrator.agent.xml +0 -113
- package/src/modules/bmb/_module-installer/installer.js +0 -76
- package/src/modules/bmb/docs/agents/module-agent-architecture.md +0 -367
- package/src/modules/bmb/workflows/create-agent/steps/step-08-setup.md +0 -179
- package/src/modules/bmb/workflows/create-agent/steps/step-09-customize.md +0 -197
- package/src/modules/bmb/workflows/create-agent/steps/step-10-build-tools.md +0 -180
- package/src/modules/bmb/workflows/create-agent/templates/agent_commands.md +0 -21
- package/src/modules/bmb/workflows/create-agent/templates/agent_persona.md +0 -25
- package/src/modules/bmb/workflows/create-agent/templates/agent_purpose_and_type.md +0 -23
- package/src/modules/bmm/tasks/daily-standup.xml +0 -85
- package/src/modules/cis/agents/README.md +0 -104
- package/src/utility/models/action-command-header.md +0 -0
- package/src/utility/models/agent-activation-ide.xml +0 -51
- package/src/utility/models/agent-activation-web.xml +0 -50
- 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 -7
- 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 -6
- package/src/utility/models/fragments/handler-multi.xml +0 -14
- 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/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 -1764
- package/tools/cli/installers/lib/core/post-install-sidecar-replacement.js +0 -79
- 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/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/agents/toolsmith/toolsmith-sidecar/instructions.md +0 -0
- /package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/agents/toolsmith/toolsmith-sidecar/knowledge/bundlers.md +0 -0
- /package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/agents/toolsmith/toolsmith-sidecar/knowledge/deploy.md +0 -0
- /package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/agents/toolsmith/toolsmith-sidecar/knowledge/docs.md +0 -0
- /package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/agents/toolsmith/toolsmith-sidecar/knowledge/installers.md +0 -0
- /package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/agents/toolsmith/toolsmith-sidecar/knowledge/modules.md +0 -0
- /package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/agents/toolsmith/toolsmith-sidecar/knowledge/tests.md +0 -0
- /package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/agents/toolsmith/toolsmith-sidecar/memories.md +0 -0
- /package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/quiz-master/templates/csv-headers.template +0 -0
- /package/{example-custom-content → docs/sample-custom-modules/sample-unitary-module}/workflows/wassup/workflow.md +0 -0
- /package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/agents/wellness-companion/wellness-companion-sidecar/insights.md +0 -0
- /package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/agents/wellness-companion/wellness-companion-sidecar/instructions.md +0 -0
- /package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/agents/wellness-companion/wellness-companion-sidecar/memories.md +0 -0
- /package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/agents/wellness-companion/wellness-companion-sidecar/patterns.md +0 -0
- /package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/workflows/daily-checkin/README.md +0 -0
- /package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/workflows/daily-checkin/workflow.md +0 -0
- /package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/workflows/guided-meditation/README.md +0 -0
- /package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/workflows/guided-meditation/workflow.md +0 -0
- /package/{example-custom-module/mwm → docs/sample-custom-modules/sample-wellness-module}/workflows/wellness-journal/README.md +0 -0
- /package/src/modules/bmgd/workflows/4-production/code-review/{backlog_template.md → backlog-template.md} +0 -0
- /package/src/modules/bmm/workflows/1-analysis/{product-brief → create-product-brief}/product-brief.template.md +0 -0
- /package/src/modules/bmm/workflows/3-solutioning/{implementation-readiness → check-implementation-readiness}/templates/readiness-report-template.md +0 -0
- /package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/architecture-decision-template.md +0 -0
- /package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/data/domain-complexity.csv +0 -0
- /package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/data/project-types.csv +0 -0
- /package/src/modules/bmm/workflows/3-solutioning/{architecture → create-architecture}/steps/step-01b-continue.md +0 -0
- /package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/_shared/excalidraw-library.json +0 -0
- /package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/_shared/excalidraw-templates.yaml +0 -0
- /package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-dataflow/checklist.md +0 -0
- /package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-diagram/checklist.md +0 -0
- /package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-flowchart/checklist.md +0 -0
- /package/src/modules/bmm/workflows/{diagrams → excalidraw-diagrams}/create-wireframe/checklist.md +0 -0
- /package/src/utility/{models/fragments/handler-data.xml → agent-components/handler-data.txt} +0 -0
package/tools/cli/lib/ui.js
CHANGED
|
@@ -1,44 +1,24 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File: tools/cli/lib/ui.js
|
|
3
|
-
*
|
|
4
|
-
* BMAD Method - Business Model Agile Development Method
|
|
5
|
-
* Repository: https://github.com/paulpreibisch/BMAD-METHOD
|
|
6
|
-
*
|
|
7
|
-
* Copyright (c) 2025 Paul Preibisch
|
|
8
|
-
* Licensed under the Apache License, Version 2.0
|
|
9
|
-
*
|
|
10
|
-
* ---
|
|
11
|
-
*
|
|
12
|
-
* @fileoverview Interactive installation prompts and user input collection for BMAD CLI
|
|
13
|
-
* @context Guides users through installation configuration including core settings, modules, IDEs, and optional AgentVibes TTS
|
|
14
|
-
* @architecture Facade pattern - presents unified installation flow, delegates to Detector/ConfigCollector/IdeManager for specifics
|
|
15
|
-
* @dependencies inquirer (prompts), chalk (formatting), detector.js (existing installation detection)
|
|
16
|
-
* @entrypoints Called by install.js command via ui.promptInstall(), returns complete configuration object
|
|
17
|
-
* @patterns Progressive disclosure (prompts in order), early IDE selection (Windows compat), AgentVibes auto-detection
|
|
18
|
-
* @related installer.js (consumes config), AgentVibes#34 (TTS integration), promptAgentVibes()
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
1
|
const chalk = require('chalk');
|
|
22
2
|
const inquirer = require('inquirer');
|
|
23
3
|
const path = require('node:path');
|
|
24
4
|
const os = require('node:os');
|
|
25
5
|
const fs = require('fs-extra');
|
|
26
6
|
const { CLIUtils } = require('./cli-utils');
|
|
7
|
+
const { CustomHandler } = require('../installers/lib/custom/handler');
|
|
27
8
|
|
|
28
9
|
/**
|
|
29
10
|
* UI utilities for the installer
|
|
30
11
|
*/
|
|
31
12
|
class UI {
|
|
32
|
-
constructor() {}
|
|
33
|
-
|
|
34
13
|
/**
|
|
35
14
|
* Prompt for installation configuration
|
|
36
15
|
* @returns {Object} Installation configuration
|
|
37
16
|
*/
|
|
38
17
|
async promptInstall() {
|
|
39
18
|
CLIUtils.displayLogo();
|
|
40
|
-
|
|
41
|
-
|
|
19
|
+
|
|
20
|
+
// Display changelog link
|
|
21
|
+
console.log(chalk.cyan('\n📋 Read the latest updates: https://github.com/bmad-code-org/BMAD-METHOD/blob/main/CHANGELOG.md\n'));
|
|
42
22
|
|
|
43
23
|
const confirmedDirectory = await this.getConfirmedDirectory();
|
|
44
24
|
|
|
@@ -52,21 +32,138 @@ class UI {
|
|
|
52
32
|
await installer.handleLegacyV4Migration(confirmedDirectory, legacyV4);
|
|
53
33
|
}
|
|
54
34
|
|
|
55
|
-
// Check
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
35
|
+
// Check for legacy folders and prompt for rename before showing any menus
|
|
36
|
+
let hasLegacyCfg = false;
|
|
37
|
+
let hasLegacyBmadFolder = false;
|
|
38
|
+
let bmadDir = null;
|
|
39
|
+
let legacyBmadPath = null;
|
|
40
|
+
|
|
41
|
+
// First check for legacy .bmad folder (instead of _bmad)
|
|
42
|
+
// Only check if directory exists
|
|
43
|
+
if (await fs.pathExists(confirmedDirectory)) {
|
|
44
|
+
const entries = await fs.readdir(confirmedDirectory, { withFileTypes: true });
|
|
45
|
+
for (const entry of entries) {
|
|
46
|
+
if (entry.isDirectory() && entry.name === '.bmad') {
|
|
47
|
+
hasLegacyBmadFolder = true;
|
|
48
|
+
legacyBmadPath = path.join(confirmedDirectory, '.bmad');
|
|
49
|
+
bmadDir = legacyBmadPath;
|
|
50
|
+
|
|
51
|
+
// Check if it has _cfg folder
|
|
52
|
+
const cfgPath = path.join(legacyBmadPath, '_cfg');
|
|
53
|
+
if (await fs.pathExists(cfgPath)) {
|
|
54
|
+
hasLegacyCfg = true;
|
|
55
|
+
}
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// If no .bmad found, check for current installations
|
|
62
|
+
if (!hasLegacyBmadFolder) {
|
|
63
|
+
const bmadResult = await installer.findBmadDir(confirmedDirectory);
|
|
64
|
+
bmadDir = bmadResult.bmadDir;
|
|
65
|
+
hasLegacyCfg = bmadResult.hasLegacyCfg;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (hasLegacyBmadFolder || hasLegacyCfg) {
|
|
69
|
+
console.log(chalk.yellow('\n⚠️ Legacy folder structure detected'));
|
|
70
|
+
|
|
71
|
+
let message = 'The following folders need to be renamed:\n';
|
|
72
|
+
if (hasLegacyBmadFolder) {
|
|
73
|
+
message += chalk.dim(` • ".bmad" → "_bmad"\n`);
|
|
74
|
+
}
|
|
75
|
+
if (hasLegacyCfg) {
|
|
76
|
+
message += chalk.dim(` • "_cfg" → "_config"\n`);
|
|
77
|
+
}
|
|
78
|
+
console.log(message);
|
|
79
|
+
|
|
80
|
+
const { shouldRename } = await inquirer.prompt([
|
|
81
|
+
{
|
|
82
|
+
type: 'confirm',
|
|
83
|
+
name: 'shouldRename',
|
|
84
|
+
message: 'Would you like the installer to rename these folders for you?',
|
|
85
|
+
default: true,
|
|
86
|
+
},
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
if (!shouldRename) {
|
|
90
|
+
console.log(chalk.red('\n❌ Installation cancelled'));
|
|
91
|
+
console.log(chalk.dim('You must manually rename the folders before proceeding:'));
|
|
92
|
+
if (hasLegacyBmadFolder) {
|
|
93
|
+
console.log(chalk.dim(` • Rename ".bmad" to "_bmad"`));
|
|
94
|
+
}
|
|
95
|
+
if (hasLegacyCfg) {
|
|
96
|
+
console.log(chalk.dim(` • Rename "_cfg" to "_config"`));
|
|
97
|
+
}
|
|
98
|
+
process.exit(0);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Perform the renames
|
|
103
|
+
const ora = require('ora');
|
|
104
|
+
const spinner = ora('Updating folder structure...').start();
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
// First rename .bmad to _bmad if needed
|
|
108
|
+
if (hasLegacyBmadFolder) {
|
|
109
|
+
const newBmadPath = path.join(confirmedDirectory, '_bmad');
|
|
110
|
+
await fs.move(legacyBmadPath, newBmadPath);
|
|
111
|
+
bmadDir = newBmadPath;
|
|
112
|
+
spinner.succeed('Renamed ".bmad" to "_bmad"');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Then rename _cfg to _config if needed
|
|
116
|
+
if (hasLegacyCfg) {
|
|
117
|
+
spinner.start('Renaming configuration folder...');
|
|
118
|
+
const oldCfgPath = path.join(bmadDir, '_cfg');
|
|
119
|
+
const newCfgPath = path.join(bmadDir, '_config');
|
|
120
|
+
await fs.move(oldCfgPath, newCfgPath);
|
|
121
|
+
spinner.succeed('Renamed "_cfg" to "_config"');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
spinner.succeed('Folder structure updated successfully');
|
|
125
|
+
} catch (error) {
|
|
126
|
+
spinner.fail('Failed to update folder structure');
|
|
127
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Check if there's an existing BMAD installation (after any folder renames)
|
|
60
133
|
const hasExistingInstall = await fs.pathExists(bmadDir);
|
|
61
134
|
|
|
62
|
-
//
|
|
135
|
+
// Collect IDE tool selection early - we need this to know if we should ask about TTS
|
|
136
|
+
let toolSelection;
|
|
137
|
+
let agentVibesConfig = { enabled: false, alreadyInstalled: false };
|
|
138
|
+
let claudeCodeSelected = false;
|
|
139
|
+
|
|
140
|
+
if (!hasExistingInstall) {
|
|
141
|
+
// For new installations, collect IDE selection first
|
|
142
|
+
// We don't have modules yet, so pass empty array
|
|
143
|
+
toolSelection = await this.promptToolSelection(confirmedDirectory, []);
|
|
144
|
+
|
|
145
|
+
// Check if Claude Code was selected
|
|
146
|
+
claudeCodeSelected = toolSelection.ides && toolSelection.ides.includes('claude-code');
|
|
147
|
+
|
|
148
|
+
// If Claude Code was selected, ask about TTS
|
|
149
|
+
if (claudeCodeSelected) {
|
|
150
|
+
const { enableTts } = await inquirer.prompt([
|
|
151
|
+
{
|
|
152
|
+
type: 'confirm',
|
|
153
|
+
name: 'enableTts',
|
|
154
|
+
message: 'Claude Code supports TTS (Text-to-Speech). Would you like to enable it?',
|
|
155
|
+
default: false,
|
|
156
|
+
},
|
|
157
|
+
]);
|
|
158
|
+
|
|
159
|
+
if (enableTts) {
|
|
160
|
+
agentVibesConfig = { enabled: true, alreadyInstalled: false };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
63
165
|
let customContentConfig = { hasCustomContent: false };
|
|
64
|
-
if (hasExistingInstall) {
|
|
65
|
-
// Existing installation - prompt to add/update custom content
|
|
66
|
-
customContentConfig = await this.promptCustomContentForExisting();
|
|
67
|
-
} else {
|
|
68
|
-
// New installation - we'll prompt after creating the directory structure
|
|
69
|
-
// For now, set a flag to indicate we should ask later
|
|
166
|
+
if (!hasExistingInstall) {
|
|
70
167
|
customContentConfig._shouldAsk = true;
|
|
71
168
|
}
|
|
72
169
|
|
|
@@ -75,19 +172,33 @@ class UI {
|
|
|
75
172
|
|
|
76
173
|
// Only show action menu if there's an existing installation
|
|
77
174
|
if (hasExistingInstall) {
|
|
175
|
+
// Get version information
|
|
176
|
+
const { existingInstall } = await this.getExistingInstallation(confirmedDirectory);
|
|
177
|
+
const packageJsonPath = path.join(__dirname, '../../../package.json');
|
|
178
|
+
const currentVersion = require(packageJsonPath).version;
|
|
179
|
+
const installedVersion = existingInstall.version || 'unknown';
|
|
180
|
+
|
|
181
|
+
// Build menu choices dynamically
|
|
182
|
+
const choices = [];
|
|
183
|
+
|
|
184
|
+
// Always show Quick Update first (allows refreshing installation even on same version)
|
|
185
|
+
if (installedVersion !== 'unknown') {
|
|
186
|
+
choices.push({
|
|
187
|
+
name: `Quick Update (v${installedVersion} → v${currentVersion})`,
|
|
188
|
+
value: 'quick-update',
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Common actions
|
|
193
|
+
choices.push({ name: 'Modify BMAD Installation', value: 'update' });
|
|
194
|
+
|
|
78
195
|
const promptResult = await inquirer.prompt([
|
|
79
196
|
{
|
|
80
197
|
type: 'list',
|
|
81
198
|
name: 'actionType',
|
|
82
199
|
message: 'What would you like to do?',
|
|
83
|
-
choices:
|
|
84
|
-
|
|
85
|
-
{ name: 'Modify BMAD Installation (Confirm or change each setting)', value: 'update' },
|
|
86
|
-
{ name: 'Remove BMad Folder and Reinstall (Full clean install - BMad Customization Will Be Lost)', value: 'reinstall' },
|
|
87
|
-
{ name: 'Compile Agents (Quick rebuild of all agent .md files)', value: 'compile' },
|
|
88
|
-
{ name: 'Cancel', value: 'cancel' },
|
|
89
|
-
],
|
|
90
|
-
default: 'quick-update',
|
|
200
|
+
choices: choices,
|
|
201
|
+
default: choices[0].value, // Use the first option as default
|
|
91
202
|
},
|
|
92
203
|
]);
|
|
93
204
|
|
|
@@ -104,165 +215,141 @@ class UI {
|
|
|
104
215
|
};
|
|
105
216
|
}
|
|
106
217
|
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
218
|
+
// If actionType === 'update', handle it with the new flow
|
|
219
|
+
// Return early with modify configuration
|
|
220
|
+
if (actionType === 'update') {
|
|
221
|
+
// Get existing installation info
|
|
222
|
+
const { installedModuleIds } = await this.getExistingInstallation(confirmedDirectory);
|
|
223
|
+
|
|
224
|
+
console.log(chalk.dim(` Found existing modules: ${[...installedModuleIds].join(', ')}`));
|
|
225
|
+
const { changeModuleSelection } = await inquirer.prompt([
|
|
226
|
+
{
|
|
227
|
+
type: 'confirm',
|
|
228
|
+
name: 'changeModuleSelection',
|
|
229
|
+
message: 'Modify official module selection (BMad Method, BMad Builder, Creative Innovation Suite)?',
|
|
230
|
+
default: false,
|
|
231
|
+
},
|
|
232
|
+
]);
|
|
233
|
+
|
|
234
|
+
let selectedModules = [];
|
|
235
|
+
if (changeModuleSelection) {
|
|
236
|
+
// Show module selection with existing modules pre-selected
|
|
237
|
+
const moduleChoices = await this.getModuleChoices(new Set(installedModuleIds), { hasCustomContent: false });
|
|
238
|
+
selectedModules = await this.selectModules(moduleChoices, [...installedModuleIds]);
|
|
239
|
+
} else {
|
|
240
|
+
selectedModules = [...installedModuleIds];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// After module selection, ask about custom modules
|
|
244
|
+
const customModuleResult = await this.handleCustomModulesInModifyFlow(confirmedDirectory, selectedModules);
|
|
245
|
+
|
|
246
|
+
// Merge any selected custom modules
|
|
247
|
+
if (customModuleResult.selectedCustomModules.length > 0) {
|
|
248
|
+
selectedModules.push(...customModuleResult.selectedCustomModules);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Get tool selection
|
|
252
|
+
const toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules);
|
|
253
|
+
|
|
254
|
+
// TTS configuration - ask right after tool selection (matches new install flow)
|
|
255
|
+
const hasClaudeCode = toolSelection.ides && toolSelection.ides.includes('claude-code');
|
|
256
|
+
let enableTts = false;
|
|
257
|
+
|
|
258
|
+
if (hasClaudeCode) {
|
|
259
|
+
const { enableTts: enable } = await inquirer.prompt([
|
|
260
|
+
{
|
|
261
|
+
type: 'confirm',
|
|
262
|
+
name: 'enableTts',
|
|
263
|
+
message: 'Claude Code supports TTS (Text-to-Speech). Would you like to enable it?',
|
|
264
|
+
default: false,
|
|
265
|
+
},
|
|
266
|
+
]);
|
|
267
|
+
enableTts = enable;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Core config with existing defaults (ask after TTS)
|
|
271
|
+
const coreConfig = await this.collectCoreConfig(confirmedDirectory);
|
|
114
272
|
|
|
115
|
-
// Handle cancel
|
|
116
|
-
if (actionType === 'cancel') {
|
|
117
273
|
return {
|
|
118
|
-
actionType: '
|
|
274
|
+
actionType: 'update',
|
|
119
275
|
directory: confirmedDirectory,
|
|
276
|
+
installCore: true,
|
|
277
|
+
modules: selectedModules,
|
|
278
|
+
ides: toolSelection.ides,
|
|
279
|
+
skipIde: toolSelection.skipIde,
|
|
280
|
+
coreConfig: coreConfig,
|
|
281
|
+
customContent: customModuleResult.customContentConfig,
|
|
282
|
+
enableAgentVibes: enableTts,
|
|
283
|
+
agentVibesInstalled: false,
|
|
120
284
|
};
|
|
121
285
|
}
|
|
122
|
-
|
|
123
|
-
// Handle reinstall - DON'T return early, let it flow through configuration collection
|
|
124
|
-
// The installer will handle deletion when it sees actionType === 'reinstall'
|
|
125
|
-
// For now, just note that we're in reinstall mode and continue below
|
|
126
|
-
|
|
127
|
-
// If actionType === 'update' or 'reinstall', continue with normal flow below
|
|
128
286
|
}
|
|
129
287
|
|
|
288
|
+
// This section is only for new installations (update returns early above)
|
|
130
289
|
const { installedModuleIds } = await this.getExistingInstallation(confirmedDirectory);
|
|
131
|
-
const coreConfig = await this.collectCoreConfig(confirmedDirectory);
|
|
132
290
|
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
await fs.ensureDir(path.join(bmadDir, '_cfg'));
|
|
143
|
-
await fs.ensureDir(path.join(bmadDir, '_cfg', 'custom'));
|
|
144
|
-
|
|
145
|
-
// Now prompt for custom content
|
|
146
|
-
customContentConfig = await this.promptCustomContentLocation();
|
|
147
|
-
|
|
148
|
-
// If custom content found, cache it
|
|
149
|
-
if (customContentConfig.hasCustomContent) {
|
|
150
|
-
const { CustomModuleCache } = require('../installers/lib/core/custom-module-cache');
|
|
151
|
-
const cache = new CustomModuleCache(bmadDir);
|
|
152
|
-
|
|
153
|
-
const { CustomHandler } = require('../installers/lib/custom/handler');
|
|
154
|
-
const customHandler = new CustomHandler();
|
|
155
|
-
const customFiles = await customHandler.findCustomContent(customContentConfig.customPath);
|
|
156
|
-
|
|
157
|
-
for (const customFile of customFiles) {
|
|
158
|
-
const customInfo = await customHandler.getCustomInfo(customFile);
|
|
159
|
-
if (customInfo && customInfo.id) {
|
|
160
|
-
// Cache the module source
|
|
161
|
-
await cache.cacheModule(customInfo.id, customInfo.path, {
|
|
162
|
-
name: customInfo.name,
|
|
163
|
-
type: 'custom',
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
console.log(chalk.dim(` Cached ${customInfo.name} to _cfg/custom/${customInfo.id}`));
|
|
167
|
-
}
|
|
168
|
-
}
|
|
291
|
+
// Ask about official modules for new installations
|
|
292
|
+
const { wantsOfficialModules } = await inquirer.prompt([
|
|
293
|
+
{
|
|
294
|
+
type: 'confirm',
|
|
295
|
+
name: 'wantsOfficialModules',
|
|
296
|
+
message: 'Will you be installing any official BMad modules (BMad Method, BMad Builder, Creative Innovation Suite)?',
|
|
297
|
+
default: true,
|
|
298
|
+
},
|
|
299
|
+
]);
|
|
169
300
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
customContentConfig.cachedModules.push({
|
|
176
|
-
id: customInfo.id,
|
|
177
|
-
cachePath: path.join(bmadDir, '_cfg', 'custom', customInfo.id),
|
|
178
|
-
// Store relative path from cache for the manifest
|
|
179
|
-
relativePath: path.join('_cfg', 'custom', customInfo.id),
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
}
|
|
301
|
+
let selectedOfficialModules = [];
|
|
302
|
+
if (wantsOfficialModules) {
|
|
303
|
+
const moduleChoices = await this.getModuleChoices(installedModuleIds, { hasCustomContent: false });
|
|
304
|
+
selectedOfficialModules = await this.selectModules(moduleChoices);
|
|
305
|
+
}
|
|
183
306
|
|
|
184
|
-
|
|
185
|
-
|
|
307
|
+
// Ask about custom content
|
|
308
|
+
const { wantsCustomContent } = await inquirer.prompt([
|
|
309
|
+
{
|
|
310
|
+
type: 'confirm',
|
|
311
|
+
name: 'wantsCustomContent',
|
|
312
|
+
message: 'Would you like to install a local custom module (this includes custom agents and workflows also)?',
|
|
313
|
+
default: false,
|
|
314
|
+
},
|
|
315
|
+
]);
|
|
186
316
|
|
|
187
|
-
|
|
188
|
-
|
|
317
|
+
if (wantsCustomContent) {
|
|
318
|
+
customContentConfig = await this.promptCustomContentSource();
|
|
189
319
|
}
|
|
190
320
|
|
|
191
|
-
//
|
|
192
|
-
|
|
193
|
-
if (actionType === 'update' || actionType === 'reinstall') {
|
|
194
|
-
// Keep all existing installed modules during update/reinstall
|
|
195
|
-
selectedModules = [...installedModuleIds];
|
|
196
|
-
console.log(chalk.cyan('\n📦 Keeping existing modules: ') + selectedModules.join(', '));
|
|
197
|
-
} else {
|
|
198
|
-
// Only show module selection for new installs
|
|
199
|
-
const moduleChoices = await this.getModuleChoices(installedModuleIds, customContentConfig);
|
|
200
|
-
selectedModules = await this.selectModules(moduleChoices);
|
|
201
|
-
|
|
202
|
-
// Check which custom content items were selected
|
|
203
|
-
const selectedCustomContent = selectedModules.filter((mod) => mod.startsWith('__CUSTOM_CONTENT__'));
|
|
204
|
-
|
|
205
|
-
// For cached modules (new installs), check if any cached modules were selected
|
|
206
|
-
let selectedCachedModules = [];
|
|
207
|
-
if (customContentConfig.cachedModules) {
|
|
208
|
-
selectedCachedModules = selectedModules.filter(
|
|
209
|
-
(mod) => !mod.startsWith('__CUSTOM_CONTENT__') && customContentConfig.cachedModules.some((cm) => cm.id === mod),
|
|
210
|
-
);
|
|
211
|
-
}
|
|
321
|
+
// Store the selected modules for later
|
|
322
|
+
customContentConfig._selectedOfficialModules = selectedOfficialModules;
|
|
212
323
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
// Handle directory-based custom content (existing installs)
|
|
217
|
-
if (selectedCustomContent.length > 0) {
|
|
218
|
-
customContentConfig.selectedFiles = selectedCustomContent.map((mod) => mod.replace('__CUSTOM_CONTENT__', ''));
|
|
219
|
-
// Convert custom content to module IDs for installation
|
|
220
|
-
const customContentModuleIds = [];
|
|
221
|
-
const { CustomHandler } = require('../installers/lib/custom/handler');
|
|
222
|
-
const customHandler = new CustomHandler();
|
|
223
|
-
for (const customFile of customContentConfig.selectedFiles) {
|
|
224
|
-
// Get the module info to extract the ID
|
|
225
|
-
const customInfo = await customHandler.getCustomInfo(customFile);
|
|
226
|
-
if (customInfo) {
|
|
227
|
-
customContentModuleIds.push(customInfo.id);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
// Filter out custom content markers and add module IDs
|
|
231
|
-
selectedModules = [...selectedModules.filter((mod) => !mod.startsWith('__CUSTOM_CONTENT__')), ...customContentModuleIds];
|
|
232
|
-
}
|
|
324
|
+
// Build the final list of selected modules
|
|
325
|
+
let selectedModules = customContentConfig._selectedOfficialModules || [];
|
|
233
326
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
// No need to filter since they're already proper module IDs
|
|
238
|
-
}
|
|
239
|
-
} else if (customContentConfig.hasCustomContent) {
|
|
240
|
-
// User provided custom content but didn't select any
|
|
241
|
-
customContentConfig.selected = false;
|
|
242
|
-
customContentConfig.selectedFiles = [];
|
|
243
|
-
customContentConfig.selectedCachedModules = [];
|
|
244
|
-
}
|
|
327
|
+
// Add custom content modules if any were selected
|
|
328
|
+
if (customContentConfig && customContentConfig.selectedModuleIds) {
|
|
329
|
+
selectedModules = [...selectedModules, ...customContentConfig.selectedModuleIds];
|
|
245
330
|
}
|
|
246
331
|
|
|
247
|
-
//
|
|
248
|
-
|
|
332
|
+
// Remove core if it's in the list (it's always installed)
|
|
333
|
+
selectedModules = selectedModules.filter((m) => m !== 'core');
|
|
249
334
|
|
|
250
|
-
//
|
|
251
|
-
|
|
252
|
-
|
|
335
|
+
// Tool selection (already done for new installs at the beginning)
|
|
336
|
+
if (!toolSelection) {
|
|
337
|
+
toolSelection = await this.promptToolSelection(confirmedDirectory, selectedModules);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Collect configurations for new installations
|
|
341
|
+
const coreConfig = await this.collectCoreConfig(confirmedDirectory);
|
|
253
342
|
|
|
254
|
-
//
|
|
343
|
+
// TTS already handled at the beginning for new installs
|
|
255
344
|
|
|
256
345
|
return {
|
|
257
|
-
actionType:
|
|
346
|
+
actionType: 'install',
|
|
258
347
|
directory: confirmedDirectory,
|
|
259
|
-
installCore: true,
|
|
348
|
+
installCore: true,
|
|
260
349
|
modules: selectedModules,
|
|
261
|
-
// IDE selection collected after config, will be configured later
|
|
262
350
|
ides: toolSelection.ides,
|
|
263
351
|
skipIde: toolSelection.skipIde,
|
|
264
|
-
coreConfig: coreConfig,
|
|
265
|
-
// Custom content configuration
|
|
352
|
+
coreConfig: coreConfig,
|
|
266
353
|
customContent: customContentConfig,
|
|
267
354
|
enableAgentVibes: agentVibesConfig.enabled,
|
|
268
355
|
agentVibesInstalled: agentVibesConfig.alreadyInstalled,
|
|
@@ -281,7 +368,8 @@ class UI {
|
|
|
281
368
|
const { Installer } = require('../installers/lib/core/installer');
|
|
282
369
|
const detector = new Detector();
|
|
283
370
|
const installer = new Installer();
|
|
284
|
-
const
|
|
371
|
+
const bmadResult = await installer.findBmadDir(projectDir || process.cwd());
|
|
372
|
+
const bmadDir = bmadResult.bmadDir;
|
|
285
373
|
const existingInstall = await detector.detect(bmadDir);
|
|
286
374
|
const configuredIdes = existingInstall.ides || [];
|
|
287
375
|
|
|
@@ -351,8 +439,6 @@ class UI {
|
|
|
351
439
|
}
|
|
352
440
|
}
|
|
353
441
|
|
|
354
|
-
CLIUtils.displaySection('Tool Integration', 'Select AI coding assistants and IDEs to configure');
|
|
355
|
-
|
|
356
442
|
let answers;
|
|
357
443
|
let userConfirmedNoTools = false;
|
|
358
444
|
|
|
@@ -364,7 +450,7 @@ class UI {
|
|
|
364
450
|
name: 'ides',
|
|
365
451
|
message: 'Select tools to configure:',
|
|
366
452
|
choices: ideChoices,
|
|
367
|
-
pageSize:
|
|
453
|
+
pageSize: 30,
|
|
368
454
|
},
|
|
369
455
|
]);
|
|
370
456
|
|
|
@@ -390,9 +476,8 @@ class UI {
|
|
|
390
476
|
]);
|
|
391
477
|
|
|
392
478
|
if (goBack) {
|
|
393
|
-
// Re-display
|
|
479
|
+
// Re-display a message before looping back
|
|
394
480
|
console.log();
|
|
395
|
-
CLIUtils.displaySection('Tool Integration', 'Select AI coding assistants and IDEs to configure');
|
|
396
481
|
} else {
|
|
397
482
|
// User explicitly chose to proceed without tools
|
|
398
483
|
userConfirmedNoTools = true;
|
|
@@ -482,69 +567,33 @@ class UI {
|
|
|
482
567
|
* @param {Object} result - Installation result
|
|
483
568
|
*/
|
|
484
569
|
showInstallSummary(result) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
const summary = [
|
|
488
|
-
`📁 Installation Path: ${result.path}`,
|
|
489
|
-
`📦 Modules Installed: ${result.modules?.length > 0 ? result.modules.join(', ') : 'core only'}`,
|
|
490
|
-
`🔧 Tools Configured: ${result.ides?.length > 0 ? result.ides.join(', ') : 'none'}`,
|
|
491
|
-
];
|
|
570
|
+
// Clean, simple completion message
|
|
571
|
+
console.log('\n' + chalk.green.bold('✨ BMAD is ready to use!'));
|
|
492
572
|
|
|
493
|
-
//
|
|
573
|
+
// Show installation summary in a simple format
|
|
574
|
+
console.log(chalk.dim(`Installed to: ${result.path}`));
|
|
575
|
+
if (result.modules && result.modules.length > 0) {
|
|
576
|
+
console.log(chalk.dim(`Modules: ${result.modules.join(', ')}`));
|
|
577
|
+
}
|
|
494
578
|
if (result.agentVibesEnabled) {
|
|
495
|
-
|
|
579
|
+
console.log(chalk.dim(`TTS: Enabled`));
|
|
496
580
|
}
|
|
497
581
|
|
|
498
|
-
|
|
499
|
-
borderColor: 'green',
|
|
500
|
-
borderStyle: 'round',
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
// Display TTS injection details if present
|
|
582
|
+
// TTS injection info (simplified)
|
|
504
583
|
if (result.ttsInjectedFiles && result.ttsInjectedFiles.length > 0) {
|
|
505
|
-
console.log(
|
|
506
|
-
console.log(chalk.
|
|
507
|
-
console.log(chalk.cyan.bold('═══════════════════════════════════════════════════\n'));
|
|
508
|
-
|
|
509
|
-
// Explain what TTS injection is
|
|
510
|
-
console.log(chalk.white.bold('What is TTS Injection?\n'));
|
|
511
|
-
console.log(chalk.dim(' TTS (Text-to-Speech) injection adds voice instructions to BMAD agents,'));
|
|
512
|
-
console.log(chalk.dim(' enabling them to speak their responses aloud using AgentVibes.\n'));
|
|
513
|
-
console.log(chalk.dim(' Example: When you activate the PM agent, it will greet you with'));
|
|
514
|
-
console.log(chalk.dim(' spoken audio like "Hey! I\'m your Project Manager. How can I help?"\n'));
|
|
515
|
-
|
|
516
|
-
console.log(chalk.green(`✅ TTS injection applied to ${result.ttsInjectedFiles.length} file(s):\n`));
|
|
517
|
-
|
|
518
|
-
// Group by type
|
|
519
|
-
const partyModeFiles = result.ttsInjectedFiles.filter((f) => f.type === 'party-mode');
|
|
520
|
-
const agentTTSFiles = result.ttsInjectedFiles.filter((f) => f.type === 'agent-tts');
|
|
521
|
-
|
|
522
|
-
if (partyModeFiles.length > 0) {
|
|
523
|
-
console.log(chalk.yellow(' Party Mode (multi-agent conversations):'));
|
|
524
|
-
for (const file of partyModeFiles) {
|
|
525
|
-
console.log(chalk.dim(` • ${file.path}`));
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
if (agentTTSFiles.length > 0) {
|
|
530
|
-
console.log(chalk.yellow(' Agent TTS (individual agent voices):'));
|
|
531
|
-
for (const file of agentTTSFiles) {
|
|
532
|
-
console.log(chalk.dim(` • ${file.path}`));
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// Show backup info and restore command
|
|
537
|
-
console.log('\n' + chalk.white.bold('Backups & Recovery:\n'));
|
|
538
|
-
console.log(chalk.dim(' Pre-injection backups are stored in:'));
|
|
539
|
-
console.log(chalk.cyan(' ~/.bmad-tts-backups/\n'));
|
|
540
|
-
console.log(chalk.dim(' To restore original files (removes TTS instructions):'));
|
|
541
|
-
console.log(chalk.cyan(` bmad-tts-injector.sh --restore ${result.path}\n`));
|
|
542
|
-
|
|
543
|
-
console.log(chalk.cyan('💡 BMAD agents will now speak when activated!'));
|
|
544
|
-
console.log(chalk.dim(' Ensure AgentVibes is installed: https://agentvibes.org'));
|
|
584
|
+
console.log(chalk.dim(`\n💡 TTS enabled for ${result.ttsInjectedFiles.length} agent(s)`));
|
|
585
|
+
console.log(chalk.dim(' Agents will now speak when using AgentVibes'));
|
|
545
586
|
}
|
|
546
587
|
|
|
547
|
-
console.log(
|
|
588
|
+
console.log(chalk.yellow('\nThank you for helping test the early release version of the new BMad Core and BMad Method!'));
|
|
589
|
+
console.log(chalk.cyan('Stable Beta coming soon - please read the full README.md and linked documentation to get started!'));
|
|
590
|
+
|
|
591
|
+
// Add changelog link at the end
|
|
592
|
+
console.log(
|
|
593
|
+
chalk.magenta(
|
|
594
|
+
"\n📋 Want to see what's new? Check out the changelog: https://github.com/bmad-code-org/BMAD-METHOD/blob/main/CHANGELOG.md",
|
|
595
|
+
),
|
|
596
|
+
);
|
|
548
597
|
}
|
|
549
598
|
|
|
550
599
|
/**
|
|
@@ -574,8 +623,8 @@ class UI {
|
|
|
574
623
|
const { Installer } = require('../installers/lib/core/installer');
|
|
575
624
|
const detector = new Detector();
|
|
576
625
|
const installer = new Installer();
|
|
577
|
-
const
|
|
578
|
-
const existingInstall = await detector.detect(bmadDir);
|
|
626
|
+
const bmadDirResult = await installer.findBmadDir(directory);
|
|
627
|
+
const existingInstall = await detector.detect(bmadDirResult.bmadDir);
|
|
579
628
|
const installedModuleIds = new Set(existingInstall.modules.map((mod) => mod.id));
|
|
580
629
|
|
|
581
630
|
return { existingInstall, installedModuleIds };
|
|
@@ -594,7 +643,9 @@ class UI {
|
|
|
594
643
|
// Now collect with existing values as defaults (false = don't skip loading, true = skip completion message)
|
|
595
644
|
await configCollector.collectModuleConfig('core', directory, false, true);
|
|
596
645
|
|
|
597
|
-
|
|
646
|
+
const coreConfig = configCollector.collectedConfig.core;
|
|
647
|
+
// Ensure we always have a core config object, even if empty
|
|
648
|
+
return coreConfig || {};
|
|
598
649
|
}
|
|
599
650
|
|
|
600
651
|
/**
|
|
@@ -611,90 +662,28 @@ class UI {
|
|
|
611
662
|
const hasCustomContentItems = false;
|
|
612
663
|
|
|
613
664
|
// Add custom content items
|
|
614
|
-
if (customContentConfig && customContentConfig.hasCustomContent) {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
// Get the module info from cache
|
|
619
|
-
const yaml = require('js-yaml');
|
|
620
|
-
const fs = require('fs-extra');
|
|
621
|
-
|
|
622
|
-
// Try multiple possible config file locations
|
|
623
|
-
const possibleConfigPaths = [
|
|
624
|
-
path.join(cachedModule.cachePath, 'module.yaml'),
|
|
625
|
-
path.join(cachedModule.cachePath, 'custom.yaml'),
|
|
626
|
-
path.join(cachedModule.cachePath, '_module-installer', 'module.yaml'),
|
|
627
|
-
path.join(cachedModule.cachePath, '_module-installer', 'custom.yaml'),
|
|
628
|
-
];
|
|
629
|
-
|
|
630
|
-
let moduleData = null;
|
|
631
|
-
let foundPath = null;
|
|
632
|
-
|
|
633
|
-
for (const configPath of possibleConfigPaths) {
|
|
634
|
-
if (await fs.pathExists(configPath)) {
|
|
635
|
-
try {
|
|
636
|
-
const yamlContent = await fs.readFile(configPath, 'utf8');
|
|
637
|
-
moduleData = yaml.load(yamlContent);
|
|
638
|
-
foundPath = configPath;
|
|
639
|
-
break;
|
|
640
|
-
} catch {
|
|
641
|
-
// Continue to next path
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
if (moduleData) {
|
|
647
|
-
// Use the name from the custom info if we have it
|
|
648
|
-
const moduleName = cachedModule.name || moduleData.name || cachedModule.id;
|
|
665
|
+
if (customContentConfig && customContentConfig.hasCustomContent && customContentConfig.customPath) {
|
|
666
|
+
// Existing installation - show from directory
|
|
667
|
+
const customHandler = new CustomHandler();
|
|
668
|
+
const customFiles = await customHandler.findCustomContent(customContentConfig.customPath);
|
|
649
669
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
console.log(
|
|
660
|
-
chalk.dim(
|
|
661
|
-
`DEBUG: Tried paths:`,
|
|
662
|
-
possibleConfigPaths.map((p) => p.replace(cachedModule.cachePath, '.')),
|
|
663
|
-
),
|
|
664
|
-
);
|
|
665
|
-
console.log(chalk.dim(`DEBUG: cachedModule:`, JSON.stringify(cachedModule, null, 2)));
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
} else if (customContentConfig.customPath) {
|
|
669
|
-
// Existing installation - show from directory
|
|
670
|
-
const { CustomHandler } = require('../installers/lib/custom/handler');
|
|
671
|
-
const customHandler = new CustomHandler();
|
|
672
|
-
const customFiles = await customHandler.findCustomContent(customContentConfig.customPath);
|
|
673
|
-
|
|
674
|
-
for (const customFile of customFiles) {
|
|
675
|
-
const customInfo = await customHandler.getCustomInfo(customFile);
|
|
676
|
-
if (customInfo) {
|
|
677
|
-
customContentItems.push({
|
|
678
|
-
name: `${chalk.cyan('✓')} ${customInfo.name} ${chalk.gray(`(${customInfo.relativePath})`)}`,
|
|
679
|
-
value: `__CUSTOM_CONTENT__${customFile}`, // Unique value for each custom content
|
|
680
|
-
checked: true, // Default to selected since user chose to provide custom content
|
|
681
|
-
path: customInfo.path, // Track path to avoid duplicates
|
|
682
|
-
});
|
|
683
|
-
}
|
|
670
|
+
for (const customFile of customFiles) {
|
|
671
|
+
const customInfo = await customHandler.getCustomInfo(customFile);
|
|
672
|
+
if (customInfo) {
|
|
673
|
+
customContentItems.push({
|
|
674
|
+
name: `${chalk.cyan('✓')} ${customInfo.name} ${chalk.gray(`(${customInfo.relativePath})`)}`,
|
|
675
|
+
value: `__CUSTOM_CONTENT__${customFile}`, // Unique value for each custom content
|
|
676
|
+
checked: true, // Default to selected since user chose to provide custom content
|
|
677
|
+
path: customInfo.path, // Track path to avoid duplicates
|
|
678
|
+
});
|
|
684
679
|
}
|
|
685
680
|
}
|
|
686
681
|
}
|
|
687
682
|
|
|
688
683
|
// Add official modules
|
|
689
684
|
const { ModuleManager } = require('../installers/lib/modules/manager');
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
const shouldScanProject =
|
|
693
|
-
!isNewInstallation && customContentConfig && customContentConfig.hasCustomContent && customContentConfig.selected;
|
|
694
|
-
const moduleManager = new ModuleManager({
|
|
695
|
-
scanProjectForModules: shouldScanProject,
|
|
696
|
-
});
|
|
697
|
-
const { modules: availableModules, customModules: customModulesFromProject } = await moduleManager.listAvailable();
|
|
685
|
+
const moduleManager = new ModuleManager();
|
|
686
|
+
const { modules: availableModules, customModules: customModulesFromCache } = await moduleManager.listAvailable();
|
|
698
687
|
|
|
699
688
|
// First, add all items to appropriate sections
|
|
700
689
|
const allCustomModules = [];
|
|
@@ -702,14 +691,14 @@ class UI {
|
|
|
702
691
|
// Add custom content items from directory
|
|
703
692
|
allCustomModules.push(...customContentItems);
|
|
704
693
|
|
|
705
|
-
// Add custom modules from
|
|
706
|
-
for (const mod of
|
|
694
|
+
// Add custom modules from cache
|
|
695
|
+
for (const mod of customModulesFromCache) {
|
|
707
696
|
// Skip if this module is already in customContentItems (by path)
|
|
708
697
|
const isDuplicate = allCustomModules.some((item) => item.path && mod.path && path.resolve(item.path) === path.resolve(mod.path));
|
|
709
698
|
|
|
710
699
|
if (!isDuplicate) {
|
|
711
700
|
allCustomModules.push({
|
|
712
|
-
name: `${chalk.cyan('✓')} ${mod.name} ${chalk.gray(`(
|
|
701
|
+
name: `${chalk.cyan('✓')} ${mod.name} ${chalk.gray(`(cached)`)}`,
|
|
713
702
|
value: mod.id,
|
|
714
703
|
checked: isNewInstallation ? mod.defaultSelected || false : installedModuleIds.has(mod.id),
|
|
715
704
|
});
|
|
@@ -745,19 +734,20 @@ class UI {
|
|
|
745
734
|
* @param {Array} moduleChoices - Available module choices
|
|
746
735
|
* @returns {Array} Selected module IDs
|
|
747
736
|
*/
|
|
748
|
-
async selectModules(moduleChoices) {
|
|
749
|
-
CLIUtils.displaySection('Module Selection', 'Choose the BMAD modules to install');
|
|
750
|
-
|
|
737
|
+
async selectModules(moduleChoices, defaultSelections = []) {
|
|
751
738
|
const moduleAnswer = await inquirer.prompt([
|
|
752
739
|
{
|
|
753
740
|
type: 'checkbox',
|
|
754
741
|
name: 'modules',
|
|
755
742
|
message: 'Select modules to install:',
|
|
756
743
|
choices: moduleChoices,
|
|
744
|
+
default: defaultSelections,
|
|
757
745
|
},
|
|
758
746
|
]);
|
|
759
747
|
|
|
760
|
-
|
|
748
|
+
const selected = moduleAnswer.modules || [];
|
|
749
|
+
|
|
750
|
+
return selected;
|
|
761
751
|
}
|
|
762
752
|
|
|
763
753
|
/**
|
|
@@ -797,15 +787,16 @@ class UI {
|
|
|
797
787
|
if (stats.isDirectory()) {
|
|
798
788
|
const files = await fs.readdir(directory);
|
|
799
789
|
if (files.length > 0) {
|
|
800
|
-
// Check for any bmad installation (any folder with
|
|
790
|
+
// Check for any bmad installation (any folder with _config/manifest.yaml)
|
|
801
791
|
const { Installer } = require('../installers/lib/core/installer');
|
|
802
792
|
const installer = new Installer();
|
|
803
|
-
const
|
|
804
|
-
const hasBmadInstall =
|
|
793
|
+
const bmadResult = await installer.findBmadDir(directory);
|
|
794
|
+
const hasBmadInstall =
|
|
795
|
+
(await fs.pathExists(bmadResult.bmadDir)) && (await fs.pathExists(path.join(bmadResult.bmadDir, '_config', 'manifest.yaml')));
|
|
805
796
|
|
|
806
797
|
console.log(
|
|
807
798
|
chalk.gray(`Directory exists and contains ${files.length} item(s)`) +
|
|
808
|
-
(hasBmadInstall ? chalk.yellow(` including existing BMAD installation (${path.basename(bmadDir)})`) : ''),
|
|
799
|
+
(hasBmadInstall ? chalk.yellow(` including existing BMAD installation (${path.basename(bmadResult.bmadDir)})`) : ''),
|
|
809
800
|
);
|
|
810
801
|
} else {
|
|
811
802
|
console.log(chalk.gray('Directory exists and is empty'));
|
|
@@ -814,116 +805,6 @@ class UI {
|
|
|
814
805
|
}
|
|
815
806
|
}
|
|
816
807
|
|
|
817
|
-
/**
|
|
818
|
-
* Prompt for custom content location
|
|
819
|
-
* @returns {Object} Custom content configuration
|
|
820
|
-
*/
|
|
821
|
-
async promptCustomContentLocation() {
|
|
822
|
-
try {
|
|
823
|
-
CLIUtils.displaySection('Custom Content', 'Optional: Add custom agents, workflows, and modules');
|
|
824
|
-
|
|
825
|
-
const { hasCustomContent } = await inquirer.prompt([
|
|
826
|
-
{
|
|
827
|
-
type: 'list',
|
|
828
|
-
name: 'hasCustomContent',
|
|
829
|
-
message: 'Do you have custom content to install?',
|
|
830
|
-
choices: [
|
|
831
|
-
{ name: 'No (skip custom content)', value: 'none' },
|
|
832
|
-
{ name: 'Enter a directory path', value: 'directory' },
|
|
833
|
-
{ name: 'Enter a URL', value: 'url' },
|
|
834
|
-
],
|
|
835
|
-
default: 'none',
|
|
836
|
-
},
|
|
837
|
-
]);
|
|
838
|
-
|
|
839
|
-
if (hasCustomContent === 'none') {
|
|
840
|
-
return { hasCustomContent: false };
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
if (hasCustomContent === 'url') {
|
|
844
|
-
console.log(chalk.yellow('\nURL-based custom content installation is coming soon!'));
|
|
845
|
-
console.log(chalk.cyan('For now, please download your custom content and choose "Enter a directory path".\n'));
|
|
846
|
-
return { hasCustomContent: false };
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
if (hasCustomContent === 'directory') {
|
|
850
|
-
let customPath;
|
|
851
|
-
while (!customPath) {
|
|
852
|
-
let expandedPath;
|
|
853
|
-
const { directory } = await inquirer.prompt([
|
|
854
|
-
{
|
|
855
|
-
type: 'input',
|
|
856
|
-
name: 'directory',
|
|
857
|
-
message: 'Enter directory to search for custom content (will scan subfolders):',
|
|
858
|
-
default: process.cwd(), // Use actual current working directory
|
|
859
|
-
validate: async (input) => {
|
|
860
|
-
if (!input || input.trim() === '') {
|
|
861
|
-
return 'Please enter a directory path';
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
try {
|
|
865
|
-
expandedPath = this.expandUserPath(input.trim());
|
|
866
|
-
} catch (error) {
|
|
867
|
-
return error.message;
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
// Check if the path exists
|
|
871
|
-
const pathExists = await fs.pathExists(expandedPath);
|
|
872
|
-
if (!pathExists) {
|
|
873
|
-
return 'Directory does not exist';
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
return true;
|
|
877
|
-
},
|
|
878
|
-
},
|
|
879
|
-
]);
|
|
880
|
-
|
|
881
|
-
// Now expand the path for use after the prompt
|
|
882
|
-
expandedPath = this.expandUserPath(directory.trim());
|
|
883
|
-
|
|
884
|
-
// Check if directory has custom content
|
|
885
|
-
const { CustomHandler } = require('../installers/lib/custom/handler');
|
|
886
|
-
const customHandler = new CustomHandler();
|
|
887
|
-
const customFiles = await customHandler.findCustomContent(expandedPath);
|
|
888
|
-
|
|
889
|
-
if (customFiles.length === 0) {
|
|
890
|
-
console.log(chalk.yellow(`\nNo custom content found in ${expandedPath}`));
|
|
891
|
-
|
|
892
|
-
const { tryAgain } = await inquirer.prompt([
|
|
893
|
-
{
|
|
894
|
-
type: 'confirm',
|
|
895
|
-
name: 'tryAgain',
|
|
896
|
-
message: 'Try a different directory?',
|
|
897
|
-
default: true,
|
|
898
|
-
},
|
|
899
|
-
]);
|
|
900
|
-
|
|
901
|
-
if (tryAgain) {
|
|
902
|
-
continue;
|
|
903
|
-
} else {
|
|
904
|
-
return { hasCustomContent: false };
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
customPath = expandedPath;
|
|
909
|
-
console.log(chalk.green(`\n✓ Found ${customFiles.length} custom content item(s):`));
|
|
910
|
-
for (const file of customFiles) {
|
|
911
|
-
const relativePath = path.relative(expandedPath, path.dirname(file));
|
|
912
|
-
const folderName = path.dirname(file).split(path.sep).pop();
|
|
913
|
-
console.log(chalk.dim(` • ${folderName} ${chalk.gray(`(${relativePath})`)}`));
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
return { hasCustomContent: true, customPath };
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
return { hasCustomContent: false };
|
|
921
|
-
} catch (error) {
|
|
922
|
-
console.error(chalk.red('Error in custom content prompt:'), error);
|
|
923
|
-
return { hasCustomContent: false };
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
|
|
927
808
|
/**
|
|
928
809
|
* Confirm directory selection
|
|
929
810
|
* @param {string} directory - The directory path
|
|
@@ -1088,7 +969,7 @@ class UI {
|
|
|
1088
969
|
* @calls checkAgentVibesInstalled(), inquirer.prompt(), chalk.green/yellow/dim()
|
|
1089
970
|
*
|
|
1090
971
|
* AI NOTE: This prompt is strategically positioned in installation flow:
|
|
1091
|
-
* - AFTER core config (
|
|
972
|
+
* - AFTER core config (user_name, etc)
|
|
1092
973
|
* - BEFORE IDE selection (which can hang on Windows/PowerShell)
|
|
1093
974
|
*
|
|
1094
975
|
* Flow Logic:
|
|
@@ -1211,141 +1092,319 @@ class UI {
|
|
|
1211
1092
|
}
|
|
1212
1093
|
|
|
1213
1094
|
/**
|
|
1214
|
-
*
|
|
1215
|
-
* @
|
|
1095
|
+
* Load existing configurations to use as defaults
|
|
1096
|
+
* @param {string} directory - Installation directory
|
|
1097
|
+
* @returns {Object} Existing configurations
|
|
1216
1098
|
*/
|
|
1217
|
-
async
|
|
1099
|
+
async loadExistingConfigurations(directory) {
|
|
1100
|
+
const configs = {
|
|
1101
|
+
hasCustomContent: false,
|
|
1102
|
+
coreConfig: {},
|
|
1103
|
+
ideConfig: { ides: [], skipIde: false },
|
|
1104
|
+
agentVibesConfig: { enabled: false, alreadyInstalled: false },
|
|
1105
|
+
};
|
|
1106
|
+
|
|
1218
1107
|
try {
|
|
1219
|
-
|
|
1108
|
+
// Load core config
|
|
1109
|
+
configs.coreConfig = await this.collectCoreConfig(directory);
|
|
1110
|
+
|
|
1111
|
+
// Load IDE configuration
|
|
1112
|
+
const configuredIdes = await this.getConfiguredIdes(directory);
|
|
1113
|
+
if (configuredIdes.length > 0) {
|
|
1114
|
+
configs.ideConfig.ides = configuredIdes;
|
|
1115
|
+
configs.ideConfig.skipIde = false;
|
|
1116
|
+
}
|
|
1220
1117
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
name: 'hasCustomContent',
|
|
1225
|
-
message: 'Do you want to add or update custom content?',
|
|
1226
|
-
choices: [
|
|
1227
|
-
{
|
|
1228
|
-
name: 'No, continue with current installation only',
|
|
1229
|
-
value: false,
|
|
1230
|
-
},
|
|
1231
|
-
{
|
|
1232
|
-
name: 'Yes, I have custom content to add or update',
|
|
1233
|
-
value: true,
|
|
1234
|
-
},
|
|
1235
|
-
],
|
|
1236
|
-
default: false,
|
|
1237
|
-
},
|
|
1238
|
-
]);
|
|
1118
|
+
// Load AgentVibes configuration
|
|
1119
|
+
const agentVibesInstalled = await this.checkAgentVibesInstalled(directory);
|
|
1120
|
+
configs.agentVibesConfig = { enabled: agentVibesInstalled, alreadyInstalled: agentVibesInstalled };
|
|
1239
1121
|
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1122
|
+
return configs;
|
|
1123
|
+
} catch {
|
|
1124
|
+
// If loading fails, return empty configs
|
|
1125
|
+
console.warn('Warning: Could not load existing configurations');
|
|
1126
|
+
return configs;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1243
1129
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
const pathExists = await fs.pathExists(expandedPath);
|
|
1259
|
-
if (!pathExists) {
|
|
1260
|
-
return 'Directory does not exist';
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
// Check if it's actually a directory
|
|
1264
|
-
const stats = await fs.stat(expandedPath);
|
|
1265
|
-
if (!stats.isDirectory()) {
|
|
1266
|
-
return 'Path must be a directory';
|
|
1267
|
-
}
|
|
1268
|
-
|
|
1269
|
-
return true;
|
|
1270
|
-
},
|
|
1271
|
-
transformer: (input) => {
|
|
1272
|
-
return CLIUtils.expandPath(input);
|
|
1273
|
-
},
|
|
1274
|
-
},
|
|
1275
|
-
]);
|
|
1130
|
+
/**
|
|
1131
|
+
* Get configured IDEs from existing installation
|
|
1132
|
+
* @param {string} directory - Installation directory
|
|
1133
|
+
* @returns {Array} List of configured IDEs
|
|
1134
|
+
*/
|
|
1135
|
+
async getConfiguredIdes(directory) {
|
|
1136
|
+
const { Detector } = require('../installers/lib/core/detector');
|
|
1137
|
+
const { Installer } = require('../installers/lib/core/installer');
|
|
1138
|
+
const detector = new Detector();
|
|
1139
|
+
const installer = new Installer();
|
|
1140
|
+
const bmadResult = await installer.findBmadDir(directory);
|
|
1141
|
+
const existingInstall = await detector.detect(bmadResult.bmadDir);
|
|
1142
|
+
return existingInstall.ides || [];
|
|
1143
|
+
}
|
|
1276
1144
|
|
|
1277
|
-
|
|
1145
|
+
/**
|
|
1146
|
+
* Prompt user for custom content source location
|
|
1147
|
+
* @returns {Object} Custom content configuration
|
|
1148
|
+
*/
|
|
1149
|
+
async promptCustomContentSource() {
|
|
1150
|
+
const customContentConfig = { hasCustomContent: true, sources: [] };
|
|
1151
|
+
|
|
1152
|
+
// Keep asking for more sources until user is done
|
|
1153
|
+
while (true) {
|
|
1154
|
+
// First ask if user wants to add another module or continue
|
|
1155
|
+
if (customContentConfig.sources.length > 0) {
|
|
1156
|
+
const { action } = await inquirer.prompt([
|
|
1157
|
+
{
|
|
1158
|
+
type: 'list',
|
|
1159
|
+
name: 'action',
|
|
1160
|
+
message: 'Would you like to:',
|
|
1161
|
+
choices: [
|
|
1162
|
+
{ name: 'Add another custom module', value: 'add' },
|
|
1163
|
+
{ name: 'Continue with installation', value: 'continue' },
|
|
1164
|
+
],
|
|
1165
|
+
default: 'continue',
|
|
1166
|
+
},
|
|
1167
|
+
]);
|
|
1278
1168
|
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1169
|
+
if (action === 'continue') {
|
|
1170
|
+
break;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1283
1173
|
|
|
1284
|
-
|
|
1285
|
-
|
|
1174
|
+
let sourcePath;
|
|
1175
|
+
let isValid = false;
|
|
1286
1176
|
|
|
1287
|
-
|
|
1177
|
+
while (!isValid) {
|
|
1178
|
+
const { path: inputPath } = await inquirer.prompt([
|
|
1288
1179
|
{
|
|
1289
|
-
type: '
|
|
1290
|
-
name: '
|
|
1291
|
-
message: '
|
|
1292
|
-
|
|
1180
|
+
type: 'input',
|
|
1181
|
+
name: 'path',
|
|
1182
|
+
message: 'Enter the path to your custom content folder (or press Enter to cancel):',
|
|
1183
|
+
validate: async (input) => {
|
|
1184
|
+
// Allow empty input to cancel
|
|
1185
|
+
if (!input || input.trim() === '') {
|
|
1186
|
+
return true; // Allow empty to exit
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
try {
|
|
1190
|
+
// Expand the path
|
|
1191
|
+
const expandedPath = this.expandUserPath(input.trim());
|
|
1192
|
+
|
|
1193
|
+
// Check if path exists
|
|
1194
|
+
if (!(await fs.pathExists(expandedPath))) {
|
|
1195
|
+
return 'Path does not exist';
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
// Check if it's a directory
|
|
1199
|
+
const stat = await fs.stat(expandedPath);
|
|
1200
|
+
if (!stat.isDirectory()) {
|
|
1201
|
+
return 'Path must be a directory';
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// Check for module.yaml in the root
|
|
1205
|
+
const moduleYamlPath = path.join(expandedPath, 'module.yaml');
|
|
1206
|
+
if (!(await fs.pathExists(moduleYamlPath))) {
|
|
1207
|
+
return 'Directory must contain a module.yaml file in the root';
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
// Try to parse the module.yaml to get the module ID
|
|
1211
|
+
try {
|
|
1212
|
+
const yaml = require('yaml');
|
|
1213
|
+
const content = await fs.readFile(moduleYamlPath, 'utf8');
|
|
1214
|
+
const moduleData = yaml.parse(content);
|
|
1215
|
+
if (!moduleData.code) {
|
|
1216
|
+
return 'module.yaml must contain a "code" field for the module ID';
|
|
1217
|
+
}
|
|
1218
|
+
} catch (error) {
|
|
1219
|
+
return 'Invalid module.yaml file: ' + error.message;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
return true;
|
|
1223
|
+
} catch (error) {
|
|
1224
|
+
return 'Error validating path: ' + error.message;
|
|
1225
|
+
}
|
|
1226
|
+
},
|
|
1293
1227
|
},
|
|
1294
1228
|
]);
|
|
1295
1229
|
|
|
1296
|
-
|
|
1297
|
-
|
|
1230
|
+
// If user pressed Enter without typing anything, exit the loop
|
|
1231
|
+
if (!inputPath || inputPath.trim() === '') {
|
|
1232
|
+
// If we have no modules yet, return false for no custom content
|
|
1233
|
+
if (customContentConfig.sources.length === 0) {
|
|
1234
|
+
return { hasCustomContent: false };
|
|
1235
|
+
}
|
|
1236
|
+
return customContentConfig;
|
|
1298
1237
|
}
|
|
1299
1238
|
|
|
1300
|
-
|
|
1239
|
+
sourcePath = this.expandUserPath(inputPath);
|
|
1240
|
+
isValid = true;
|
|
1301
1241
|
}
|
|
1302
1242
|
|
|
1303
|
-
//
|
|
1304
|
-
|
|
1305
|
-
const
|
|
1306
|
-
const
|
|
1307
|
-
const
|
|
1243
|
+
// Read module.yaml to get module info
|
|
1244
|
+
const yaml = require('yaml');
|
|
1245
|
+
const moduleYamlPath = path.join(sourcePath, 'module.yaml');
|
|
1246
|
+
const moduleContent = await fs.readFile(moduleYamlPath, 'utf8');
|
|
1247
|
+
const moduleData = yaml.parse(moduleContent);
|
|
1308
1248
|
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1249
|
+
// Add to sources
|
|
1250
|
+
customContentConfig.sources.push({
|
|
1251
|
+
path: sourcePath,
|
|
1252
|
+
id: moduleData.code,
|
|
1253
|
+
name: moduleData.name || moduleData.code,
|
|
1254
|
+
});
|
|
1255
|
+
|
|
1256
|
+
console.log(chalk.green(`✓ Confirmed local custom module: ${moduleData.name || moduleData.code}`));
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
// Ask if user wants to add these to the installation
|
|
1260
|
+
const { shouldInstall } = await inquirer.prompt([
|
|
1261
|
+
{
|
|
1262
|
+
type: 'confirm',
|
|
1263
|
+
name: 'shouldInstall',
|
|
1264
|
+
message: `Install ${customContentConfig.sources.length} custom module(s) now?`,
|
|
1265
|
+
default: true,
|
|
1266
|
+
},
|
|
1267
|
+
]);
|
|
1268
|
+
|
|
1269
|
+
if (shouldInstall) {
|
|
1270
|
+
customContentConfig.selected = true;
|
|
1271
|
+
// Store paths to module.yaml files, not directories
|
|
1272
|
+
customContentConfig.selectedFiles = customContentConfig.sources.map((s) => path.join(s.path, 'module.yaml'));
|
|
1273
|
+
// Also include module IDs for installation
|
|
1274
|
+
customContentConfig.selectedModuleIds = customContentConfig.sources.map((s) => s.id);
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
return customContentConfig;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
/**
|
|
1281
|
+
* Handle custom modules in the modify flow
|
|
1282
|
+
* @param {string} directory - Installation directory
|
|
1283
|
+
* @param {Array} selectedModules - Currently selected modules
|
|
1284
|
+
* @returns {Object} Result with selected custom modules and custom content config
|
|
1285
|
+
*/
|
|
1286
|
+
async handleCustomModulesInModifyFlow(directory, selectedModules) {
|
|
1287
|
+
// Get existing installation to find custom modules
|
|
1288
|
+
const { existingInstall } = await this.getExistingInstallation(directory);
|
|
1289
|
+
|
|
1290
|
+
// Check if there are any custom modules in cache
|
|
1291
|
+
const { Installer } = require('../installers/lib/core/installer');
|
|
1292
|
+
const installer = new Installer();
|
|
1293
|
+
const { bmadDir } = await installer.findBmadDir(directory);
|
|
1294
|
+
|
|
1295
|
+
const cacheDir = path.join(bmadDir, '_config', 'custom');
|
|
1296
|
+
const cachedCustomModules = [];
|
|
1297
|
+
|
|
1298
|
+
if (await fs.pathExists(cacheDir)) {
|
|
1299
|
+
const entries = await fs.readdir(cacheDir, { withFileTypes: true });
|
|
1300
|
+
for (const entry of entries) {
|
|
1301
|
+
if (entry.isDirectory()) {
|
|
1302
|
+
const moduleYamlPath = path.join(cacheDir, entry.name, 'module.yaml');
|
|
1303
|
+
if (await fs.pathExists(moduleYamlPath)) {
|
|
1304
|
+
const yaml = require('yaml');
|
|
1305
|
+
const content = await fs.readFile(moduleYamlPath, 'utf8');
|
|
1306
|
+
const moduleData = yaml.parse(content);
|
|
1307
|
+
|
|
1308
|
+
cachedCustomModules.push({
|
|
1309
|
+
id: entry.name,
|
|
1310
|
+
name: moduleData.name || entry.name,
|
|
1311
|
+
description: moduleData.description || 'Custom module from cache',
|
|
1312
|
+
checked: selectedModules.includes(entry.name),
|
|
1313
|
+
fromCache: true,
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1317
1316
|
}
|
|
1318
1317
|
}
|
|
1318
|
+
}
|
|
1319
1319
|
|
|
1320
|
-
|
|
1321
|
-
|
|
1320
|
+
const result = {
|
|
1321
|
+
selectedCustomModules: [],
|
|
1322
|
+
customContentConfig: { hasCustomContent: false },
|
|
1323
|
+
};
|
|
1322
1324
|
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1325
|
+
if (cachedCustomModules.length === 0) {
|
|
1326
|
+
return result;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// Ask user about custom modules
|
|
1330
|
+
console.log(chalk.cyan('\n⚙️ Custom Modules'));
|
|
1331
|
+
console.log(chalk.dim('Found custom modules in your installation:'));
|
|
1332
|
+
|
|
1333
|
+
const { customAction } = await inquirer.prompt([
|
|
1334
|
+
{
|
|
1335
|
+
type: 'list',
|
|
1336
|
+
name: 'customAction',
|
|
1337
|
+
message: 'What would you like to do with custom modules?',
|
|
1338
|
+
choices: [
|
|
1339
|
+
{ name: 'Keep all existing custom modules', value: 'keep' },
|
|
1340
|
+
{ name: 'Select which custom modules to keep', value: 'select' },
|
|
1341
|
+
{ name: 'Add new custom modules', value: 'add' },
|
|
1342
|
+
{ name: 'Remove all custom modules', value: 'remove' },
|
|
1343
|
+
],
|
|
1344
|
+
default: 'keep',
|
|
1345
|
+
},
|
|
1346
|
+
]);
|
|
1347
|
+
|
|
1348
|
+
switch (customAction) {
|
|
1349
|
+
case 'keep': {
|
|
1350
|
+
// Keep all existing custom modules
|
|
1351
|
+
result.selectedCustomModules = cachedCustomModules.map((m) => m.id);
|
|
1352
|
+
console.log(chalk.dim(`Keeping ${result.selectedCustomModules.length} custom module(s)`));
|
|
1353
|
+
break;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
case 'select': {
|
|
1357
|
+
// Let user choose which to keep
|
|
1358
|
+
const choices = cachedCustomModules.map((m) => ({
|
|
1359
|
+
name: `${m.name} ${chalk.gray(`(${m.id})`)}`,
|
|
1360
|
+
value: m.id,
|
|
1361
|
+
}));
|
|
1362
|
+
|
|
1363
|
+
const { keepModules } = await inquirer.prompt([
|
|
1364
|
+
{
|
|
1365
|
+
type: 'checkbox',
|
|
1366
|
+
name: 'keepModules',
|
|
1367
|
+
message: 'Select custom modules to keep:',
|
|
1368
|
+
choices: choices,
|
|
1369
|
+
default: cachedCustomModules.filter((m) => m.checked).map((m) => m.id),
|
|
1335
1370
|
},
|
|
1336
|
-
|
|
1337
|
-
|
|
1371
|
+
]);
|
|
1372
|
+
result.selectedCustomModules = keepModules;
|
|
1373
|
+
break;
|
|
1374
|
+
}
|
|
1338
1375
|
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1376
|
+
case 'add': {
|
|
1377
|
+
// First ask to keep existing ones
|
|
1378
|
+
const { keepExisting } = await inquirer.prompt([
|
|
1379
|
+
{
|
|
1380
|
+
type: 'confirm',
|
|
1381
|
+
name: 'keepExisting',
|
|
1382
|
+
message: 'Keep existing custom modules?',
|
|
1383
|
+
default: true,
|
|
1384
|
+
},
|
|
1385
|
+
]);
|
|
1386
|
+
|
|
1387
|
+
if (keepExisting) {
|
|
1388
|
+
result.selectedCustomModules = cachedCustomModules.map((m) => m.id);
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
// Then prompt for new ones (reuse existing method)
|
|
1392
|
+
const newCustomContent = await this.promptCustomContentSource();
|
|
1393
|
+
if (newCustomContent.hasCustomContent && newCustomContent.selected) {
|
|
1394
|
+
result.selectedCustomModules.push(...newCustomContent.selectedModuleIds);
|
|
1395
|
+
result.customContentConfig = newCustomContent;
|
|
1396
|
+
}
|
|
1397
|
+
break;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
case 'remove': {
|
|
1401
|
+
// Remove all custom modules
|
|
1402
|
+
console.log(chalk.yellow('All custom modules will be removed from the installation'));
|
|
1403
|
+
break;
|
|
1404
|
+
}
|
|
1348
1405
|
}
|
|
1406
|
+
|
|
1407
|
+
return result;
|
|
1349
1408
|
}
|
|
1350
1409
|
}
|
|
1351
1410
|
|