@zeyue0329/xiaoma-cli 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/FORK_GUIDE.md +106 -0
- package/.github/FUNDING.yaml +15 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- package/.github/workflows/discord.yaml +26 -0
- package/.github/workflows/format-check.yaml +44 -0
- package/.github/workflows/manual-release.yaml +174 -0
- package/.github/workflows/pr-validation.yaml +55 -0
- package/.husky/pre-commit +3 -0
- package/.vscode/settings.json +26 -1
- package/CHANGELOG.md +686 -0
- package/CONTRIBUTING.md +250 -0
- package/LICENSE +6 -1
- package/common/tasks/create-doc.md +2 -0
- package/common/tasks/execute-checklist.md +2 -7
- package/common/utils/bmad-doc-template.md +7 -5
- package/common/utils/workflow-management.md +2 -0
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +2103 -0
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.txt +1627 -0
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.txt +822 -0
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +8486 -0
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.txt +3210 -0
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.txt +3244 -0
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.txt +317 -0
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.txt +982 -0
- package/dist/expansion-packs/bmad-2d-unity-game-dev/teams/unity-2d-game-team.txt +12854 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/beta-reader.txt +921 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/book-critic.txt +81 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/character-psychologist.txt +886 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/cover-designer.txt +85 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/dialog-specialist.txt +903 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/editor.txt +837 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/genre-specialist.txt +989 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/narrative-designer.txt +888 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/plot-architect.txt +1173 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/world-builder.txt +914 -0
- package/dist/expansion-packs/bmad-creative-writing/teams/agent-team.txt +6071 -0
- package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +2079 -0
- package/docs/GUIDING-PRINCIPLES.md +91 -0
- package/docs/core-architecture.md +219 -0
- package/docs/enhanced-ide-development-workflow.md +248 -0
- package/docs/expansion-packs.md +200 -0
- package/docs/how-to-contribute-with-pull-requests.md +158 -0
- package/docs/user-guide.md +530 -0
- package/docs/versioning-and-releases.md +155 -0
- package/docs/versions.md +48 -0
- package/docs/working-in-the-brownfield.md +597 -0
- package/eslint.config.mjs +119 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/agent-teams/phaser-2d-nodejs-game-team.yaml +14 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.md +73 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.md +80 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.md +66 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-design-checklist.md +203 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-story-dod-checklist.md +162 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/config.yaml +9 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/data/bmad-kb.md +252 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/data/development-guidelines.md +649 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/tasks/advanced-elicitation.md +112 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/tasks/create-game-story.md +218 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/tasks/game-design-brainstorming.md +292 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-architecture-tmpl.yaml +614 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-brief-tmpl.yaml +357 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-design-doc-tmpl.yaml +344 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-story-tmpl.yaml +254 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/templates/level-design-doc-tmpl.yaml +485 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-dev-greenfield.yaml +184 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-prototype.yaml +176 -0
- package/expansion-packs/bmad-2d-unity-game-dev/agent-teams/unity-2d-game-team.yaml +15 -0
- package/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.md +82 -0
- package/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.md +79 -0
- package/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.md +80 -0
- package/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.md +67 -0
- package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-architect-checklist.md +393 -0
- package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-change-checklist.md +205 -0
- package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-design-checklist.md +203 -0
- package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-story-dod-checklist.md +126 -0
- package/expansion-packs/bmad-2d-unity-game-dev/config.yaml +7 -0
- package/expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md +771 -0
- package/expansion-packs/bmad-2d-unity-game-dev/data/development-guidelines.md +588 -0
- package/expansion-packs/bmad-2d-unity-game-dev/tasks/advanced-elicitation.md +112 -0
- package/expansion-packs/bmad-2d-unity-game-dev/tasks/correct-course-game.md +143 -0
- package/expansion-packs/bmad-2d-unity-game-dev/tasks/create-game-story.md +186 -0
- package/expansion-packs/bmad-2d-unity-game-dev/tasks/game-design-brainstorming.md +292 -0
- package/expansion-packs/bmad-2d-unity-game-dev/tasks/validate-game-story.md +202 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-architecture-tmpl.yaml +1031 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-brief-tmpl.yaml +357 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml +706 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-story-tmpl.yaml +257 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml +485 -0
- package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-dev-greenfield.yaml +184 -0
- package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-prototype.yaml +176 -0
- package/expansion-packs/bmad-creative-writing/README.md +146 -0
- package/expansion-packs/bmad-creative-writing/agent-teams/agent-team.yaml +20 -0
- package/expansion-packs/bmad-creative-writing/agents/beta-reader.md +94 -0
- package/expansion-packs/bmad-creative-writing/agents/book-critic.md +40 -0
- package/expansion-packs/bmad-creative-writing/agents/character-psychologist.md +93 -0
- package/expansion-packs/bmad-creative-writing/agents/cover-designer.md +46 -0
- package/expansion-packs/bmad-creative-writing/agents/dialog-specialist.md +92 -0
- package/expansion-packs/bmad-creative-writing/agents/editor.md +93 -0
- package/expansion-packs/bmad-creative-writing/agents/genre-specialist.md +95 -0
- package/expansion-packs/bmad-creative-writing/agents/narrative-designer.md +93 -0
- package/expansion-packs/bmad-creative-writing/agents/plot-architect.md +95 -0
- package/expansion-packs/bmad-creative-writing/agents/world-builder.md +94 -0
- package/expansion-packs/bmad-creative-writing/checklists/beta-feedback-closure-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/character-consistency-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/comedic-timing-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/cyberpunk-aesthetic-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/ebook-formatting-checklist.md +21 -0
- package/expansion-packs/bmad-creative-writing/checklists/epic-poetry-meter-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/fantasy-magic-system-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/foreshadowing-payoff-checklist.md +22 -0
- package/expansion-packs/bmad-creative-writing/checklists/genre-tropes-checklist.md +22 -0
- package/expansion-packs/bmad-creative-writing/checklists/historical-accuracy-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/horror-suspense-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/kdp-cover-ready-checklist.md +25 -0
- package/expansion-packs/bmad-creative-writing/checklists/line-edit-quality-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/marketing-copy-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/mystery-clue-trail-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/orbital-mechanics-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/plot-structure-checklist.md +59 -0
- package/expansion-packs/bmad-creative-writing/checklists/publication-readiness-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/romance-emotional-beats-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/scene-quality-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/scifi-technology-plausibility-checklist.md +22 -0
- package/expansion-packs/bmad-creative-writing/checklists/sensitivity-representation-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/steampunk-gadget-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/thriller-pacing-stakes-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/timeline-continuity-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/world-building-continuity-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/checklists/ya-appropriateness-checklist.md +23 -0
- package/expansion-packs/bmad-creative-writing/config.yaml +12 -0
- package/expansion-packs/bmad-creative-writing/data/bmad-kb.md +209 -0
- package/expansion-packs/bmad-creative-writing/data/story-structures.md +67 -0
- package/expansion-packs/bmad-creative-writing/docs/brief.md +212 -0
- package/expansion-packs/bmad-creative-writing/tasks/advanced-elicitation.md +119 -0
- package/expansion-packs/bmad-creative-writing/tasks/analyze-reader-feedback.md +23 -0
- package/expansion-packs/bmad-creative-writing/tasks/analyze-story-structure.md +67 -0
- package/expansion-packs/bmad-creative-writing/tasks/assemble-kdp-package.md +29 -0
- package/expansion-packs/bmad-creative-writing/tasks/brainstorm-premise.md +23 -0
- package/expansion-packs/bmad-creative-writing/tasks/build-world.md +24 -0
- package/expansion-packs/bmad-creative-writing/tasks/character-depth-pass.md +22 -0
- package/expansion-packs/bmad-creative-writing/tasks/create-doc.md +103 -0
- package/expansion-packs/bmad-creative-writing/tasks/create-draft-section.md +26 -0
- package/expansion-packs/bmad-creative-writing/tasks/critical-review.md +26 -0
- package/expansion-packs/bmad-creative-writing/tasks/develop-character.md +24 -0
- package/expansion-packs/bmad-creative-writing/tasks/execute-checklist.md +88 -0
- package/expansion-packs/bmad-creative-writing/tasks/expand-premise.md +23 -0
- package/expansion-packs/bmad-creative-writing/tasks/expand-synopsis.md +23 -0
- package/expansion-packs/bmad-creative-writing/tasks/final-polish.md +23 -0
- package/expansion-packs/bmad-creative-writing/tasks/generate-cover-brief.md +25 -0
- package/expansion-packs/bmad-creative-writing/tasks/generate-cover-prompts.md +26 -0
- package/expansion-packs/bmad-creative-writing/tasks/generate-scene-list.md +23 -0
- package/expansion-packs/bmad-creative-writing/tasks/incorporate-feedback.md +25 -0
- package/expansion-packs/bmad-creative-writing/tasks/outline-scenes.md +23 -0
- package/expansion-packs/bmad-creative-writing/tasks/provide-feedback.md +24 -0
- package/expansion-packs/bmad-creative-writing/tasks/publish-chapter.md +23 -0
- package/expansion-packs/bmad-creative-writing/tasks/quick-feedback.md +22 -0
- package/expansion-packs/bmad-creative-writing/tasks/select-next-arc.md +23 -0
- package/expansion-packs/bmad-creative-writing/tasks/workshop-dialog.md +64 -0
- package/expansion-packs/bmad-creative-writing/templates/beta-feedback-form.yaml +97 -0
- package/expansion-packs/bmad-creative-writing/templates/chapter-draft-tmpl.yaml +82 -0
- package/expansion-packs/bmad-creative-writing/templates/character-profile-tmpl.yaml +92 -0
- package/expansion-packs/bmad-creative-writing/templates/cover-design-brief-tmpl.yaml +98 -0
- package/expansion-packs/bmad-creative-writing/templates/premise-brief-tmpl.yaml +78 -0
- package/expansion-packs/bmad-creative-writing/templates/scene-list-tmpl.yaml +55 -0
- package/expansion-packs/bmad-creative-writing/templates/story-outline-tmpl.yaml +96 -0
- package/expansion-packs/bmad-creative-writing/templates/world-guide-tmpl.yaml +89 -0
- package/expansion-packs/bmad-creative-writing/workflows/book-cover-design-workflow.md +218 -0
- package/expansion-packs/bmad-creative-writing/workflows/novel-greenfield-workflow.yaml +56 -0
- package/expansion-packs/bmad-creative-writing/workflows/novel-serial-workflow.yaml +50 -0
- package/expansion-packs/bmad-creative-writing/workflows/novel-snowflake-workflow.yaml +69 -0
- package/expansion-packs/bmad-creative-writing/workflows/novel-writing.yaml +91 -0
- package/expansion-packs/bmad-creative-writing/workflows/screenplay-development.yaml +85 -0
- package/expansion-packs/bmad-creative-writing/workflows/series-planning.yaml +78 -0
- package/expansion-packs/bmad-creative-writing/workflows/short-story-creation.yaml +64 -0
- package/expansion-packs/bmad-infrastructure-devops/README.md +147 -0
- package/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.md +73 -0
- package/expansion-packs/bmad-infrastructure-devops/checklists/infrastructure-checklist.md +486 -0
- package/expansion-packs/bmad-infrastructure-devops/config.yaml +10 -0
- package/expansion-packs/bmad-infrastructure-devops/data/bmad-kb.md +307 -0
- package/expansion-packs/bmad-infrastructure-devops/tasks/review-infrastructure.md +161 -0
- package/expansion-packs/bmad-infrastructure-devops/tasks/validate-infrastructure.md +155 -0
- package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-architecture-tmpl.yaml +425 -0
- package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.yaml +630 -0
- package/implement-fork-friendly-ci.sh +229 -0
- package/package.json +75 -45
- package/prettier.config.mjs +32 -0
- package/test.md +1 -0
- package/tools/builders/web-builder.js +143 -149
- package/tools/bump-all-versions.js +42 -33
- package/tools/bump-expansion-version.js +23 -16
- package/tools/cli.js +15 -15
- package/tools/flattener/aggregate.js +76 -0
- package/tools/flattener/binary.js +80 -0
- package/tools/flattener/discovery.js +71 -0
- package/tools/flattener/files.js +35 -0
- package/tools/flattener/ignoreRules.js +176 -0
- package/tools/flattener/main.js +458 -460
- package/tools/flattener/projectRoot.js +206 -0
- package/tools/flattener/prompts.js +44 -0
- package/tools/flattener/stats.helpers.js +395 -0
- package/tools/flattener/stats.js +80 -0
- package/tools/flattener/test-matrix.js +413 -0
- package/tools/flattener/xml.js +88 -0
- package/tools/installer/README.md +1 -1
- package/tools/installer/bin/xiaoma.js +390 -150
- package/tools/installer/config/ide-agent-config.yaml +1 -1
- package/tools/installer/config/install.config.yaml +60 -9
- package/tools/installer/lib/config-loader.js +55 -51
- package/tools/installer/lib/file-manager.js +92 -117
- package/tools/installer/lib/ide-base-setup.js +57 -56
- package/tools/installer/lib/ide-setup.js +821 -414
- package/tools/installer/lib/installer.js +924 -699
- package/tools/installer/lib/memory-profiler.js +54 -53
- package/tools/installer/lib/module-manager.js +19 -15
- package/tools/installer/lib/resource-locator.js +31 -33
- package/tools/installer/package.json +24 -23
- package/tools/lib/dependency-resolver.js +39 -43
- package/tools/lib/yaml-utils.js +7 -7
- package/tools/md-assets/web-agent-startup-instructions.md +6 -6
- package/tools/preview-release-notes.js +66 -0
- package/tools/setup-hooks.sh +37 -0
- package/tools/shared/bannerArt.js +105 -0
- package/tools/sync-installer-version.js +7 -9
- package/tools/sync-version.sh +23 -0
- package/tools/update-expansion-version.js +14 -15
- package/tools/upgraders/v3-to-v4-upgrader.js +203 -294
- package/tools/version-bump.js +41 -26
- package/tools/xiaoma-npx-wrapper.js +14 -14
- package/tools/yaml-format.js +56 -43
- package/xiaoma-core/agent-teams/team-all.yaml +3 -2
- package/xiaoma-core/agent-teams/team-fullstack.yaml +2 -1
- package/xiaoma-core/agent-teams/team-ide-minimal.yaml +1 -0
- package/xiaoma-core/agent-teams/team-no-ui.yaml +2 -1
- package/xiaoma-core/agents/analyst.md +20 -17
- package/xiaoma-core/agents/architect.md +15 -14
- package/xiaoma-core/agents/{xiaoma-master.md → bmad-master.md} +29 -27
- package/xiaoma-core/agents/{xiaoma-orchestrator.md → bmad-orchestrator.md} +36 -39
- package/xiaoma-core/agents/dev.md +23 -18
- package/xiaoma-core/agents/pm.md +18 -15
- package/xiaoma-core/agents/po.md +13 -10
- package/xiaoma-core/agents/qa.md +46 -24
- package/xiaoma-core/agents/sm.md +11 -8
- package/xiaoma-core/agents/ux-expert.md +10 -7
- package/xiaoma-core/checklists/architect-checklist.md +2 -5
- package/xiaoma-core/checklists/change-checklist.md +4 -2
- package/xiaoma-core/checklists/pm-checklist.md +2 -5
- package/xiaoma-core/checklists/po-master-checklist.md +2 -9
- package/xiaoma-core/checklists/story-dod-checklist.md +2 -7
- package/xiaoma-core/checklists/story-draft-checklist.md +2 -3
- package/xiaoma-core/core-config.yaml +4 -1
- package/xiaoma-core/data/{xiaoma-kb.md → bmad-kb.md} +48 -42
- package/xiaoma-core/data/brainstorming-techniques.md +2 -0
- package/xiaoma-core/data/elicitation-methods.md +22 -0
- package/xiaoma-core/data/technical-preferences.md +2 -0
- package/xiaoma-core/data/test-levels-framework.md +148 -0
- package/xiaoma-core/data/test-priorities-matrix.md +174 -0
- package/xiaoma-core/tasks/advanced-elicitation.md +2 -0
- package/xiaoma-core/tasks/apply-qa-fixes.md +150 -0
- package/xiaoma-core/tasks/brownfield-create-epic.md +2 -0
- package/xiaoma-core/tasks/brownfield-create-story.md +2 -0
- package/xiaoma-core/tasks/correct-course.md +2 -0
- package/xiaoma-core/tasks/create-brownfield-story.md +14 -4
- package/xiaoma-core/tasks/create-deep-research-prompt.md +2 -11
- package/xiaoma-core/tasks/create-next-story.md +3 -1
- package/xiaoma-core/tasks/document-project.md +17 -13
- package/xiaoma-core/tasks/facilitate-brainstorming-session.md +5 -3
- package/xiaoma-core/tasks/generate-ai-frontend-prompt.md +2 -0
- package/xiaoma-core/tasks/index-docs.md +2 -6
- package/xiaoma-core/tasks/kb-mode-interaction.md +17 -15
- package/xiaoma-core/tasks/nfr-assess.md +345 -0
- package/xiaoma-core/tasks/qa-gate.md +163 -0
- package/xiaoma-core/tasks/review-story.md +245 -74
- package/xiaoma-core/tasks/risk-profile.md +355 -0
- package/xiaoma-core/tasks/shard-doc.md +2 -2
- package/xiaoma-core/tasks/test-design.md +176 -0
- package/xiaoma-core/tasks/trace-requirements.md +266 -0
- package/xiaoma-core/tasks/validate-next-story.md +5 -3
- package/xiaoma-core/templates/architecture-tmpl.yaml +50 -49
- package/xiaoma-core/templates/brainstorming-output-tmpl.yaml +5 -5
- package/xiaoma-core/templates/brownfield-architecture-tmpl.yaml +32 -31
- package/xiaoma-core/templates/brownfield-prd-tmpl.yaml +14 -13
- package/xiaoma-core/templates/competitor-analysis-tmpl.yaml +20 -6
- package/xiaoma-core/templates/front-end-architecture-tmpl.yaml +22 -9
- package/xiaoma-core/templates/front-end-spec-tmpl.yaml +25 -24
- package/xiaoma-core/templates/fullstack-architecture-tmpl.yaml +123 -104
- package/xiaoma-core/templates/market-research-tmpl.yaml +3 -2
- package/xiaoma-core/templates/prd-tmpl.yaml +10 -9
- package/xiaoma-core/templates/project-brief-tmpl.yaml +5 -4
- package/xiaoma-core/templates/qa-gate-tmpl.yaml +103 -0
- package/xiaoma-core/templates/story-tmpl.yaml +13 -12
- package/xiaoma-core/workflows/brownfield-fullstack.yaml +13 -12
- package/xiaoma-core/workflows/brownfield-service.yaml +5 -4
- package/xiaoma-core/workflows/brownfield-ui.yaml +5 -4
- package/xiaoma-core/workflows/greenfield-fullstack.yaml +7 -6
- package/xiaoma-core/workflows/greenfield-service.yaml +5 -4
- package/xiaoma-core/workflows/greenfield-ui.yaml +6 -5
- package/.releaserc.json +0 -18
- package/README.md +0 -532
- package/XiaoMa-Web/345/244/232/346/231/272/350/203/275/344/275/2230-1/351/241/271/347/233/256/345/274/200/345/217/221/345/256/214/346/225/264/346/214/207/345/215/227.md +0 -977
- package/XiaoMa-Web/347/216/260/346/234/211/351/241/271/347/233/256/351/234/200/346/261/202/345/274/200/345/217/221/345/256/214/346/225/264/346/214/207/345/215/227.md +0 -873
- package/XiaoMa-Web/347/272/257/345/211/215/347/253/257/351/241/271/347/233/256Claude-Code/345/274/200/345/217/221/345/256/214/346/225/264/346/214/207/345/215/227.md +0 -372
- package/XiaoMa-Web/351/241/271/347/233/256/346/200/273/347/273/223/346/212/245/345/221/212.md +0 -310
- package/dist/agents/analyst.txt +0 -2882
- package/dist/agents/architect.txt +0 -3543
- package/dist/agents/dev-cn.txt +0 -428
- package/dist/agents/dev.txt +0 -428
- package/dist/agents/pm.txt +0 -2229
- package/dist/agents/po.txt +0 -1364
- package/dist/agents/qa.txt +0 -386
- package/dist/agents/sm.txt +0 -668
- package/dist/agents/ux-expert.txt +0 -701
- package/dist/agents/xiaoma-master.txt +0 -8756
- package/dist/agents/xiaoma-orchestrator.txt +0 -1490
- package/dist/teams/team-all.txt +0 -11062
- package/dist/teams/team-fullstack.txt +0 -10392
- package/dist/teams/team-ide-minimal.txt +0 -3507
- package/dist/teams/team-no-ui.txt +0 -8951
- package/docs/quick-start.md +0 -179
- package/tools/bmad-npx-wrapper.js +0 -39
- package/tools/installer/package-lock.json +0 -704
- package/tools/semantic-release-sync-installer.js +0 -30
- package/xiaoma-core/bmad-core/user-guide.md +0 -0
- package/xiaoma-core/enhanced-ide-development-workflow.md +0 -43
- package/xiaoma-core/user-guide.md +0 -251
- package/xiaoma-core/working-in-the-brownfield.md +0 -364
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
const path = require(
|
|
2
|
-
const fs = require(
|
|
3
|
-
const yaml = require(
|
|
4
|
-
const chalk = require(
|
|
5
|
-
const inquirer = require(
|
|
6
|
-
const fileManager = require(
|
|
7
|
-
const configLoader = require(
|
|
8
|
-
const { extractYamlFromAgent } = require(
|
|
9
|
-
const BaseIdeSetup = require(
|
|
10
|
-
const resourceLocator = require(
|
|
1
|
+
const path = require('node:path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const yaml = require('js-yaml');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const inquirer = require('inquirer');
|
|
6
|
+
const fileManager = require('./file-manager');
|
|
7
|
+
const configLoader = require('./config-loader');
|
|
8
|
+
const { extractYamlFromAgent } = require('../../lib/yaml-utils');
|
|
9
|
+
const BaseIdeSetup = require('./ide-base-setup');
|
|
10
|
+
const resourceLocator = require('./resource-locator');
|
|
11
11
|
|
|
12
12
|
class IdeSetup extends BaseIdeSetup {
|
|
13
13
|
constructor() {
|
|
@@ -17,17 +17,17 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
17
17
|
|
|
18
18
|
async loadIdeAgentConfig() {
|
|
19
19
|
if (this.ideAgentConfig) return this.ideAgentConfig;
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
try {
|
|
22
22
|
const configPath = path.join(__dirname, '..', 'config', 'ide-agent-config.yaml');
|
|
23
23
|
const configContent = await fs.readFile(configPath, 'utf8');
|
|
24
24
|
this.ideAgentConfig = yaml.load(configContent);
|
|
25
25
|
return this.ideAgentConfig;
|
|
26
|
-
} catch
|
|
26
|
+
} catch {
|
|
27
27
|
console.warn('Failed to load IDE agent configuration, using defaults');
|
|
28
28
|
return {
|
|
29
29
|
'roo-permissions': {},
|
|
30
|
-
'cline-order': {}
|
|
30
|
+
'cline-order': {},
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -41,34 +41,226 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
switch (ide) {
|
|
44
|
-
case
|
|
44
|
+
case 'cursor': {
|
|
45
45
|
return this.setupCursor(installDir, selectedAgent);
|
|
46
|
-
|
|
46
|
+
}
|
|
47
|
+
case 'claude-code': {
|
|
47
48
|
return this.setupClaudeCode(installDir, selectedAgent);
|
|
48
|
-
|
|
49
|
+
}
|
|
50
|
+
case 'crush': {
|
|
51
|
+
return this.setupCrush(installDir, selectedAgent);
|
|
52
|
+
}
|
|
53
|
+
case 'windsurf': {
|
|
49
54
|
return this.setupWindsurf(installDir, selectedAgent);
|
|
50
|
-
|
|
55
|
+
}
|
|
56
|
+
case 'trae': {
|
|
51
57
|
return this.setupTrae(installDir, selectedAgent);
|
|
52
|
-
|
|
58
|
+
}
|
|
59
|
+
case 'roo': {
|
|
53
60
|
return this.setupRoo(installDir, selectedAgent);
|
|
54
|
-
|
|
61
|
+
}
|
|
62
|
+
case 'cline': {
|
|
55
63
|
return this.setupCline(installDir, selectedAgent);
|
|
56
|
-
|
|
64
|
+
}
|
|
65
|
+
case 'kilo': {
|
|
57
66
|
return this.setupKilocode(installDir, selectedAgent);
|
|
58
|
-
|
|
67
|
+
}
|
|
68
|
+
case 'gemini': {
|
|
59
69
|
return this.setupGeminiCli(installDir, selectedAgent);
|
|
60
|
-
|
|
70
|
+
}
|
|
71
|
+
case 'github-copilot': {
|
|
61
72
|
return this.setupGitHubCopilot(installDir, selectedAgent, spinner, preConfiguredSettings);
|
|
62
|
-
|
|
73
|
+
}
|
|
74
|
+
case 'qwen-code': {
|
|
63
75
|
return this.setupQwenCode(installDir, selectedAgent);
|
|
64
|
-
|
|
76
|
+
}
|
|
77
|
+
case 'auggie-cli': {
|
|
78
|
+
return this.setupAuggieCLI(installDir, selectedAgent, spinner, preConfiguredSettings);
|
|
79
|
+
}
|
|
80
|
+
case 'codex': {
|
|
81
|
+
return this.setupCodex(installDir, selectedAgent, { webEnabled: false });
|
|
82
|
+
}
|
|
83
|
+
case 'codex-web': {
|
|
84
|
+
return this.setupCodex(installDir, selectedAgent, { webEnabled: true });
|
|
85
|
+
}
|
|
86
|
+
default: {
|
|
65
87
|
console.log(chalk.yellow(`\nIDE ${ide} not yet supported`));
|
|
66
88
|
return false;
|
|
89
|
+
}
|
|
67
90
|
}
|
|
68
91
|
}
|
|
69
92
|
|
|
93
|
+
async setupCodex(installDir, selectedAgent, options) {
|
|
94
|
+
options = options ?? { webEnabled: false };
|
|
95
|
+
// Codex reads AGENTS.md at the project root as project memory (CLI & Web).
|
|
96
|
+
// Inject/update a BMAD section with guidance, directory, and details.
|
|
97
|
+
const filePath = path.join(installDir, 'AGENTS.md');
|
|
98
|
+
const startMarker = '<!-- BEGIN: BMAD-AGENTS -->';
|
|
99
|
+
const endMarker = '<!-- END: BMAD-AGENTS -->';
|
|
100
|
+
|
|
101
|
+
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
102
|
+
const tasks = await this.getAllTaskIds(installDir);
|
|
103
|
+
|
|
104
|
+
// Build BMAD section content
|
|
105
|
+
let section = '';
|
|
106
|
+
section += `${startMarker}\n`;
|
|
107
|
+
section += `# BMAD-METHOD Agents and Tasks\n\n`;
|
|
108
|
+
section += `This section is auto-generated by BMAD-METHOD for Codex. Codex merges this AGENTS.md into context.\n\n`;
|
|
109
|
+
section += `## How To Use With Codex\n\n`;
|
|
110
|
+
section += `- Codex CLI: run \`codex\` in this project. Reference an agent naturally, e.g., "As dev, implement ...".\n`;
|
|
111
|
+
section += `- Codex Web: open this repo and reference roles the same way; Codex reads \`AGENTS.md\`.\n`;
|
|
112
|
+
section += `- Commit \`.bmad-core\` and this \`AGENTS.md\` file to your repo so Codex (Web/CLI) can read full agent definitions.\n`;
|
|
113
|
+
section += `- Refresh this section after agent updates: \`npx xiaoma-cli install -f -i codex\`.\n\n`;
|
|
114
|
+
|
|
115
|
+
section += `### Helpful Commands\n\n`;
|
|
116
|
+
section += `- List agents: \`npx xiaoma-cli list:agents\`\n`;
|
|
117
|
+
section += `- Reinstall BMAD core and regenerate AGENTS.md: \`npx xiaoma-cli install -f -i codex\`\n`;
|
|
118
|
+
section += `- Validate configuration: \`npx xiaoma-cli validate\`\n\n`;
|
|
119
|
+
|
|
120
|
+
// Agents directory table
|
|
121
|
+
section += `## Agents\n\n`;
|
|
122
|
+
section += `### Directory\n\n`;
|
|
123
|
+
section += `| Title | ID | When To Use |\n|---|---|---|\n`;
|
|
124
|
+
const agentSummaries = [];
|
|
125
|
+
for (const agentId of agents) {
|
|
126
|
+
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
127
|
+
if (!agentPath) continue;
|
|
128
|
+
const raw = await fileManager.readFile(agentPath);
|
|
129
|
+
const yamlMatch = raw.match(/```ya?ml\r?\n([\s\S]*?)```/);
|
|
130
|
+
const yamlBlock = yamlMatch ? yamlMatch[1].trim() : null;
|
|
131
|
+
const title = await this.getAgentTitle(agentId, installDir);
|
|
132
|
+
const whenToUse = yamlBlock?.match(/whenToUse:\s*"?([^\n"]+)"?/i)?.[1]?.trim() || '';
|
|
133
|
+
agentSummaries.push({ agentId, title, whenToUse, yamlBlock, raw, path: agentPath });
|
|
134
|
+
section += `| ${title} | ${agentId} | ${whenToUse || '—'} |\n`;
|
|
135
|
+
}
|
|
136
|
+
section += `\n`;
|
|
137
|
+
|
|
138
|
+
// Detailed agent sections
|
|
139
|
+
for (const { agentId, title, whenToUse, yamlBlock, raw, path: agentPath } of agentSummaries) {
|
|
140
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
141
|
+
section += `### ${title} (id: ${agentId})\n`;
|
|
142
|
+
section += `Source: ${relativePath}\n\n`;
|
|
143
|
+
if (whenToUse) section += `- When to use: ${whenToUse}\n`;
|
|
144
|
+
section += `- How to activate: Mention "As ${agentId}, ..." or "Use ${title} to ..."\n\n`;
|
|
145
|
+
if (yamlBlock) {
|
|
146
|
+
section += '```yaml\n' + yamlBlock + '\n```\n\n';
|
|
147
|
+
} else {
|
|
148
|
+
section += '```md\n' + raw.trim() + '\n```\n\n';
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Tasks
|
|
153
|
+
if (tasks && tasks.length > 0) {
|
|
154
|
+
section += `## Tasks\n\n`;
|
|
155
|
+
section += `These are reusable task briefs you can reference directly in Codex.\n\n`;
|
|
156
|
+
for (const taskId of tasks) {
|
|
157
|
+
const taskPath = await this.findTaskPath(taskId, installDir);
|
|
158
|
+
if (!taskPath) continue;
|
|
159
|
+
const raw = await fileManager.readFile(taskPath);
|
|
160
|
+
const relativePath = path.relative(installDir, taskPath).replaceAll('\\', '/');
|
|
161
|
+
section += `### Task: ${taskId}\n`;
|
|
162
|
+
section += `Source: ${relativePath}\n`;
|
|
163
|
+
section += `- How to use: "Use task ${taskId} with the appropriate agent" and paste relevant parts as needed.\n\n`;
|
|
164
|
+
section += '```md\n' + raw.trim() + '\n```\n\n';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
section += `${endMarker}\n`;
|
|
169
|
+
|
|
170
|
+
// Write or update AGENTS.md
|
|
171
|
+
let finalContent = '';
|
|
172
|
+
if (await fileManager.pathExists(filePath)) {
|
|
173
|
+
const existing = await fileManager.readFile(filePath);
|
|
174
|
+
if (existing.includes(startMarker) && existing.includes(endMarker)) {
|
|
175
|
+
// Replace existing BMAD block
|
|
176
|
+
const pattern = String.raw`${startMarker}[\s\S]*?${endMarker}`;
|
|
177
|
+
const replaced = existing.replace(new RegExp(pattern, 'm'), section);
|
|
178
|
+
finalContent = replaced;
|
|
179
|
+
} else {
|
|
180
|
+
// Append BMAD block to existing file
|
|
181
|
+
finalContent = existing.trimEnd() + `\n\n` + section;
|
|
182
|
+
}
|
|
183
|
+
} else {
|
|
184
|
+
// Create fresh AGENTS.md with a small header and BMAD block
|
|
185
|
+
finalContent += '# Project Agents\n\n';
|
|
186
|
+
finalContent += 'This file provides guidance and memory for Codex CLI.\n\n';
|
|
187
|
+
finalContent += section;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
await fileManager.writeFile(filePath, finalContent);
|
|
191
|
+
console.log(chalk.green('✓ Created/updated AGENTS.md for Codex CLI integration'));
|
|
192
|
+
console.log(
|
|
193
|
+
chalk.dim(
|
|
194
|
+
'Codex reads AGENTS.md automatically. Run `codex` in this project to use BMAD agents.',
|
|
195
|
+
),
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
// Optionally add helpful npm scripts if a package.json exists
|
|
199
|
+
try {
|
|
200
|
+
const pkgPath = path.join(installDir, 'package.json');
|
|
201
|
+
if (await fileManager.pathExists(pkgPath)) {
|
|
202
|
+
const pkgRaw = await fileManager.readFile(pkgPath);
|
|
203
|
+
const pkg = JSON.parse(pkgRaw);
|
|
204
|
+
pkg.scripts = pkg.scripts || {};
|
|
205
|
+
const updated = { ...pkg.scripts };
|
|
206
|
+
if (!updated['bmad:refresh']) updated['bmad:refresh'] = 'xiaoma-cli install -f -i codex';
|
|
207
|
+
if (!updated['bmad:list']) updated['bmad:list'] = 'xiaoma-cli list:agents';
|
|
208
|
+
if (!updated['bmad:validate']) updated['bmad:validate'] = 'xiaoma-cli validate';
|
|
209
|
+
const changed = JSON.stringify(updated) !== JSON.stringify(pkg.scripts);
|
|
210
|
+
if (changed) {
|
|
211
|
+
const newPkg = { ...pkg, scripts: updated };
|
|
212
|
+
await fileManager.writeFile(pkgPath, JSON.stringify(newPkg, null, 2) + '\n');
|
|
213
|
+
console.log(chalk.green('✓ Added npm scripts: bmad:refresh, bmad:list, bmad:validate'));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
} catch {
|
|
217
|
+
console.log(
|
|
218
|
+
chalk.yellow('⚠︎ Skipped adding npm scripts (package.json not writable or invalid)'),
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Adjust .gitignore behavior depending on Codex mode
|
|
223
|
+
try {
|
|
224
|
+
const gitignorePath = path.join(installDir, '.gitignore');
|
|
225
|
+
const ignoreLines = ['# BMAD (local only)', '.bmad-core/', '.bmad-*/'];
|
|
226
|
+
const exists = await fileManager.pathExists(gitignorePath);
|
|
227
|
+
if (options.webEnabled) {
|
|
228
|
+
if (exists) {
|
|
229
|
+
let gi = await fileManager.readFile(gitignorePath);
|
|
230
|
+
// Remove lines that ignore BMAD dot-folders
|
|
231
|
+
const updated = gi
|
|
232
|
+
.split(/\r?\n/)
|
|
233
|
+
.filter((l) => !/^\s*\.bmad-core\/?\s*$/.test(l) && !/^\s*\.bmad-\*\/?\s*$/.test(l))
|
|
234
|
+
.join('\n');
|
|
235
|
+
if (updated !== gi) {
|
|
236
|
+
await fileManager.writeFile(gitignorePath, updated.trimEnd() + '\n');
|
|
237
|
+
console.log(chalk.green('✓ Updated .gitignore to include .bmad-core in commits'));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
// Local-only: add ignores if missing
|
|
242
|
+
let base = exists ? await fileManager.readFile(gitignorePath) : '';
|
|
243
|
+
const haveCore = base.includes('.bmad-core/');
|
|
244
|
+
const haveStar = base.includes('.bmad-*/');
|
|
245
|
+
if (!haveCore || !haveStar) {
|
|
246
|
+
const sep = base.endsWith('\n') || base.length === 0 ? '' : '\n';
|
|
247
|
+
const add = [!haveCore || !haveStar ? ignoreLines.join('\n') : '']
|
|
248
|
+
.filter(Boolean)
|
|
249
|
+
.join('\n');
|
|
250
|
+
const out = base + sep + add + '\n';
|
|
251
|
+
await fileManager.writeFile(gitignorePath, out);
|
|
252
|
+
console.log(chalk.green('✓ Added .bmad-core/* to .gitignore for local-only Codex setup'));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
} catch {
|
|
256
|
+
console.log(chalk.yellow('⚠︎ Could not update .gitignore (skipping)'));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
|
|
70
262
|
async setupCursor(installDir, selectedAgent) {
|
|
71
|
-
const cursorRulesDir = path.join(installDir,
|
|
263
|
+
const cursorRulesDir = path.join(installDir, '.cursor', 'rules', 'bmad');
|
|
72
264
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
73
265
|
|
|
74
266
|
await fileManager.ensureDirectory(cursorRulesDir);
|
|
@@ -88,19 +280,57 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
88
280
|
return true;
|
|
89
281
|
}
|
|
90
282
|
|
|
91
|
-
async
|
|
92
|
-
//
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
283
|
+
async setupCrush(installDir, selectedAgent) {
|
|
284
|
+
// Setup bmad-core commands
|
|
285
|
+
const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
|
|
286
|
+
const coreAgents = selectedAgent ? [selectedAgent] : await this.getCoreAgentIds(installDir);
|
|
287
|
+
const coreTasks = await this.getCoreTaskIds(installDir);
|
|
288
|
+
await this.setupCrushForPackage(
|
|
289
|
+
installDir,
|
|
290
|
+
'core',
|
|
291
|
+
coreSlashPrefix,
|
|
292
|
+
coreAgents,
|
|
293
|
+
coreTasks,
|
|
294
|
+
'.bmad-core',
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
// Setup expansion pack commands
|
|
298
|
+
const expansionPacks = await this.getInstalledExpansionPacks(installDir);
|
|
299
|
+
for (const packInfo of expansionPacks) {
|
|
300
|
+
const packSlashPrefix = await this.getExpansionPackSlashPrefix(packInfo.path);
|
|
301
|
+
const packAgents = await this.getExpansionPackAgents(packInfo.path);
|
|
302
|
+
const packTasks = await this.getExpansionPackTasks(packInfo.path);
|
|
303
|
+
|
|
304
|
+
if (packAgents.length > 0 || packTasks.length > 0) {
|
|
305
|
+
// Use the actual directory name where the expansion pack is installed
|
|
306
|
+
const rootPath = path.relative(installDir, packInfo.path);
|
|
307
|
+
await this.setupCrushForPackage(
|
|
308
|
+
installDir,
|
|
309
|
+
packInfo.name,
|
|
310
|
+
packSlashPrefix,
|
|
311
|
+
packAgents,
|
|
312
|
+
packTasks,
|
|
313
|
+
rootPath,
|
|
314
|
+
);
|
|
315
|
+
}
|
|
97
316
|
}
|
|
98
317
|
|
|
99
|
-
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async setupClaudeCode(installDir, selectedAgent) {
|
|
322
|
+
// Setup bmad-core commands
|
|
100
323
|
const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
|
|
101
324
|
const coreAgents = selectedAgent ? [selectedAgent] : await this.getCoreAgentIds(installDir);
|
|
102
325
|
const coreTasks = await this.getCoreTaskIds(installDir);
|
|
103
|
-
await this.setupClaudeCodeForPackage(
|
|
326
|
+
await this.setupClaudeCodeForPackage(
|
|
327
|
+
installDir,
|
|
328
|
+
'core',
|
|
329
|
+
coreSlashPrefix,
|
|
330
|
+
coreAgents,
|
|
331
|
+
coreTasks,
|
|
332
|
+
'.bmad-core',
|
|
333
|
+
);
|
|
104
334
|
|
|
105
335
|
// Setup expansion pack commands
|
|
106
336
|
const expansionPacks = await this.getInstalledExpansionPacks(installDir);
|
|
@@ -108,21 +338,35 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
108
338
|
const packSlashPrefix = await this.getExpansionPackSlashPrefix(packInfo.path);
|
|
109
339
|
const packAgents = await this.getExpansionPackAgents(packInfo.path);
|
|
110
340
|
const packTasks = await this.getExpansionPackTasks(packInfo.path);
|
|
111
|
-
|
|
341
|
+
|
|
112
342
|
if (packAgents.length > 0 || packTasks.length > 0) {
|
|
113
343
|
// Use the actual directory name where the expansion pack is installed
|
|
114
344
|
const rootPath = path.relative(installDir, packInfo.path);
|
|
115
|
-
await this.setupClaudeCodeForPackage(
|
|
345
|
+
await this.setupClaudeCodeForPackage(
|
|
346
|
+
installDir,
|
|
347
|
+
packInfo.name,
|
|
348
|
+
packSlashPrefix,
|
|
349
|
+
packAgents,
|
|
350
|
+
packTasks,
|
|
351
|
+
rootPath,
|
|
352
|
+
);
|
|
116
353
|
}
|
|
117
354
|
}
|
|
118
355
|
|
|
119
356
|
return true;
|
|
120
357
|
}
|
|
121
358
|
|
|
122
|
-
async setupClaudeCodeForPackage(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
359
|
+
async setupClaudeCodeForPackage(
|
|
360
|
+
installDir,
|
|
361
|
+
packageName,
|
|
362
|
+
slashPrefix,
|
|
363
|
+
agentIds,
|
|
364
|
+
taskIds,
|
|
365
|
+
rootPath,
|
|
366
|
+
) {
|
|
367
|
+
const commandsBaseDir = path.join(installDir, '.claude', 'commands', slashPrefix);
|
|
368
|
+
const agentsDir = path.join(commandsBaseDir, 'agents');
|
|
369
|
+
const tasksDir = path.join(commandsBaseDir, 'tasks');
|
|
126
370
|
|
|
127
371
|
// Ensure directories exist
|
|
128
372
|
await fileManager.ensureDirectory(agentsDir);
|
|
@@ -132,28 +376,28 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
132
376
|
for (const agentId of agentIds) {
|
|
133
377
|
// Find the agent file - for expansion packs, prefer the expansion pack version
|
|
134
378
|
let agentPath;
|
|
135
|
-
if (packageName
|
|
379
|
+
if (packageName === 'core') {
|
|
380
|
+
// For core, use the normal search
|
|
381
|
+
agentPath = await this.findAgentPath(agentId, installDir);
|
|
382
|
+
} else {
|
|
136
383
|
// For expansion packs, first try to find the agent in the expansion pack directory
|
|
137
|
-
const expansionPackPath = path.join(installDir, rootPath,
|
|
384
|
+
const expansionPackPath = path.join(installDir, rootPath, 'agents', `${agentId}.md`);
|
|
138
385
|
if (await fileManager.pathExists(expansionPackPath)) {
|
|
139
386
|
agentPath = expansionPackPath;
|
|
140
387
|
} else {
|
|
141
388
|
// Fall back to core if not found in expansion pack
|
|
142
389
|
agentPath = await this.findAgentPath(agentId, installDir);
|
|
143
390
|
}
|
|
144
|
-
} else {
|
|
145
|
-
// For core, use the normal search
|
|
146
|
-
agentPath = await this.findAgentPath(agentId, installDir);
|
|
147
391
|
}
|
|
148
|
-
|
|
392
|
+
|
|
149
393
|
const commandPath = path.join(agentsDir, `${agentId}.md`);
|
|
150
394
|
|
|
151
395
|
if (agentPath) {
|
|
152
396
|
// Create command file with agent content
|
|
153
397
|
let agentContent = await fileManager.readFile(agentPath);
|
|
154
|
-
|
|
398
|
+
|
|
155
399
|
// Replace {root} placeholder with the appropriate root path for this context
|
|
156
|
-
agentContent = agentContent.
|
|
400
|
+
agentContent = agentContent.replaceAll('{root}', rootPath);
|
|
157
401
|
|
|
158
402
|
// Add command header
|
|
159
403
|
let commandContent = `# /${agentId} Command\n\n`;
|
|
@@ -169,28 +413,118 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
169
413
|
for (const taskId of taskIds) {
|
|
170
414
|
// Find the task file - for expansion packs, prefer the expansion pack version
|
|
171
415
|
let taskPath;
|
|
172
|
-
if (packageName
|
|
416
|
+
if (packageName === 'core') {
|
|
417
|
+
// For core, use the normal search
|
|
418
|
+
taskPath = await this.findTaskPath(taskId, installDir);
|
|
419
|
+
} else {
|
|
173
420
|
// For expansion packs, first try to find the task in the expansion pack directory
|
|
174
|
-
const expansionPackPath = path.join(installDir, rootPath,
|
|
421
|
+
const expansionPackPath = path.join(installDir, rootPath, 'tasks', `${taskId}.md`);
|
|
175
422
|
if (await fileManager.pathExists(expansionPackPath)) {
|
|
176
423
|
taskPath = expansionPackPath;
|
|
177
424
|
} else {
|
|
178
425
|
// Fall back to core if not found in expansion pack
|
|
179
426
|
taskPath = await this.findTaskPath(taskId, installDir);
|
|
180
427
|
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const commandPath = path.join(tasksDir, `${taskId}.md`);
|
|
431
|
+
|
|
432
|
+
if (taskPath) {
|
|
433
|
+
// Create command file with task content
|
|
434
|
+
let taskContent = await fileManager.readFile(taskPath);
|
|
435
|
+
|
|
436
|
+
// Replace {root} placeholder with the appropriate root path for this context
|
|
437
|
+
taskContent = taskContent.replaceAll('{root}', rootPath);
|
|
438
|
+
|
|
439
|
+
// Add command header
|
|
440
|
+
let commandContent = `# /${taskId} Task\n\n`;
|
|
441
|
+
commandContent += `When this command is used, execute the following task:\n\n`;
|
|
442
|
+
commandContent += taskContent;
|
|
443
|
+
|
|
444
|
+
await fileManager.writeFile(commandPath, commandContent);
|
|
445
|
+
console.log(chalk.green(`✓ Created task command: /${taskId}`));
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
console.log(
|
|
450
|
+
chalk.green(`\n✓ Created Claude Code commands for ${packageName} in ${commandsBaseDir}`),
|
|
451
|
+
);
|
|
452
|
+
console.log(chalk.dim(` - Agents in: ${agentsDir}`));
|
|
453
|
+
console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
async setupCrushForPackage(installDir, packageName, slashPrefix, agentIds, taskIds, rootPath) {
|
|
457
|
+
const commandsBaseDir = path.join(installDir, '.crush', 'commands', slashPrefix);
|
|
458
|
+
const agentsDir = path.join(commandsBaseDir, 'agents');
|
|
459
|
+
const tasksDir = path.join(commandsBaseDir, 'tasks');
|
|
460
|
+
|
|
461
|
+
// Ensure directories exist
|
|
462
|
+
await fileManager.ensureDirectory(agentsDir);
|
|
463
|
+
await fileManager.ensureDirectory(tasksDir);
|
|
464
|
+
|
|
465
|
+
// Setup agents
|
|
466
|
+
for (const agentId of agentIds) {
|
|
467
|
+
// Find the agent file - for expansion packs, prefer the expansion pack version
|
|
468
|
+
let agentPath;
|
|
469
|
+
if (packageName === 'core') {
|
|
470
|
+
// For core, use the normal search
|
|
471
|
+
agentPath = await this.findAgentPath(agentId, installDir);
|
|
181
472
|
} else {
|
|
473
|
+
// For expansion packs, first try to find the agent in the expansion pack directory
|
|
474
|
+
const expansionPackPath = path.join(installDir, rootPath, 'agents', `${agentId}.md`);
|
|
475
|
+
if (await fileManager.pathExists(expansionPackPath)) {
|
|
476
|
+
agentPath = expansionPackPath;
|
|
477
|
+
} else {
|
|
478
|
+
// Fall back to core if not found in expansion pack
|
|
479
|
+
agentPath = await this.findAgentPath(agentId, installDir);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const commandPath = path.join(agentsDir, `${agentId}.md`);
|
|
484
|
+
|
|
485
|
+
if (agentPath) {
|
|
486
|
+
// Create command file with agent content
|
|
487
|
+
let agentContent = await fileManager.readFile(agentPath);
|
|
488
|
+
|
|
489
|
+
// Replace {root} placeholder with the appropriate root path for this context
|
|
490
|
+
agentContent = agentContent.replaceAll('{root}', rootPath);
|
|
491
|
+
|
|
492
|
+
// Add command header
|
|
493
|
+
let commandContent = `# /${agentId} Command\n\n`;
|
|
494
|
+
commandContent += `When this command is used, adopt the following agent persona:\n\n`;
|
|
495
|
+
commandContent += agentContent;
|
|
496
|
+
|
|
497
|
+
await fileManager.writeFile(commandPath, commandContent);
|
|
498
|
+
console.log(chalk.green(`✓ Created agent command: /${agentId}`));
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Setup tasks
|
|
503
|
+
for (const taskId of taskIds) {
|
|
504
|
+
// Find the task file - for expansion packs, prefer the expansion pack version
|
|
505
|
+
let taskPath;
|
|
506
|
+
if (packageName === 'core') {
|
|
182
507
|
// For core, use the normal search
|
|
183
508
|
taskPath = await this.findTaskPath(taskId, installDir);
|
|
509
|
+
} else {
|
|
510
|
+
// For expansion packs, first try to find the task in the expansion pack directory
|
|
511
|
+
const expansionPackPath = path.join(installDir, rootPath, 'tasks', `${taskId}.md`);
|
|
512
|
+
if (await fileManager.pathExists(expansionPackPath)) {
|
|
513
|
+
taskPath = expansionPackPath;
|
|
514
|
+
} else {
|
|
515
|
+
// Fall back to core if not found in expansion pack
|
|
516
|
+
taskPath = await this.findTaskPath(taskId, installDir);
|
|
517
|
+
}
|
|
184
518
|
}
|
|
185
|
-
|
|
519
|
+
|
|
186
520
|
const commandPath = path.join(tasksDir, `${taskId}.md`);
|
|
187
521
|
|
|
188
522
|
if (taskPath) {
|
|
189
523
|
// Create command file with task content
|
|
190
524
|
let taskContent = await fileManager.readFile(taskPath);
|
|
191
|
-
|
|
525
|
+
|
|
192
526
|
// Replace {root} placeholder with the appropriate root path for this context
|
|
193
|
-
taskContent = taskContent.
|
|
527
|
+
taskContent = taskContent.replaceAll('{root}', rootPath);
|
|
194
528
|
|
|
195
529
|
// Add command header
|
|
196
530
|
let commandContent = `# /${taskId} Task\n\n`;
|
|
@@ -202,16 +536,16 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
202
536
|
}
|
|
203
537
|
}
|
|
204
538
|
|
|
205
|
-
console.log(chalk.green(`\n✓ Created
|
|
539
|
+
console.log(chalk.green(`\n✓ Created Crush commands for ${packageName} in ${commandsBaseDir}`));
|
|
206
540
|
console.log(chalk.dim(` - Agents in: ${agentsDir}`));
|
|
207
541
|
console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
|
|
208
542
|
}
|
|
209
543
|
|
|
210
544
|
async setupWindsurf(installDir, selectedAgent) {
|
|
211
|
-
const
|
|
545
|
+
const windsurfWorkflowDir = path.join(installDir, '.windsurf', 'workflows');
|
|
212
546
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
213
547
|
|
|
214
|
-
await fileManager.ensureDirectory(
|
|
548
|
+
await fileManager.ensureDirectory(windsurfWorkflowDir);
|
|
215
549
|
|
|
216
550
|
for (const agentId of agents) {
|
|
217
551
|
// Find the agent file
|
|
@@ -219,89 +553,67 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
219
553
|
|
|
220
554
|
if (agentPath) {
|
|
221
555
|
const agentContent = await fileManager.readFile(agentPath);
|
|
222
|
-
const mdPath = path.join(
|
|
556
|
+
const mdPath = path.join(windsurfWorkflowDir, `${agentId}.md`);
|
|
223
557
|
|
|
224
|
-
//
|
|
225
|
-
let mdContent =
|
|
226
|
-
mdContent += `
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
mdContent += "## Agent Activation\n\n";
|
|
231
|
-
mdContent +=
|
|
232
|
-
"CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n";
|
|
233
|
-
mdContent += "```yaml\n";
|
|
234
|
-
// Extract just the YAML content from the agent file
|
|
235
|
-
const yamlContent = extractYamlFromAgent(agentContent);
|
|
236
|
-
if (yamlContent) {
|
|
237
|
-
mdContent += yamlContent;
|
|
238
|
-
} else {
|
|
239
|
-
// If no YAML found, include the whole content minus the header
|
|
240
|
-
mdContent += agentContent.replace(/^#.*$/m, "").trim();
|
|
241
|
-
}
|
|
242
|
-
mdContent += "\n```\n\n";
|
|
243
|
-
mdContent += "## File Reference\n\n";
|
|
244
|
-
const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
|
|
245
|
-
mdContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
|
|
246
|
-
mdContent += "## Usage\n\n";
|
|
247
|
-
mdContent += `When the user types \`@${agentId}\`, activate this ${await this.getAgentTitle(
|
|
248
|
-
agentId,
|
|
249
|
-
installDir
|
|
250
|
-
)} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
558
|
+
// Write the agent file contents prefixed with Windsurf frontmatter
|
|
559
|
+
let mdContent = `---\n`;
|
|
560
|
+
mdContent += `description: ${agentId}\n`;
|
|
561
|
+
mdContent += `auto_execution_mode: 3\n`;
|
|
562
|
+
mdContent += `---\n\n`;
|
|
563
|
+
mdContent += agentContent;
|
|
251
564
|
|
|
252
565
|
await fileManager.writeFile(mdPath, mdContent);
|
|
253
|
-
console.log(chalk.green(`✓ Created
|
|
566
|
+
console.log(chalk.green(`✓ Created workflow: ${agentId}.md`));
|
|
254
567
|
}
|
|
255
568
|
}
|
|
256
569
|
|
|
257
|
-
console.log(chalk.green(`\n✓ Created Windsurf
|
|
570
|
+
console.log(chalk.green(`\n✓ Created Windsurf workflows in ${windsurfWorkflowDir}`));
|
|
258
571
|
|
|
259
572
|
return true;
|
|
260
573
|
}
|
|
261
574
|
|
|
262
575
|
async setupTrae(installDir, selectedAgent) {
|
|
263
|
-
const traeRulesDir = path.join(installDir,
|
|
264
|
-
const agents = selectedAgent? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
265
|
-
|
|
576
|
+
const traeRulesDir = path.join(installDir, '.trae', 'rules');
|
|
577
|
+
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
578
|
+
|
|
266
579
|
await fileManager.ensureDirectory(traeRulesDir);
|
|
267
|
-
|
|
580
|
+
|
|
268
581
|
for (const agentId of agents) {
|
|
269
582
|
// Find the agent file
|
|
270
583
|
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
271
|
-
|
|
584
|
+
|
|
272
585
|
if (agentPath) {
|
|
273
586
|
const agentContent = await fileManager.readFile(agentPath);
|
|
274
587
|
const mdPath = path.join(traeRulesDir, `${agentId}.md`);
|
|
275
|
-
|
|
588
|
+
|
|
276
589
|
// Create MD content (similar to Cursor but without frontmatter)
|
|
277
590
|
let mdContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
278
591
|
mdContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${await this.getAgentTitle(
|
|
279
592
|
agentId,
|
|
280
|
-
installDir
|
|
593
|
+
installDir,
|
|
281
594
|
)} agent persona.\n\n`;
|
|
282
|
-
mdContent +=
|
|
595
|
+
mdContent += '## Agent Activation\n\n';
|
|
283
596
|
mdContent +=
|
|
284
|
-
|
|
285
|
-
mdContent +=
|
|
597
|
+
'CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n';
|
|
598
|
+
mdContent += '```yaml\n';
|
|
286
599
|
// Extract just the YAML content from the agent file
|
|
287
600
|
const yamlContent = extractYamlFromAgent(agentContent);
|
|
288
601
|
if (yamlContent) {
|
|
289
602
|
mdContent += yamlContent;
|
|
290
|
-
}
|
|
291
|
-
else {
|
|
603
|
+
} else {
|
|
292
604
|
// If no YAML found, include the whole content minus the header
|
|
293
|
-
mdContent += agentContent.replace(/^#.*$/m,
|
|
605
|
+
mdContent += agentContent.replace(/^#.*$/m, '').trim();
|
|
294
606
|
}
|
|
295
|
-
mdContent +=
|
|
296
|
-
mdContent +=
|
|
297
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
607
|
+
mdContent += '\n```\n\n';
|
|
608
|
+
mdContent += '## File Reference\n\n';
|
|
609
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
298
610
|
mdContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
|
|
299
|
-
mdContent +=
|
|
611
|
+
mdContent += '## Usage\n\n';
|
|
300
612
|
mdContent += `When the user types \`@${agentId}\`, activate this ${await this.getAgentTitle(
|
|
301
613
|
agentId,
|
|
302
|
-
installDir
|
|
614
|
+
installDir,
|
|
303
615
|
)} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
304
|
-
|
|
616
|
+
|
|
305
617
|
await fileManager.writeFile(mdPath, mdContent);
|
|
306
618
|
console.log(chalk.green(`✓ Created rule: ${agentId}.md`));
|
|
307
619
|
}
|
|
@@ -311,116 +623,116 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
311
623
|
async findAgentPath(agentId, installDir) {
|
|
312
624
|
// Try to find the agent file in various locations
|
|
313
625
|
const possiblePaths = [
|
|
314
|
-
path.join(installDir,
|
|
315
|
-
path.join(installDir,
|
|
626
|
+
path.join(installDir, '.bmad-core', 'agents', `${agentId}.md`),
|
|
627
|
+
path.join(installDir, 'agents', `${agentId}.md`),
|
|
316
628
|
];
|
|
317
|
-
|
|
629
|
+
|
|
318
630
|
// Also check expansion pack directories
|
|
319
|
-
const glob = require(
|
|
320
|
-
const
|
|
321
|
-
for (const expDir of
|
|
631
|
+
const glob = require('glob');
|
|
632
|
+
const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
|
|
633
|
+
for (const expDir of expansionDirectories) {
|
|
322
634
|
possiblePaths.push(path.join(installDir, expDir, `${agentId}.md`));
|
|
323
635
|
}
|
|
324
|
-
|
|
636
|
+
|
|
325
637
|
for (const agentPath of possiblePaths) {
|
|
326
638
|
if (await fileManager.pathExists(agentPath)) {
|
|
327
639
|
return agentPath;
|
|
328
640
|
}
|
|
329
641
|
}
|
|
330
|
-
|
|
642
|
+
|
|
331
643
|
return null;
|
|
332
644
|
}
|
|
333
645
|
|
|
334
646
|
async getAllAgentIds(installDir) {
|
|
335
|
-
const glob = require(
|
|
647
|
+
const glob = require('glob');
|
|
336
648
|
const allAgentIds = [];
|
|
337
|
-
|
|
338
|
-
// Check core agents in .
|
|
339
|
-
let agentsDir = path.join(installDir,
|
|
649
|
+
|
|
650
|
+
// Check core agents in .bmad-core or root
|
|
651
|
+
let agentsDir = path.join(installDir, '.bmad-core', 'agents');
|
|
340
652
|
if (!(await fileManager.pathExists(agentsDir))) {
|
|
341
|
-
agentsDir = path.join(installDir,
|
|
653
|
+
agentsDir = path.join(installDir, 'agents');
|
|
342
654
|
}
|
|
343
|
-
|
|
655
|
+
|
|
344
656
|
if (await fileManager.pathExists(agentsDir)) {
|
|
345
|
-
const agentFiles = glob.sync(
|
|
346
|
-
allAgentIds.push(...agentFiles.map((file) => path.basename(file,
|
|
657
|
+
const agentFiles = glob.sync('*.md', { cwd: agentsDir });
|
|
658
|
+
allAgentIds.push(...agentFiles.map((file) => path.basename(file, '.md')));
|
|
347
659
|
}
|
|
348
|
-
|
|
660
|
+
|
|
349
661
|
// Also check for expansion pack agents in dot folders
|
|
350
|
-
const
|
|
351
|
-
for (const expDir of
|
|
662
|
+
const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
|
|
663
|
+
for (const expDir of expansionDirectories) {
|
|
352
664
|
const fullExpDir = path.join(installDir, expDir);
|
|
353
|
-
const expAgentFiles = glob.sync(
|
|
354
|
-
allAgentIds.push(...expAgentFiles.map((file) => path.basename(file,
|
|
665
|
+
const expAgentFiles = glob.sync('*.md', { cwd: fullExpDir });
|
|
666
|
+
allAgentIds.push(...expAgentFiles.map((file) => path.basename(file, '.md')));
|
|
355
667
|
}
|
|
356
|
-
|
|
668
|
+
|
|
357
669
|
// Remove duplicates
|
|
358
670
|
return [...new Set(allAgentIds)];
|
|
359
671
|
}
|
|
360
672
|
|
|
361
673
|
async getCoreAgentIds(installDir) {
|
|
362
674
|
const allAgentIds = [];
|
|
363
|
-
|
|
364
|
-
// Check core agents in .
|
|
365
|
-
let agentsDir = path.join(installDir,
|
|
675
|
+
|
|
676
|
+
// Check core agents in .bmad-core or root only
|
|
677
|
+
let agentsDir = path.join(installDir, '.bmad-core', 'agents');
|
|
366
678
|
if (!(await fileManager.pathExists(agentsDir))) {
|
|
367
|
-
agentsDir = path.join(installDir,
|
|
679
|
+
agentsDir = path.join(installDir, 'bmad-core', 'agents');
|
|
368
680
|
}
|
|
369
|
-
|
|
681
|
+
|
|
370
682
|
if (await fileManager.pathExists(agentsDir)) {
|
|
371
|
-
const glob = require(
|
|
372
|
-
const agentFiles = glob.sync(
|
|
373
|
-
allAgentIds.push(...agentFiles.map((file) => path.basename(file,
|
|
683
|
+
const glob = require('glob');
|
|
684
|
+
const agentFiles = glob.sync('*.md', { cwd: agentsDir });
|
|
685
|
+
allAgentIds.push(...agentFiles.map((file) => path.basename(file, '.md')));
|
|
374
686
|
}
|
|
375
|
-
|
|
687
|
+
|
|
376
688
|
return [...new Set(allAgentIds)];
|
|
377
689
|
}
|
|
378
690
|
|
|
379
691
|
async getCoreTaskIds(installDir) {
|
|
380
692
|
const allTaskIds = [];
|
|
381
|
-
|
|
382
|
-
// Check core tasks in .
|
|
383
|
-
let tasksDir = path.join(installDir,
|
|
693
|
+
|
|
694
|
+
// Check core tasks in .bmad-core or root only
|
|
695
|
+
let tasksDir = path.join(installDir, '.bmad-core', 'tasks');
|
|
384
696
|
if (!(await fileManager.pathExists(tasksDir))) {
|
|
385
|
-
tasksDir = path.join(installDir,
|
|
697
|
+
tasksDir = path.join(installDir, 'bmad-core', 'tasks');
|
|
386
698
|
}
|
|
387
|
-
|
|
699
|
+
|
|
388
700
|
if (await fileManager.pathExists(tasksDir)) {
|
|
389
|
-
const glob = require(
|
|
390
|
-
const taskFiles = glob.sync(
|
|
391
|
-
allTaskIds.push(...taskFiles.map((file) => path.basename(file,
|
|
701
|
+
const glob = require('glob');
|
|
702
|
+
const taskFiles = glob.sync('*.md', { cwd: tasksDir });
|
|
703
|
+
allTaskIds.push(...taskFiles.map((file) => path.basename(file, '.md')));
|
|
392
704
|
}
|
|
393
|
-
|
|
705
|
+
|
|
394
706
|
// Check common tasks
|
|
395
|
-
const commonTasksDir = path.join(installDir,
|
|
707
|
+
const commonTasksDir = path.join(installDir, 'common', 'tasks');
|
|
396
708
|
if (await fileManager.pathExists(commonTasksDir)) {
|
|
397
|
-
const commonTaskFiles = glob.sync(
|
|
398
|
-
allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file,
|
|
709
|
+
const commonTaskFiles = glob.sync('*.md', { cwd: commonTasksDir });
|
|
710
|
+
allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, '.md')));
|
|
399
711
|
}
|
|
400
|
-
|
|
712
|
+
|
|
401
713
|
return [...new Set(allTaskIds)];
|
|
402
714
|
}
|
|
403
715
|
|
|
404
716
|
async getAgentTitle(agentId, installDir) {
|
|
405
717
|
// Try to find the agent file in various locations
|
|
406
718
|
const possiblePaths = [
|
|
407
|
-
path.join(installDir,
|
|
408
|
-
path.join(installDir,
|
|
719
|
+
path.join(installDir, '.bmad-core', 'agents', `${agentId}.md`),
|
|
720
|
+
path.join(installDir, 'agents', `${agentId}.md`),
|
|
409
721
|
];
|
|
410
|
-
|
|
722
|
+
|
|
411
723
|
// Also check expansion pack directories
|
|
412
|
-
const glob = require(
|
|
413
|
-
const
|
|
414
|
-
for (const expDir of
|
|
724
|
+
const glob = require('glob');
|
|
725
|
+
const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
|
|
726
|
+
for (const expDir of expansionDirectories) {
|
|
415
727
|
possiblePaths.push(path.join(installDir, expDir, `${agentId}.md`));
|
|
416
728
|
}
|
|
417
|
-
|
|
729
|
+
|
|
418
730
|
for (const agentPath of possiblePaths) {
|
|
419
731
|
if (await fileManager.pathExists(agentPath)) {
|
|
420
732
|
try {
|
|
421
733
|
const agentContent = await fileManager.readFile(agentPath);
|
|
422
734
|
const yamlMatch = agentContent.match(/```ya?ml\r?\n([\s\S]*?)```/);
|
|
423
|
-
|
|
735
|
+
|
|
424
736
|
if (yamlMatch) {
|
|
425
737
|
const yaml = yamlMatch[1];
|
|
426
738
|
const titleMatch = yaml.match(/title:\s*(.+)/);
|
|
@@ -433,54 +745,55 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
433
745
|
}
|
|
434
746
|
}
|
|
435
747
|
}
|
|
436
|
-
|
|
748
|
+
|
|
437
749
|
// Fallback to formatted agent ID
|
|
438
|
-
return agentId
|
|
439
|
-
|
|
440
|
-
|
|
750
|
+
return agentId
|
|
751
|
+
.split('-')
|
|
752
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
753
|
+
.join(' ');
|
|
441
754
|
}
|
|
442
755
|
|
|
443
756
|
async getAllTaskIds(installDir) {
|
|
444
|
-
const glob = require(
|
|
757
|
+
const glob = require('glob');
|
|
445
758
|
const allTaskIds = [];
|
|
446
|
-
|
|
447
|
-
// Check core tasks in .
|
|
448
|
-
let tasksDir = path.join(installDir,
|
|
759
|
+
|
|
760
|
+
// Check core tasks in .bmad-core or root
|
|
761
|
+
let tasksDir = path.join(installDir, '.bmad-core', 'tasks');
|
|
449
762
|
if (!(await fileManager.pathExists(tasksDir))) {
|
|
450
|
-
tasksDir = path.join(installDir,
|
|
763
|
+
tasksDir = path.join(installDir, 'bmad-core', 'tasks');
|
|
451
764
|
}
|
|
452
|
-
|
|
765
|
+
|
|
453
766
|
if (await fileManager.pathExists(tasksDir)) {
|
|
454
|
-
const taskFiles = glob.sync(
|
|
455
|
-
allTaskIds.push(...taskFiles.map((file) => path.basename(file,
|
|
767
|
+
const taskFiles = glob.sync('*.md', { cwd: tasksDir });
|
|
768
|
+
allTaskIds.push(...taskFiles.map((file) => path.basename(file, '.md')));
|
|
456
769
|
}
|
|
457
|
-
|
|
770
|
+
|
|
458
771
|
// Check common tasks
|
|
459
|
-
const commonTasksDir = path.join(installDir,
|
|
772
|
+
const commonTasksDir = path.join(installDir, 'common', 'tasks');
|
|
460
773
|
if (await fileManager.pathExists(commonTasksDir)) {
|
|
461
|
-
const commonTaskFiles = glob.sync(
|
|
462
|
-
allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file,
|
|
774
|
+
const commonTaskFiles = glob.sync('*.md', { cwd: commonTasksDir });
|
|
775
|
+
allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, '.md')));
|
|
463
776
|
}
|
|
464
|
-
|
|
777
|
+
|
|
465
778
|
// Also check for expansion pack tasks in dot folders
|
|
466
|
-
const
|
|
467
|
-
for (const expDir of
|
|
779
|
+
const expansionDirectories = glob.sync('.*/tasks', { cwd: installDir });
|
|
780
|
+
for (const expDir of expansionDirectories) {
|
|
468
781
|
const fullExpDir = path.join(installDir, expDir);
|
|
469
|
-
const expTaskFiles = glob.sync(
|
|
470
|
-
allTaskIds.push(...expTaskFiles.map((file) => path.basename(file,
|
|
782
|
+
const expTaskFiles = glob.sync('*.md', { cwd: fullExpDir });
|
|
783
|
+
allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, '.md')));
|
|
471
784
|
}
|
|
472
|
-
|
|
785
|
+
|
|
473
786
|
// Check expansion-packs folder tasks
|
|
474
|
-
const expansionPacksDir = path.join(installDir,
|
|
787
|
+
const expansionPacksDir = path.join(installDir, 'expansion-packs');
|
|
475
788
|
if (await fileManager.pathExists(expansionPacksDir)) {
|
|
476
|
-
const
|
|
477
|
-
for (const expDir of
|
|
789
|
+
const expPackDirectories = glob.sync('*/tasks', { cwd: expansionPacksDir });
|
|
790
|
+
for (const expDir of expPackDirectories) {
|
|
478
791
|
const fullExpDir = path.join(expansionPacksDir, expDir);
|
|
479
|
-
const expTaskFiles = glob.sync(
|
|
480
|
-
allTaskIds.push(...expTaskFiles.map((file) => path.basename(file,
|
|
792
|
+
const expTaskFiles = glob.sync('*.md', { cwd: fullExpDir });
|
|
793
|
+
allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, '.md')));
|
|
481
794
|
}
|
|
482
795
|
}
|
|
483
|
-
|
|
796
|
+
|
|
484
797
|
// Remove duplicates
|
|
485
798
|
return [...new Set(allTaskIds)];
|
|
486
799
|
}
|
|
@@ -488,102 +801,104 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
488
801
|
async findTaskPath(taskId, installDir) {
|
|
489
802
|
// Try to find the task file in various locations
|
|
490
803
|
const possiblePaths = [
|
|
491
|
-
path.join(installDir,
|
|
492
|
-
path.join(installDir,
|
|
493
|
-
path.join(installDir,
|
|
804
|
+
path.join(installDir, '.bmad-core', 'tasks', `${taskId}.md`),
|
|
805
|
+
path.join(installDir, 'bmad-core', 'tasks', `${taskId}.md`),
|
|
806
|
+
path.join(installDir, 'common', 'tasks', `${taskId}.md`),
|
|
494
807
|
];
|
|
495
|
-
|
|
808
|
+
|
|
496
809
|
// Also check expansion pack directories
|
|
497
|
-
const glob = require(
|
|
498
|
-
|
|
810
|
+
const glob = require('glob');
|
|
811
|
+
|
|
499
812
|
// Check dot folder expansion packs
|
|
500
|
-
const
|
|
501
|
-
for (const expDir of
|
|
813
|
+
const expansionDirectories = glob.sync('.*/tasks', { cwd: installDir });
|
|
814
|
+
for (const expDir of expansionDirectories) {
|
|
502
815
|
possiblePaths.push(path.join(installDir, expDir, `${taskId}.md`));
|
|
503
816
|
}
|
|
504
|
-
|
|
817
|
+
|
|
505
818
|
// Check expansion-packs folder
|
|
506
|
-
const expansionPacksDir = path.join(installDir,
|
|
819
|
+
const expansionPacksDir = path.join(installDir, 'expansion-packs');
|
|
507
820
|
if (await fileManager.pathExists(expansionPacksDir)) {
|
|
508
|
-
const
|
|
509
|
-
for (const expDir of
|
|
821
|
+
const expPackDirectories = glob.sync('*/tasks', { cwd: expansionPacksDir });
|
|
822
|
+
for (const expDir of expPackDirectories) {
|
|
510
823
|
possiblePaths.push(path.join(expansionPacksDir, expDir, `${taskId}.md`));
|
|
511
824
|
}
|
|
512
825
|
}
|
|
513
|
-
|
|
826
|
+
|
|
514
827
|
for (const taskPath of possiblePaths) {
|
|
515
828
|
if (await fileManager.pathExists(taskPath)) {
|
|
516
829
|
return taskPath;
|
|
517
830
|
}
|
|
518
831
|
}
|
|
519
|
-
|
|
832
|
+
|
|
520
833
|
return null;
|
|
521
834
|
}
|
|
522
835
|
|
|
523
836
|
async getCoreSlashPrefix(installDir) {
|
|
524
837
|
try {
|
|
525
|
-
const coreConfigPath = path.join(installDir,
|
|
838
|
+
const coreConfigPath = path.join(installDir, '.bmad-core', 'core-config.yaml');
|
|
526
839
|
if (!(await fileManager.pathExists(coreConfigPath))) {
|
|
527
|
-
// Try
|
|
528
|
-
const altConfigPath = path.join(installDir,
|
|
840
|
+
// Try bmad-core directory
|
|
841
|
+
const altConfigPath = path.join(installDir, 'bmad-core', 'core-config.yaml');
|
|
529
842
|
if (await fileManager.pathExists(altConfigPath)) {
|
|
530
843
|
const configContent = await fileManager.readFile(altConfigPath);
|
|
531
844
|
const config = yaml.load(configContent);
|
|
532
|
-
return config.slashPrefix ||
|
|
845
|
+
return config.slashPrefix || 'BMad';
|
|
533
846
|
}
|
|
534
|
-
return
|
|
847
|
+
return 'BMad'; // fallback
|
|
535
848
|
}
|
|
536
|
-
|
|
849
|
+
|
|
537
850
|
const configContent = await fileManager.readFile(coreConfigPath);
|
|
538
851
|
const config = yaml.load(configContent);
|
|
539
|
-
return config.slashPrefix ||
|
|
852
|
+
return config.slashPrefix || 'BMad';
|
|
540
853
|
} catch (error) {
|
|
541
|
-
console.warn(`Failed to read core slashPrefix, using default '
|
|
542
|
-
return
|
|
854
|
+
console.warn(`Failed to read core slashPrefix, using default 'BMad': ${error.message}`);
|
|
855
|
+
return 'BMad';
|
|
543
856
|
}
|
|
544
857
|
}
|
|
545
858
|
|
|
546
859
|
async getInstalledExpansionPacks(installDir) {
|
|
547
860
|
const expansionPacks = [];
|
|
548
|
-
|
|
861
|
+
|
|
549
862
|
// Check for dot-prefixed expansion packs in install directory
|
|
550
|
-
const glob = require(
|
|
551
|
-
const dotExpansions = glob.sync(
|
|
552
|
-
|
|
863
|
+
const glob = require('glob');
|
|
864
|
+
const dotExpansions = glob.sync('.bmad-*', { cwd: installDir });
|
|
865
|
+
|
|
553
866
|
for (const dotExpansion of dotExpansions) {
|
|
554
|
-
if (dotExpansion !==
|
|
867
|
+
if (dotExpansion !== '.bmad-core') {
|
|
555
868
|
const packPath = path.join(installDir, dotExpansion);
|
|
556
|
-
const packName = dotExpansion.
|
|
869
|
+
const packName = dotExpansion.slice(1); // remove the dot
|
|
557
870
|
expansionPacks.push({
|
|
558
871
|
name: packName,
|
|
559
|
-
path: packPath
|
|
872
|
+
path: packPath,
|
|
560
873
|
});
|
|
561
874
|
}
|
|
562
875
|
}
|
|
563
|
-
|
|
876
|
+
|
|
564
877
|
// Check for expansion-packs directory style
|
|
565
|
-
const expansionPacksDir = path.join(installDir,
|
|
878
|
+
const expansionPacksDir = path.join(installDir, 'expansion-packs');
|
|
566
879
|
if (await fileManager.pathExists(expansionPacksDir)) {
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
for (const packDir of
|
|
880
|
+
const packDirectories = glob.sync('*', { cwd: expansionPacksDir });
|
|
881
|
+
|
|
882
|
+
for (const packDir of packDirectories) {
|
|
570
883
|
const packPath = path.join(expansionPacksDir, packDir);
|
|
571
|
-
if (
|
|
572
|
-
|
|
884
|
+
if (
|
|
885
|
+
(await fileManager.pathExists(packPath)) &&
|
|
886
|
+
(await fileManager.pathExists(path.join(packPath, 'config.yaml')))
|
|
887
|
+
) {
|
|
573
888
|
expansionPacks.push({
|
|
574
889
|
name: packDir,
|
|
575
|
-
path: packPath
|
|
890
|
+
path: packPath,
|
|
576
891
|
});
|
|
577
892
|
}
|
|
578
893
|
}
|
|
579
894
|
}
|
|
580
|
-
|
|
895
|
+
|
|
581
896
|
return expansionPacks;
|
|
582
897
|
}
|
|
583
898
|
|
|
584
899
|
async getExpansionPackSlashPrefix(packPath) {
|
|
585
900
|
try {
|
|
586
|
-
const configPath = path.join(packPath,
|
|
901
|
+
const configPath = path.join(packPath, 'config.yaml');
|
|
587
902
|
if (await fileManager.pathExists(configPath)) {
|
|
588
903
|
const configContent = await fileManager.readFile(configPath);
|
|
589
904
|
const config = yaml.load(configContent);
|
|
@@ -592,20 +907,20 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
592
907
|
} catch (error) {
|
|
593
908
|
console.warn(`Failed to read expansion pack slashPrefix from ${packPath}: ${error.message}`);
|
|
594
909
|
}
|
|
595
|
-
|
|
910
|
+
|
|
596
911
|
return path.basename(packPath); // fallback to directory name
|
|
597
912
|
}
|
|
598
913
|
|
|
599
914
|
async getExpansionPackAgents(packPath) {
|
|
600
|
-
const agentsDir = path.join(packPath,
|
|
915
|
+
const agentsDir = path.join(packPath, 'agents');
|
|
601
916
|
if (!(await fileManager.pathExists(agentsDir))) {
|
|
602
917
|
return [];
|
|
603
918
|
}
|
|
604
|
-
|
|
919
|
+
|
|
605
920
|
try {
|
|
606
|
-
const glob = require(
|
|
607
|
-
const agentFiles = glob.sync(
|
|
608
|
-
return agentFiles.map(file => path.basename(file,
|
|
921
|
+
const glob = require('glob');
|
|
922
|
+
const agentFiles = glob.sync('*.md', { cwd: agentsDir });
|
|
923
|
+
return agentFiles.map((file) => path.basename(file, '.md'));
|
|
609
924
|
} catch (error) {
|
|
610
925
|
console.warn(`Failed to read expansion pack agents from ${packPath}: ${error.message}`);
|
|
611
926
|
return [];
|
|
@@ -613,15 +928,15 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
613
928
|
}
|
|
614
929
|
|
|
615
930
|
async getExpansionPackTasks(packPath) {
|
|
616
|
-
const tasksDir = path.join(packPath,
|
|
931
|
+
const tasksDir = path.join(packPath, 'tasks');
|
|
617
932
|
if (!(await fileManager.pathExists(tasksDir))) {
|
|
618
933
|
return [];
|
|
619
934
|
}
|
|
620
|
-
|
|
935
|
+
|
|
621
936
|
try {
|
|
622
|
-
const glob = require(
|
|
623
|
-
const taskFiles = glob.sync(
|
|
624
|
-
return taskFiles.map(file => path.basename(file,
|
|
937
|
+
const glob = require('glob');
|
|
938
|
+
const taskFiles = glob.sync('*.md', { cwd: tasksDir });
|
|
939
|
+
return taskFiles.map((file) => path.basename(file, '.md'));
|
|
625
940
|
} catch (error) {
|
|
626
941
|
console.warn(`Failed to read expansion pack tasks from ${packPath}: ${error.message}`);
|
|
627
942
|
return [];
|
|
@@ -632,9 +947,9 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
632
947
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
633
948
|
|
|
634
949
|
// Check for existing .roomodes file in project root
|
|
635
|
-
const roomodesPath = path.join(installDir,
|
|
950
|
+
const roomodesPath = path.join(installDir, '.roomodes');
|
|
636
951
|
let existingModes = [];
|
|
637
|
-
let existingContent =
|
|
952
|
+
let existingContent = '';
|
|
638
953
|
|
|
639
954
|
if (await fileManager.pathExists(roomodesPath)) {
|
|
640
955
|
existingContent = await fileManager.readFile(roomodesPath);
|
|
@@ -647,7 +962,7 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
647
962
|
}
|
|
648
963
|
|
|
649
964
|
// Create new modes content
|
|
650
|
-
let newModesContent =
|
|
965
|
+
let newModesContent = '';
|
|
651
966
|
|
|
652
967
|
// Load dynamic agent permissions from configuration
|
|
653
968
|
const config = await this.loadIdeAgentConfig();
|
|
@@ -679,14 +994,15 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
679
994
|
const whenToUseMatch = yaml.match(/whenToUse:\s*"(.+)"/);
|
|
680
995
|
const roleDefinitionMatch = yaml.match(/roleDefinition:\s*"(.+)"/);
|
|
681
996
|
|
|
682
|
-
const title = titleMatch
|
|
683
|
-
|
|
997
|
+
const title = titleMatch
|
|
998
|
+
? titleMatch[1].trim()
|
|
999
|
+
: await this.getAgentTitle(agentId, installDir);
|
|
1000
|
+
const icon = iconMatch ? iconMatch[1].trim() : '🤖';
|
|
684
1001
|
const whenToUse = whenToUseMatch ? whenToUseMatch[1].trim() : `Use for ${title} tasks`;
|
|
685
1002
|
const roleDefinition = roleDefinitionMatch
|
|
686
1003
|
? roleDefinitionMatch[1].trim()
|
|
687
1004
|
: `You are a ${title} specializing in ${title.toLowerCase()} tasks and responsibilities.`;
|
|
688
1005
|
|
|
689
|
-
|
|
690
1006
|
// Add permissions based on agent type
|
|
691
1007
|
const permissions = agentPermissions[agentId];
|
|
692
1008
|
// Build mode entry with proper formatting (matching exact indentation)
|
|
@@ -695,12 +1011,12 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
695
1011
|
newModesContent += ` - slug: ${slug}\n`;
|
|
696
1012
|
newModesContent += ` name: '${icon} ${title}'\n`;
|
|
697
1013
|
if (permissions) {
|
|
698
|
-
|
|
1014
|
+
newModesContent += ` description: '${permissions.description}'\n`;
|
|
699
1015
|
}
|
|
700
1016
|
newModesContent += ` roleDefinition: ${roleDefinition}\n`;
|
|
701
1017
|
newModesContent += ` whenToUse: ${whenToUse}\n`;
|
|
702
1018
|
// Get relative path from installDir to agent file
|
|
703
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
1019
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
704
1020
|
newModesContent += ` customInstructions: CRITICAL Read the full YAML from ${relativePath} start activation to alter your state of being follow startup section instructions stay in this being until told to exit this mode\n`;
|
|
705
1021
|
newModesContent += ` groups:\n`;
|
|
706
1022
|
newModesContent += ` - read\n`;
|
|
@@ -719,42 +1035,45 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
719
1035
|
}
|
|
720
1036
|
|
|
721
1037
|
// Build final roomodes content
|
|
722
|
-
let roomodesContent =
|
|
1038
|
+
let roomodesContent = '';
|
|
723
1039
|
if (existingContent) {
|
|
724
1040
|
// If there's existing content, append new modes to it
|
|
725
|
-
roomodesContent = existingContent.trim() +
|
|
1041
|
+
roomodesContent = existingContent.trim() + '\n' + newModesContent;
|
|
726
1042
|
} else {
|
|
727
1043
|
// Create new .roomodes file with proper YAML structure
|
|
728
|
-
roomodesContent =
|
|
1044
|
+
roomodesContent = 'customModes:\n' + newModesContent;
|
|
729
1045
|
}
|
|
730
1046
|
|
|
731
1047
|
// Write .roomodes file
|
|
732
1048
|
await fileManager.writeFile(roomodesPath, roomodesContent);
|
|
733
|
-
console.log(chalk.green(
|
|
1049
|
+
console.log(chalk.green('✓ Created .roomodes file in project root'));
|
|
734
1050
|
|
|
735
1051
|
console.log(chalk.green(`\n✓ Roo Code setup complete!`));
|
|
736
|
-
console.log(chalk.dim(
|
|
1052
|
+
console.log(chalk.dim('Custom modes will be available when you open this project in Roo Code'));
|
|
737
1053
|
|
|
738
1054
|
return true;
|
|
739
1055
|
}
|
|
740
|
-
|
|
1056
|
+
|
|
741
1057
|
async setupKilocode(installDir, selectedAgent) {
|
|
742
|
-
const filePath = path.join(installDir,
|
|
1058
|
+
const filePath = path.join(installDir, '.kilocodemodes');
|
|
743
1059
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
744
1060
|
|
|
745
|
-
let existingModes = [],
|
|
1061
|
+
let existingModes = [],
|
|
1062
|
+
existingContent = '';
|
|
746
1063
|
if (await fileManager.pathExists(filePath)) {
|
|
747
1064
|
existingContent = await fileManager.readFile(filePath);
|
|
748
1065
|
for (const match of existingContent.matchAll(/- slug: ([\w-]+)/g)) {
|
|
749
1066
|
existingModes.push(match[1]);
|
|
750
1067
|
}
|
|
751
|
-
console.log(
|
|
1068
|
+
console.log(
|
|
1069
|
+
chalk.yellow(`Found existing .kilocodemodes file with ${existingModes.length} modes`),
|
|
1070
|
+
);
|
|
752
1071
|
}
|
|
753
1072
|
|
|
754
1073
|
const config = await this.loadIdeAgentConfig();
|
|
755
1074
|
const permissions = config['roo-permissions'] || {}; // reuse same roo permissions block (Kilo Code understands same mode schema)
|
|
756
1075
|
|
|
757
|
-
let newContent =
|
|
1076
|
+
let newContent = '';
|
|
758
1077
|
|
|
759
1078
|
for (const agentId of agents) {
|
|
760
1079
|
const slug = agentId.startsWith('bmad-') ? agentId : `bmad-${agentId}`;
|
|
@@ -779,13 +1098,15 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
779
1098
|
const yaml = yamlMatch[1];
|
|
780
1099
|
|
|
781
1100
|
// Robust fallback for title and icon
|
|
782
|
-
const title =
|
|
783
|
-
|
|
784
|
-
const
|
|
785
|
-
const
|
|
1101
|
+
const title =
|
|
1102
|
+
yaml.match(/title:\s*(.+)/)?.[1]?.trim() || (await this.getAgentTitle(agentId, installDir));
|
|
1103
|
+
const icon = yaml.match(/icon:\s*(.+)/)?.[1]?.trim() || '🤖';
|
|
1104
|
+
const whenToUse = yaml.match(/whenToUse:\s*"(.+)"/)?.[1]?.trim() || `Use for ${title} tasks`;
|
|
1105
|
+
const roleDefinition =
|
|
1106
|
+
yaml.match(/roleDefinition:\s*"(.+)"/)?.[1]?.trim() ||
|
|
786
1107
|
`You are a ${title} specializing in ${title.toLowerCase()} tasks and responsibilities.`;
|
|
787
1108
|
|
|
788
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
1109
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
789
1110
|
const customInstructions = `CRITICAL Read the full YAML from ${relativePath} start activation to alter your state of being follow startup section instructions stay in this being until told to exit this mode`;
|
|
790
1111
|
|
|
791
1112
|
// Add permissions from config if they exist
|
|
@@ -795,7 +1116,7 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
795
1116
|
newContent += ` - slug: ${slug}\n`;
|
|
796
1117
|
newContent += ` name: '${icon} ${title}'\n`;
|
|
797
1118
|
if (agentPermission) {
|
|
798
|
-
|
|
1119
|
+
newContent += ` description: '${agentPermission.description}'\n`;
|
|
799
1120
|
}
|
|
800
1121
|
|
|
801
1122
|
newContent += ` roleDefinition: ${roleDefinition}\n`;
|
|
@@ -804,7 +1125,6 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
804
1125
|
newContent += ` groups:\n`;
|
|
805
1126
|
newContent += ` - read\n`;
|
|
806
1127
|
|
|
807
|
-
|
|
808
1128
|
if (agentPermission) {
|
|
809
1129
|
newContent += ` - - edit\n`;
|
|
810
1130
|
newContent += ` - fileRegex: ${agentPermission.fileRegex}\n`;
|
|
@@ -818,19 +1138,19 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
818
1138
|
}
|
|
819
1139
|
|
|
820
1140
|
const finalContent = existingContent
|
|
821
|
-
? existingContent.trim() +
|
|
822
|
-
:
|
|
1141
|
+
? existingContent.trim() + '\n' + newContent
|
|
1142
|
+
: 'customModes:\n' + newContent;
|
|
823
1143
|
|
|
824
1144
|
await fileManager.writeFile(filePath, finalContent);
|
|
825
|
-
console.log(chalk.green(
|
|
1145
|
+
console.log(chalk.green('✓ Created .kilocodemodes file in project root'));
|
|
826
1146
|
console.log(chalk.green(`✓ KiloCode setup complete!`));
|
|
827
|
-
console.log(chalk.dim(
|
|
1147
|
+
console.log(chalk.dim('Custom modes will be available when you open this project in KiloCode'));
|
|
828
1148
|
|
|
829
1149
|
return true;
|
|
830
1150
|
}
|
|
831
|
-
|
|
1151
|
+
|
|
832
1152
|
async setupCline(installDir, selectedAgent) {
|
|
833
|
-
const clineRulesDir = path.join(installDir,
|
|
1153
|
+
const clineRulesDir = path.join(installDir, '.clinerules');
|
|
834
1154
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
835
1155
|
|
|
836
1156
|
await fileManager.ensureDirectory(clineRulesDir);
|
|
@@ -854,26 +1174,28 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
854
1174
|
// Create MD content for Cline (focused on project standards and role)
|
|
855
1175
|
let mdContent = `# ${await this.getAgentTitle(agentId, installDir)} Agent\n\n`;
|
|
856
1176
|
mdContent += `This rule defines the ${await this.getAgentTitle(agentId, installDir)} persona and project standards.\n\n`;
|
|
857
|
-
mdContent +=
|
|
1177
|
+
mdContent += '## Role Definition\n\n';
|
|
858
1178
|
mdContent +=
|
|
859
|
-
|
|
860
|
-
|
|
1179
|
+
'When the user types `@' +
|
|
1180
|
+
agentId +
|
|
1181
|
+
'`, adopt this persona and follow these guidelines:\n\n';
|
|
1182
|
+
mdContent += '```yaml\n';
|
|
861
1183
|
// Extract just the YAML content from the agent file
|
|
862
1184
|
const yamlContent = extractYamlFromAgent(agentContent);
|
|
863
1185
|
if (yamlContent) {
|
|
864
1186
|
mdContent += yamlContent;
|
|
865
1187
|
} else {
|
|
866
1188
|
// If no YAML found, include the whole content minus the header
|
|
867
|
-
mdContent += agentContent.replace(/^#.*$/m,
|
|
1189
|
+
mdContent += agentContent.replace(/^#.*$/m, '').trim();
|
|
868
1190
|
}
|
|
869
|
-
mdContent +=
|
|
870
|
-
mdContent +=
|
|
871
|
-
mdContent += `- Always maintain consistency with project documentation in .
|
|
1191
|
+
mdContent += '\n```\n\n';
|
|
1192
|
+
mdContent += '## Project Standards\n\n';
|
|
1193
|
+
mdContent += `- Always maintain consistency with project documentation in .bmad-core/\n`;
|
|
872
1194
|
mdContent += `- Follow the agent's specific guidelines and constraints\n`;
|
|
873
1195
|
mdContent += `- Update relevant project files when making changes\n`;
|
|
874
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
1196
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
875
1197
|
mdContent += `- Reference the complete agent definition in [${relativePath}](${relativePath})\n\n`;
|
|
876
|
-
mdContent +=
|
|
1198
|
+
mdContent += '## Usage\n\n';
|
|
877
1199
|
mdContent += `Type \`@${agentId}\` to activate this ${await this.getAgentTitle(agentId, installDir)} persona.\n`;
|
|
878
1200
|
|
|
879
1201
|
await fileManager.writeFile(mdPath, mdContent);
|
|
@@ -887,54 +1209,50 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
887
1209
|
}
|
|
888
1210
|
|
|
889
1211
|
async setupGeminiCli(installDir) {
|
|
890
|
-
const geminiDir = path.join(installDir,
|
|
891
|
-
const bmadMethodDir = path.join(geminiDir,
|
|
1212
|
+
const geminiDir = path.join(installDir, '.gemini');
|
|
1213
|
+
const bmadMethodDir = path.join(geminiDir, 'xiaoma-cli');
|
|
892
1214
|
await fileManager.ensureDirectory(bmadMethodDir);
|
|
893
1215
|
|
|
894
1216
|
// Update logic for existing settings.json
|
|
895
|
-
const settingsPath = path.join(geminiDir,
|
|
1217
|
+
const settingsPath = path.join(geminiDir, 'settings.json');
|
|
896
1218
|
if (await fileManager.pathExists(settingsPath)) {
|
|
897
1219
|
try {
|
|
898
1220
|
const settingsContent = await fileManager.readFile(settingsPath);
|
|
899
1221
|
const settings = JSON.parse(settingsContent);
|
|
900
1222
|
let updated = false;
|
|
901
|
-
|
|
1223
|
+
|
|
902
1224
|
// Handle contextFileName property
|
|
903
1225
|
if (settings.contextFileName && Array.isArray(settings.contextFileName)) {
|
|
904
1226
|
const originalLength = settings.contextFileName.length;
|
|
905
1227
|
settings.contextFileName = settings.contextFileName.filter(
|
|
906
|
-
(fileName) => !fileName.startsWith(
|
|
1228
|
+
(fileName) => !fileName.startsWith('agents/'),
|
|
907
1229
|
);
|
|
908
1230
|
if (settings.contextFileName.length !== originalLength) {
|
|
909
1231
|
updated = true;
|
|
910
1232
|
}
|
|
911
1233
|
}
|
|
912
|
-
|
|
1234
|
+
|
|
913
1235
|
if (updated) {
|
|
914
|
-
await fileManager.writeFile(
|
|
915
|
-
|
|
916
|
-
|
|
1236
|
+
await fileManager.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
1237
|
+
console.log(
|
|
1238
|
+
chalk.green('✓ Updated .gemini/settings.json - removed agent file references'),
|
|
917
1239
|
);
|
|
918
|
-
console.log(chalk.green("✓ Updated .gemini/settings.json - removed agent file references"));
|
|
919
1240
|
}
|
|
920
1241
|
} catch (error) {
|
|
921
|
-
console.warn(
|
|
922
|
-
chalk.yellow("Could not update .gemini/settings.json"),
|
|
923
|
-
error
|
|
924
|
-
);
|
|
1242
|
+
console.warn(chalk.yellow('Could not update .gemini/settings.json'), error);
|
|
925
1243
|
}
|
|
926
1244
|
}
|
|
927
1245
|
|
|
928
1246
|
// Remove old agents directory
|
|
929
|
-
const agentsDir = path.join(geminiDir,
|
|
1247
|
+
const agentsDir = path.join(geminiDir, 'agents');
|
|
930
1248
|
if (await fileManager.pathExists(agentsDir)) {
|
|
931
1249
|
await fileManager.removeDirectory(agentsDir);
|
|
932
|
-
console.log(chalk.green(
|
|
1250
|
+
console.log(chalk.green('✓ Removed old .gemini/agents directory'));
|
|
933
1251
|
}
|
|
934
1252
|
|
|
935
1253
|
// Get all available agents
|
|
936
1254
|
const agents = await this.getAllAgentIds(installDir);
|
|
937
|
-
let concatenatedContent =
|
|
1255
|
+
let concatenatedContent = '';
|
|
938
1256
|
|
|
939
1257
|
for (const agentId of agents) {
|
|
940
1258
|
// Find the source agent file
|
|
@@ -942,44 +1260,43 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
942
1260
|
|
|
943
1261
|
if (agentPath) {
|
|
944
1262
|
const agentContent = await fileManager.readFile(agentPath);
|
|
945
|
-
|
|
1263
|
+
|
|
946
1264
|
// Create properly formatted agent rule content (similar to trae)
|
|
947
1265
|
let agentRuleContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
948
1266
|
agentRuleContent += `This rule is triggered when the user types \`*${agentId}\` and activates the ${await this.getAgentTitle(
|
|
949
1267
|
agentId,
|
|
950
|
-
installDir
|
|
1268
|
+
installDir,
|
|
951
1269
|
)} agent persona.\n\n`;
|
|
952
|
-
agentRuleContent +=
|
|
1270
|
+
agentRuleContent += '## Agent Activation\n\n';
|
|
953
1271
|
agentRuleContent +=
|
|
954
|
-
|
|
955
|
-
agentRuleContent +=
|
|
1272
|
+
'CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n';
|
|
1273
|
+
agentRuleContent += '```yaml\n';
|
|
956
1274
|
// Extract just the YAML content from the agent file
|
|
957
1275
|
const yamlContent = extractYamlFromAgent(agentContent);
|
|
958
1276
|
if (yamlContent) {
|
|
959
1277
|
agentRuleContent += yamlContent;
|
|
960
|
-
}
|
|
961
|
-
else {
|
|
1278
|
+
} else {
|
|
962
1279
|
// If no YAML found, include the whole content minus the header
|
|
963
|
-
agentRuleContent += agentContent.replace(/^#.*$/m,
|
|
1280
|
+
agentRuleContent += agentContent.replace(/^#.*$/m, '').trim();
|
|
964
1281
|
}
|
|
965
|
-
agentRuleContent +=
|
|
966
|
-
agentRuleContent +=
|
|
967
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
1282
|
+
agentRuleContent += '\n```\n\n';
|
|
1283
|
+
agentRuleContent += '## File Reference\n\n';
|
|
1284
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
968
1285
|
agentRuleContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
|
|
969
|
-
agentRuleContent +=
|
|
1286
|
+
agentRuleContent += '## Usage\n\n';
|
|
970
1287
|
agentRuleContent += `When the user types \`*${agentId}\`, activate this ${await this.getAgentTitle(
|
|
971
1288
|
agentId,
|
|
972
|
-
installDir
|
|
1289
|
+
installDir,
|
|
973
1290
|
)} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
974
|
-
|
|
1291
|
+
|
|
975
1292
|
// Add to concatenated content with separator
|
|
976
|
-
concatenatedContent += agentRuleContent +
|
|
1293
|
+
concatenatedContent += agentRuleContent + '\n\n---\n\n';
|
|
977
1294
|
console.log(chalk.green(`✓ Added context for @${agentId}`));
|
|
978
1295
|
}
|
|
979
1296
|
}
|
|
980
1297
|
|
|
981
1298
|
// Write the concatenated content to GEMINI.md
|
|
982
|
-
const geminiMdPath = path.join(bmadMethodDir,
|
|
1299
|
+
const geminiMdPath = path.join(bmadMethodDir, 'GEMINI.md');
|
|
983
1300
|
await fileManager.writeFile(geminiMdPath, concatenatedContent);
|
|
984
1301
|
console.log(chalk.green(`\n✓ Created GEMINI.md in ${bmadMethodDir}`));
|
|
985
1302
|
|
|
@@ -987,54 +1304,48 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
987
1304
|
}
|
|
988
1305
|
|
|
989
1306
|
async setupQwenCode(installDir, selectedAgent) {
|
|
990
|
-
const qwenDir = path.join(installDir,
|
|
991
|
-
const bmadMethodDir = path.join(qwenDir,
|
|
1307
|
+
const qwenDir = path.join(installDir, '.qwen');
|
|
1308
|
+
const bmadMethodDir = path.join(qwenDir, 'xiaoma-cli');
|
|
992
1309
|
await fileManager.ensureDirectory(bmadMethodDir);
|
|
993
1310
|
|
|
994
1311
|
// Update logic for existing settings.json
|
|
995
|
-
const settingsPath = path.join(qwenDir,
|
|
1312
|
+
const settingsPath = path.join(qwenDir, 'settings.json');
|
|
996
1313
|
if (await fileManager.pathExists(settingsPath)) {
|
|
997
1314
|
try {
|
|
998
1315
|
const settingsContent = await fileManager.readFile(settingsPath);
|
|
999
1316
|
const settings = JSON.parse(settingsContent);
|
|
1000
1317
|
let updated = false;
|
|
1001
|
-
|
|
1318
|
+
|
|
1002
1319
|
// Handle contextFileName property
|
|
1003
1320
|
if (settings.contextFileName && Array.isArray(settings.contextFileName)) {
|
|
1004
1321
|
const originalLength = settings.contextFileName.length;
|
|
1005
1322
|
settings.contextFileName = settings.contextFileName.filter(
|
|
1006
|
-
(fileName) => !fileName.startsWith(
|
|
1323
|
+
(fileName) => !fileName.startsWith('agents/'),
|
|
1007
1324
|
);
|
|
1008
1325
|
if (settings.contextFileName.length !== originalLength) {
|
|
1009
1326
|
updated = true;
|
|
1010
1327
|
}
|
|
1011
1328
|
}
|
|
1012
|
-
|
|
1329
|
+
|
|
1013
1330
|
if (updated) {
|
|
1014
|
-
await fileManager.writeFile(
|
|
1015
|
-
|
|
1016
|
-
JSON.stringify(settings, null, 2)
|
|
1017
|
-
);
|
|
1018
|
-
console.log(chalk.green("✓ Updated .qwen/settings.json - removed agent file references"));
|
|
1331
|
+
await fileManager.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
1332
|
+
console.log(chalk.green('✓ Updated .qwen/settings.json - removed agent file references'));
|
|
1019
1333
|
}
|
|
1020
1334
|
} catch (error) {
|
|
1021
|
-
console.warn(
|
|
1022
|
-
chalk.yellow("Could not update .qwen/settings.json"),
|
|
1023
|
-
error
|
|
1024
|
-
);
|
|
1335
|
+
console.warn(chalk.yellow('Could not update .qwen/settings.json'), error);
|
|
1025
1336
|
}
|
|
1026
1337
|
}
|
|
1027
1338
|
|
|
1028
1339
|
// Remove old agents directory
|
|
1029
|
-
const agentsDir = path.join(qwenDir,
|
|
1340
|
+
const agentsDir = path.join(qwenDir, 'agents');
|
|
1030
1341
|
if (await fileManager.pathExists(agentsDir)) {
|
|
1031
1342
|
await fileManager.removeDirectory(agentsDir);
|
|
1032
|
-
console.log(chalk.green(
|
|
1343
|
+
console.log(chalk.green('✓ Removed old .qwen/agents directory'));
|
|
1033
1344
|
}
|
|
1034
1345
|
|
|
1035
1346
|
// Get all available agents
|
|
1036
1347
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
1037
|
-
let concatenatedContent =
|
|
1348
|
+
let concatenatedContent = '';
|
|
1038
1349
|
|
|
1039
1350
|
for (const agentId of agents) {
|
|
1040
1351
|
// Find the source agent file
|
|
@@ -1042,57 +1353,61 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
1042
1353
|
|
|
1043
1354
|
if (agentPath) {
|
|
1044
1355
|
const agentContent = await fileManager.readFile(agentPath);
|
|
1045
|
-
|
|
1356
|
+
|
|
1046
1357
|
// Create properly formatted agent rule content (similar to gemini)
|
|
1047
1358
|
let agentRuleContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
1048
1359
|
agentRuleContent += `This rule is triggered when the user types \`*${agentId}\` and activates the ${await this.getAgentTitle(
|
|
1049
1360
|
agentId,
|
|
1050
|
-
installDir
|
|
1361
|
+
installDir,
|
|
1051
1362
|
)} agent persona.\n\n`;
|
|
1052
|
-
agentRuleContent +=
|
|
1363
|
+
agentRuleContent += '## Agent Activation\n\n';
|
|
1053
1364
|
agentRuleContent +=
|
|
1054
|
-
|
|
1055
|
-
agentRuleContent +=
|
|
1365
|
+
'CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n';
|
|
1366
|
+
agentRuleContent += '```yaml\n';
|
|
1056
1367
|
// Extract just the YAML content from the agent file
|
|
1057
1368
|
const yamlContent = extractYamlFromAgent(agentContent);
|
|
1058
1369
|
if (yamlContent) {
|
|
1059
1370
|
agentRuleContent += yamlContent;
|
|
1060
|
-
}
|
|
1061
|
-
else {
|
|
1371
|
+
} else {
|
|
1062
1372
|
// If no YAML found, include the whole content minus the header
|
|
1063
|
-
agentRuleContent += agentContent.replace(/^#.*$/m,
|
|
1373
|
+
agentRuleContent += agentContent.replace(/^#.*$/m, '').trim();
|
|
1064
1374
|
}
|
|
1065
|
-
agentRuleContent +=
|
|
1066
|
-
agentRuleContent +=
|
|
1067
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
1375
|
+
agentRuleContent += '\n```\n\n';
|
|
1376
|
+
agentRuleContent += '## File Reference\n\n';
|
|
1377
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
1068
1378
|
agentRuleContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
|
|
1069
|
-
agentRuleContent +=
|
|
1379
|
+
agentRuleContent += '## Usage\n\n';
|
|
1070
1380
|
agentRuleContent += `When the user types \`*${agentId}\`, activate this ${await this.getAgentTitle(
|
|
1071
1381
|
agentId,
|
|
1072
|
-
installDir
|
|
1382
|
+
installDir,
|
|
1073
1383
|
)} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
1074
|
-
|
|
1384
|
+
|
|
1075
1385
|
// Add to concatenated content with separator
|
|
1076
|
-
concatenatedContent += agentRuleContent +
|
|
1386
|
+
concatenatedContent += agentRuleContent + '\n\n---\n\n';
|
|
1077
1387
|
console.log(chalk.green(`✓ Added context for *${agentId}`));
|
|
1078
1388
|
}
|
|
1079
1389
|
}
|
|
1080
1390
|
|
|
1081
1391
|
// Write the concatenated content to QWEN.md
|
|
1082
|
-
const qwenMdPath = path.join(bmadMethodDir,
|
|
1392
|
+
const qwenMdPath = path.join(bmadMethodDir, 'QWEN.md');
|
|
1083
1393
|
await fileManager.writeFile(qwenMdPath, concatenatedContent);
|
|
1084
1394
|
console.log(chalk.green(`\n✓ Created QWEN.md in ${bmadMethodDir}`));
|
|
1085
1395
|
|
|
1086
1396
|
return true;
|
|
1087
1397
|
}
|
|
1088
1398
|
|
|
1089
|
-
async setupGitHubCopilot(
|
|
1399
|
+
async setupGitHubCopilot(
|
|
1400
|
+
installDir,
|
|
1401
|
+
selectedAgent,
|
|
1402
|
+
spinner = null,
|
|
1403
|
+
preConfiguredSettings = null,
|
|
1404
|
+
) {
|
|
1090
1405
|
// Configure VS Code workspace settings first to avoid UI conflicts with loading spinners
|
|
1091
1406
|
await this.configureVsCodeSettings(installDir, spinner, preConfiguredSettings);
|
|
1092
|
-
|
|
1093
|
-
const chatmodesDir = path.join(installDir,
|
|
1407
|
+
|
|
1408
|
+
const chatmodesDir = path.join(installDir, '.github', 'chatmodes');
|
|
1094
1409
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
1095
|
-
|
|
1410
|
+
|
|
1096
1411
|
await fileManager.ensureDirectory(chatmodesDir);
|
|
1097
1412
|
|
|
1098
1413
|
for (const agentId of agents) {
|
|
@@ -1104,7 +1419,7 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
1104
1419
|
// Create chat mode file with agent content
|
|
1105
1420
|
const agentContent = await fileManager.readFile(agentPath);
|
|
1106
1421
|
const agentTitle = await this.getAgentTitle(agentId, installDir);
|
|
1107
|
-
|
|
1422
|
+
|
|
1108
1423
|
// Extract whenToUse for the description
|
|
1109
1424
|
const yamlMatch = agentContent.match(/```ya?ml\r?\n([\s\S]*?)```/);
|
|
1110
1425
|
let description = `Activates the ${agentTitle} agent persona.`;
|
|
@@ -1114,9 +1429,9 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
1114
1429
|
description = whenToUseMatch[1];
|
|
1115
1430
|
}
|
|
1116
1431
|
}
|
|
1117
|
-
|
|
1432
|
+
|
|
1118
1433
|
let chatmodeContent = `---
|
|
1119
|
-
description: "${description.
|
|
1434
|
+
description: "${description.replaceAll('"', String.raw`\"`)}"
|
|
1120
1435
|
tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems', 'usages', 'editFiles', 'runCommands', 'runTasks', 'runTests', 'search', 'searchResults', 'terminalLastCommand', 'terminalSelection', 'testFailure']
|
|
1121
1436
|
---
|
|
1122
1437
|
|
|
@@ -1129,30 +1444,30 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
|
|
|
1129
1444
|
}
|
|
1130
1445
|
|
|
1131
1446
|
console.log(chalk.green(`\n✓ Github Copilot setup complete!`));
|
|
1132
|
-
console.log(chalk.dim(`You can now find the
|
|
1447
|
+
console.log(chalk.dim(`You can now find the BMad agents in the Chat view's mode selector.`));
|
|
1133
1448
|
|
|
1134
1449
|
return true;
|
|
1135
1450
|
}
|
|
1136
1451
|
|
|
1137
1452
|
async configureVsCodeSettings(installDir, spinner, preConfiguredSettings = null) {
|
|
1138
|
-
const vscodeDir = path.join(installDir,
|
|
1139
|
-
const settingsPath = path.join(vscodeDir,
|
|
1140
|
-
|
|
1453
|
+
const vscodeDir = path.join(installDir, '.vscode');
|
|
1454
|
+
const settingsPath = path.join(vscodeDir, 'settings.json');
|
|
1455
|
+
|
|
1141
1456
|
await fileManager.ensureDirectory(vscodeDir);
|
|
1142
|
-
|
|
1457
|
+
|
|
1143
1458
|
// Read existing settings if they exist
|
|
1144
1459
|
let existingSettings = {};
|
|
1145
1460
|
if (await fileManager.pathExists(settingsPath)) {
|
|
1146
1461
|
try {
|
|
1147
1462
|
const existingContent = await fileManager.readFile(settingsPath);
|
|
1148
1463
|
existingSettings = JSON.parse(existingContent);
|
|
1149
|
-
console.log(chalk.yellow(
|
|
1150
|
-
} catch
|
|
1151
|
-
console.warn(chalk.yellow(
|
|
1464
|
+
console.log(chalk.yellow('Found existing .vscode/settings.json. Merging BMad settings...'));
|
|
1465
|
+
} catch {
|
|
1466
|
+
console.warn(chalk.yellow('Could not parse existing settings.json. Creating new one.'));
|
|
1152
1467
|
existingSettings = {};
|
|
1153
1468
|
}
|
|
1154
1469
|
}
|
|
1155
|
-
|
|
1470
|
+
|
|
1156
1471
|
// Use pre-configured settings if provided, otherwise prompt
|
|
1157
1472
|
let configChoice;
|
|
1158
1473
|
if (preConfiguredSettings && preConfiguredSettings.configChoice) {
|
|
@@ -1161,10 +1476,12 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
|
|
|
1161
1476
|
} else {
|
|
1162
1477
|
// Clear any previous output and add spacing to avoid conflicts with loaders
|
|
1163
1478
|
console.log('\n'.repeat(2));
|
|
1164
|
-
console.log(chalk.blue(
|
|
1165
|
-
console.log(
|
|
1479
|
+
console.log(chalk.blue('🔧 Github Copilot Agent Settings Configuration'));
|
|
1480
|
+
console.log(
|
|
1481
|
+
chalk.dim('BMad works best with specific VS Code settings for optimal agent experience.'),
|
|
1482
|
+
);
|
|
1166
1483
|
console.log(''); // Add extra spacing
|
|
1167
|
-
|
|
1484
|
+
|
|
1168
1485
|
const response = await inquirer.prompt([
|
|
1169
1486
|
{
|
|
1170
1487
|
type: 'list',
|
|
@@ -1173,59 +1490,59 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
|
|
|
1173
1490
|
choices: [
|
|
1174
1491
|
{
|
|
1175
1492
|
name: 'Use recommended defaults (fastest setup)',
|
|
1176
|
-
value: 'defaults'
|
|
1493
|
+
value: 'defaults',
|
|
1177
1494
|
},
|
|
1178
1495
|
{
|
|
1179
1496
|
name: 'Configure each setting manually (customize to your preferences)',
|
|
1180
|
-
value: 'manual'
|
|
1497
|
+
value: 'manual',
|
|
1181
1498
|
},
|
|
1182
1499
|
{
|
|
1183
|
-
name:
|
|
1184
|
-
value: 'skip'
|
|
1185
|
-
}
|
|
1500
|
+
name: "Skip settings configuration (I'll configure manually later)",
|
|
1501
|
+
value: 'skip',
|
|
1502
|
+
},
|
|
1186
1503
|
],
|
|
1187
|
-
default: 'defaults'
|
|
1188
|
-
}
|
|
1504
|
+
default: 'defaults',
|
|
1505
|
+
},
|
|
1189
1506
|
]);
|
|
1190
1507
|
configChoice = response.configChoice;
|
|
1191
1508
|
}
|
|
1192
|
-
|
|
1509
|
+
|
|
1193
1510
|
let bmadSettings = {};
|
|
1194
|
-
|
|
1511
|
+
|
|
1195
1512
|
if (configChoice === 'skip') {
|
|
1196
|
-
console.log(chalk.yellow(
|
|
1197
|
-
console.log(chalk.dim(
|
|
1198
|
-
console.log(chalk.dim(
|
|
1199
|
-
console.log(chalk.dim(
|
|
1200
|
-
console.log(chalk.dim(
|
|
1201
|
-
console.log(chalk.dim(
|
|
1202
|
-
console.log(chalk.dim(
|
|
1203
|
-
console.log(chalk.dim(
|
|
1513
|
+
console.log(chalk.yellow('⚠️ Skipping VS Code settings configuration.'));
|
|
1514
|
+
console.log(chalk.dim('You can manually configure these settings in .vscode/settings.json:'));
|
|
1515
|
+
console.log(chalk.dim(' • chat.agent.enabled: true'));
|
|
1516
|
+
console.log(chalk.dim(' • chat.agent.maxRequests: 15'));
|
|
1517
|
+
console.log(chalk.dim(' • github.copilot.chat.agent.runTasks: true'));
|
|
1518
|
+
console.log(chalk.dim(' • chat.mcp.discovery.enabled: true'));
|
|
1519
|
+
console.log(chalk.dim(' • github.copilot.chat.agent.autoFix: true'));
|
|
1520
|
+
console.log(chalk.dim(' • chat.tools.autoApprove: false'));
|
|
1204
1521
|
return true;
|
|
1205
1522
|
}
|
|
1206
|
-
|
|
1523
|
+
|
|
1207
1524
|
if (configChoice === 'defaults') {
|
|
1208
1525
|
// Use recommended defaults
|
|
1209
1526
|
bmadSettings = {
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1527
|
+
'chat.agent.enabled': true,
|
|
1528
|
+
'chat.agent.maxRequests': 15,
|
|
1529
|
+
'github.copilot.chat.agent.runTasks': true,
|
|
1530
|
+
'chat.mcp.discovery.enabled': true,
|
|
1531
|
+
'github.copilot.chat.agent.autoFix': true,
|
|
1532
|
+
'chat.tools.autoApprove': false,
|
|
1216
1533
|
};
|
|
1217
|
-
console.log(chalk.green(
|
|
1534
|
+
console.log(chalk.green('✓ Using recommended BMad defaults for Github Copilot settings'));
|
|
1218
1535
|
} else {
|
|
1219
1536
|
// Manual configuration
|
|
1220
1537
|
console.log(chalk.blue("\n📋 Let's configure each setting for your preferences:"));
|
|
1221
|
-
|
|
1538
|
+
|
|
1222
1539
|
// Pause spinner during manual configuration prompts
|
|
1223
1540
|
let spinnerWasActive = false;
|
|
1224
1541
|
if (spinner && spinner.isSpinning) {
|
|
1225
1542
|
spinner.stop();
|
|
1226
1543
|
spinnerWasActive = true;
|
|
1227
1544
|
}
|
|
1228
|
-
|
|
1545
|
+
|
|
1229
1546
|
const manualSettings = await inquirer.prompt([
|
|
1230
1547
|
{
|
|
1231
1548
|
type: 'input',
|
|
@@ -1233,69 +1550,159 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
|
|
|
1233
1550
|
message: 'Maximum requests per agent session (recommended: 15)?',
|
|
1234
1551
|
default: '15',
|
|
1235
1552
|
validate: (input) => {
|
|
1236
|
-
const
|
|
1237
|
-
if (isNaN(
|
|
1553
|
+
const number_ = Number.parseInt(input);
|
|
1554
|
+
if (isNaN(number_) || number_ < 1 || number_ > 50) {
|
|
1238
1555
|
return 'Please enter a number between 1 and 50';
|
|
1239
1556
|
}
|
|
1240
1557
|
return true;
|
|
1241
|
-
}
|
|
1558
|
+
},
|
|
1242
1559
|
},
|
|
1243
1560
|
{
|
|
1244
1561
|
type: 'confirm',
|
|
1245
1562
|
name: 'runTasks',
|
|
1246
1563
|
message: 'Allow agents to run workspace tasks (package.json scripts, etc.)?',
|
|
1247
|
-
default: true
|
|
1564
|
+
default: true,
|
|
1248
1565
|
},
|
|
1249
1566
|
{
|
|
1250
1567
|
type: 'confirm',
|
|
1251
1568
|
name: 'mcpDiscovery',
|
|
1252
1569
|
message: 'Enable MCP (Model Context Protocol) server discovery?',
|
|
1253
|
-
default: true
|
|
1570
|
+
default: true,
|
|
1254
1571
|
},
|
|
1255
1572
|
{
|
|
1256
1573
|
type: 'confirm',
|
|
1257
1574
|
name: 'autoFix',
|
|
1258
1575
|
message: 'Enable automatic error detection and fixing in generated code?',
|
|
1259
|
-
default: true
|
|
1576
|
+
default: true,
|
|
1260
1577
|
},
|
|
1261
1578
|
{
|
|
1262
1579
|
type: 'confirm',
|
|
1263
1580
|
name: 'autoApprove',
|
|
1264
1581
|
message: 'Auto-approve ALL tools without confirmation? (⚠️ EXPERIMENTAL - less secure)',
|
|
1265
|
-
default: false
|
|
1266
|
-
}
|
|
1582
|
+
default: false,
|
|
1583
|
+
},
|
|
1267
1584
|
]);
|
|
1268
1585
|
|
|
1269
1586
|
// Restart spinner if it was active before prompts
|
|
1270
1587
|
if (spinner && spinnerWasActive) {
|
|
1271
1588
|
spinner.start();
|
|
1272
1589
|
}
|
|
1273
|
-
|
|
1590
|
+
|
|
1274
1591
|
bmadSettings = {
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1592
|
+
'chat.agent.enabled': true, // Always enabled - required for BMad agents
|
|
1593
|
+
'chat.agent.maxRequests': Number.parseInt(manualSettings.maxRequests),
|
|
1594
|
+
'github.copilot.chat.agent.runTasks': manualSettings.runTasks,
|
|
1595
|
+
'chat.mcp.discovery.enabled': manualSettings.mcpDiscovery,
|
|
1596
|
+
'github.copilot.chat.agent.autoFix': manualSettings.autoFix,
|
|
1597
|
+
'chat.tools.autoApprove': manualSettings.autoApprove,
|
|
1281
1598
|
};
|
|
1282
|
-
|
|
1283
|
-
console.log(chalk.green(
|
|
1599
|
+
|
|
1600
|
+
console.log(chalk.green('✓ Custom settings configured'));
|
|
1284
1601
|
}
|
|
1285
|
-
|
|
1602
|
+
|
|
1286
1603
|
// Merge settings (existing settings take precedence to avoid overriding user preferences)
|
|
1287
1604
|
const mergedSettings = { ...bmadSettings, ...existingSettings };
|
|
1288
|
-
|
|
1605
|
+
|
|
1289
1606
|
// Write the updated settings
|
|
1290
1607
|
await fileManager.writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2));
|
|
1291
|
-
|
|
1292
|
-
console.log(chalk.green(
|
|
1293
|
-
console.log(chalk.dim(
|
|
1294
|
-
|
|
1608
|
+
|
|
1609
|
+
console.log(chalk.green('✓ VS Code workspace settings configured successfully'));
|
|
1610
|
+
console.log(chalk.dim(' Settings written to .vscode/settings.json:'));
|
|
1611
|
+
for (const [key, value] of Object.entries(bmadSettings)) {
|
|
1295
1612
|
console.log(chalk.dim(` • ${key}: ${value}`));
|
|
1296
|
-
}
|
|
1297
|
-
console.log(chalk.dim(
|
|
1298
|
-
console.log(chalk.dim(
|
|
1613
|
+
}
|
|
1614
|
+
console.log(chalk.dim(''));
|
|
1615
|
+
console.log(chalk.dim('You can modify these settings anytime in .vscode/settings.json'));
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
async setupAuggieCLI(installDir, selectedAgent, spinner = null, preConfiguredSettings = null) {
|
|
1619
|
+
const os = require('node:os');
|
|
1620
|
+
const inquirer = require('inquirer');
|
|
1621
|
+
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
1622
|
+
|
|
1623
|
+
// Get the IDE configuration to access location options
|
|
1624
|
+
const ideConfig = await configLoader.getIdeConfiguration('auggie-cli');
|
|
1625
|
+
const locations = ideConfig.locations;
|
|
1626
|
+
|
|
1627
|
+
// Use pre-configured settings if provided, otherwise prompt
|
|
1628
|
+
let selectedLocations;
|
|
1629
|
+
if (preConfiguredSettings && preConfiguredSettings.selectedLocations) {
|
|
1630
|
+
selectedLocations = preConfiguredSettings.selectedLocations;
|
|
1631
|
+
console.log(
|
|
1632
|
+
chalk.dim(
|
|
1633
|
+
`Using pre-configured Auggie CLI (Augment Code) locations: ${selectedLocations.join(', ')}`,
|
|
1634
|
+
),
|
|
1635
|
+
);
|
|
1636
|
+
} else {
|
|
1637
|
+
// Pause spinner during location selection to avoid UI conflicts
|
|
1638
|
+
let spinnerWasActive = false;
|
|
1639
|
+
if (spinner && spinner.isSpinning) {
|
|
1640
|
+
spinner.stop();
|
|
1641
|
+
spinnerWasActive = true;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
// Clear any previous output and add spacing to avoid conflicts with loaders
|
|
1645
|
+
console.log('\n'.repeat(2));
|
|
1646
|
+
console.log(chalk.blue('📍 Auggie CLI Location Configuration'));
|
|
1647
|
+
console.log(chalk.dim('Choose where to install BMad agents for Auggie CLI access.'));
|
|
1648
|
+
console.log(''); // Add extra spacing
|
|
1649
|
+
|
|
1650
|
+
const response = await inquirer.prompt([
|
|
1651
|
+
{
|
|
1652
|
+
type: 'checkbox',
|
|
1653
|
+
name: 'selectedLocations',
|
|
1654
|
+
message: 'Select Auggie CLI command locations:',
|
|
1655
|
+
choices: Object.entries(locations).map(([key, location]) => ({
|
|
1656
|
+
name: `${location.name}: ${location.description}`,
|
|
1657
|
+
value: key,
|
|
1658
|
+
})),
|
|
1659
|
+
validate: (selected) => {
|
|
1660
|
+
if (selected.length === 0) {
|
|
1661
|
+
return 'Please select at least one location';
|
|
1662
|
+
}
|
|
1663
|
+
return true;
|
|
1664
|
+
},
|
|
1665
|
+
},
|
|
1666
|
+
]);
|
|
1667
|
+
selectedLocations = response.selectedLocations;
|
|
1668
|
+
|
|
1669
|
+
// Restart spinner if it was active before prompts
|
|
1670
|
+
if (spinner && spinnerWasActive) {
|
|
1671
|
+
spinner.start();
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
// Install to each selected location
|
|
1676
|
+
for (const locationKey of selectedLocations) {
|
|
1677
|
+
const location = locations[locationKey];
|
|
1678
|
+
let commandsDir = location['rule-dir'];
|
|
1679
|
+
|
|
1680
|
+
// Handle tilde expansion for user directory
|
|
1681
|
+
if (commandsDir.startsWith('~/')) {
|
|
1682
|
+
commandsDir = path.join(os.homedir(), commandsDir.slice(2));
|
|
1683
|
+
} else if (commandsDir.startsWith('./')) {
|
|
1684
|
+
commandsDir = path.join(installDir, commandsDir.slice(2));
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
await fileManager.ensureDirectory(commandsDir);
|
|
1688
|
+
|
|
1689
|
+
for (const agentId of agents) {
|
|
1690
|
+
// Find the agent file
|
|
1691
|
+
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
1692
|
+
|
|
1693
|
+
if (agentPath) {
|
|
1694
|
+
const agentContent = await fileManager.readFile(agentPath);
|
|
1695
|
+
const mdPath = path.join(commandsDir, `${agentId}.md`);
|
|
1696
|
+
await fileManager.writeFile(mdPath, agentContent);
|
|
1697
|
+
console.log(chalk.green(`✓ Created command: ${agentId}.md in ${location.name}`));
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
console.log(chalk.green(`\n✓ Created Auggie CLI commands in ${commandsDir}`));
|
|
1702
|
+
console.log(chalk.dim(` Location: ${location.name} - ${location.description}`));
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
return true;
|
|
1299
1706
|
}
|
|
1300
1707
|
}
|
|
1301
1708
|
|