bmad-method 4.37.0 → 4.39.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.md +3 -3
- package/.github/ISSUE_TEMPLATE/feature_request.md +3 -3
- package/.github/workflows/discord.yaml +11 -2
- package/.github/workflows/format-check.yaml +42 -0
- package/.github/workflows/manual-release.yaml +173 -0
- package/.husky/pre-commit +3 -0
- package/.vscode/settings.json +26 -1
- package/CHANGELOG.md +2 -23
- package/README.md +2 -0
- package/bmad-core/agent-teams/team-all.yaml +1 -1
- package/bmad-core/agents/analyst.md +16 -15
- package/bmad-core/agents/architect.md +11 -11
- package/bmad-core/agents/bmad-master.md +23 -22
- package/bmad-core/agents/bmad-orchestrator.md +13 -17
- package/bmad-core/agents/dev.md +14 -11
- package/bmad-core/agents/pm.md +15 -14
- package/bmad-core/agents/po.md +9 -8
- package/bmad-core/agents/qa.md +42 -22
- package/bmad-core/agents/sm.md +7 -6
- package/bmad-core/agents/ux-expert.md +6 -5
- package/bmad-core/core-config.yaml +2 -0
- package/bmad-core/data/bmad-kb.md +1 -1
- package/bmad-core/data/test-levels-framework.md +146 -0
- package/bmad-core/data/test-priorities-matrix.md +172 -0
- package/bmad-core/tasks/apply-qa-fixes.md +148 -0
- package/bmad-core/tasks/facilitate-brainstorming-session.md +1 -1
- package/bmad-core/tasks/nfr-assess.md +343 -0
- package/bmad-core/tasks/qa-gate.md +161 -0
- package/bmad-core/tasks/review-story.md +234 -74
- package/bmad-core/tasks/risk-profile.md +353 -0
- package/bmad-core/tasks/test-design.md +174 -0
- package/bmad-core/tasks/trace-requirements.md +264 -0
- package/bmad-core/templates/architecture-tmpl.yaml +49 -49
- package/bmad-core/templates/brainstorming-output-tmpl.yaml +5 -5
- package/bmad-core/templates/brownfield-architecture-tmpl.yaml +31 -31
- package/bmad-core/templates/brownfield-prd-tmpl.yaml +13 -13
- package/bmad-core/templates/competitor-analysis-tmpl.yaml +19 -6
- package/bmad-core/templates/front-end-architecture-tmpl.yaml +21 -9
- package/bmad-core/templates/front-end-spec-tmpl.yaml +24 -24
- package/bmad-core/templates/fullstack-architecture-tmpl.yaml +122 -104
- package/bmad-core/templates/market-research-tmpl.yaml +2 -2
- package/bmad-core/templates/prd-tmpl.yaml +9 -9
- package/bmad-core/templates/project-brief-tmpl.yaml +4 -4
- package/bmad-core/templates/qa-gate-tmpl.yaml +102 -0
- package/bmad-core/templates/story-tmpl.yaml +12 -12
- package/bmad-core/workflows/brownfield-fullstack.yaml +9 -9
- package/bmad-core/workflows/brownfield-service.yaml +1 -1
- package/bmad-core/workflows/brownfield-ui.yaml +1 -1
- package/bmad-core/workflows/greenfield-fullstack.yaml +1 -1
- package/bmad-core/workflows/greenfield-service.yaml +1 -1
- package/bmad-core/workflows/greenfield-ui.yaml +1 -1
- package/common/utils/bmad-doc-template.md +5 -5
- package/dist/agents/analyst.txt +1086 -1079
- package/dist/agents/architect.txt +1534 -1526
- package/dist/agents/bmad-master.txt +646 -632
- package/dist/agents/bmad-orchestrator.txt +40 -18
- package/dist/agents/dev.txt +158 -19
- package/dist/agents/pm.txt +1082 -1107
- package/dist/agents/po.txt +314 -332
- package/dist/agents/qa.txt +1754 -151
- package/dist/agents/sm.txt +88 -98
- package/dist/agents/ux-expert.txt +80 -87
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +109 -146
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.txt +75 -86
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.txt +41 -48
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +1903 -1941
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.txt +15 -50
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.txt +149 -195
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.txt +0 -15
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.txt +20 -37
- package/dist/expansion-packs/bmad-2d-unity-game-dev/teams/unity-2d-game-team.txt +2660 -2752
- package/dist/expansion-packs/bmad-creative-writing/agents/beta-reader.txt +871 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/book-critic.txt +78 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/character-psychologist.txt +839 -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 +861 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/editor.txt +796 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/genre-specialist.txt +927 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/narrative-designer.txt +842 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/plot-architect.txt +1126 -0
- package/dist/expansion-packs/bmad-creative-writing/agents/world-builder.txt +864 -0
- package/dist/expansion-packs/bmad-creative-writing/teams/agent-team.txt +5917 -0
- package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +25 -27
- package/dist/teams/team-all.txt +5541 -3768
- package/dist/teams/team-fullstack.txt +3014 -2987
- package/dist/teams/team-ide-minimal.txt +2219 -469
- package/dist/teams/team-no-ui.txt +2993 -2966
- package/docs/enhanced-ide-development-workflow.md +220 -15
- package/docs/user-guide.md +271 -18
- package/docs/versioning-and-releases.md +122 -44
- package/docs/working-in-the-brownfield.md +264 -31
- package/eslint.config.mjs +119 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.md +4 -4
- package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.md +1 -1
- package/expansion-packs/bmad-2d-phaser-game-dev/config.yaml +1 -1
- package/expansion-packs/bmad-2d-phaser-game-dev/data/development-guidelines.md +26 -28
- package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-architecture-tmpl.yaml +50 -50
- package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-brief-tmpl.yaml +23 -23
- package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-design-doc-tmpl.yaml +24 -24
- package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-story-tmpl.yaml +42 -42
- package/expansion-packs/bmad-2d-phaser-game-dev/templates/level-design-doc-tmpl.yaml +65 -65
- package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-dev-greenfield.yaml +5 -5
- package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-prototype.yaml +1 -1
- package/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.md +3 -3
- package/expansion-packs/bmad-2d-unity-game-dev/config.yaml +1 -1
- package/expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md +1 -1
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-brief-tmpl.yaml +23 -23
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml +63 -63
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-story-tmpl.yaml +20 -20
- package/expansion-packs/bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml +65 -65
- package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-dev-greenfield.yaml +5 -5
- package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-prototype.yaml +1 -1
- package/expansion-packs/bmad-creative-writing/README.md +132 -0
- package/expansion-packs/bmad-creative-writing/agent-teams/agent-team.yaml +19 -0
- package/expansion-packs/bmad-creative-writing/agents/beta-reader.md +91 -0
- package/expansion-packs/bmad-creative-writing/agents/book-critic.md +35 -0
- package/expansion-packs/bmad-creative-writing/agents/character-psychologist.md +90 -0
- package/expansion-packs/bmad-creative-writing/agents/cover-designer.md +41 -0
- package/expansion-packs/bmad-creative-writing/agents/dialog-specialist.md +89 -0
- package/expansion-packs/bmad-creative-writing/agents/editor.md +90 -0
- package/expansion-packs/bmad-creative-writing/agents/genre-specialist.md +92 -0
- package/expansion-packs/bmad-creative-writing/agents/narrative-designer.md +90 -0
- package/expansion-packs/bmad-creative-writing/agents/plot-architect.md +92 -0
- package/expansion-packs/bmad-creative-writing/agents/world-builder.md +91 -0
- package/expansion-packs/bmad-creative-writing/checklists/beta-feedback-closure-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/character-consistency-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/comedic-timing-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/cyberpunk-aesthetic-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/ebook-formatting-checklist.md +15 -0
- package/expansion-packs/bmad-creative-writing/checklists/epic-poetry-meter-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/fantasy-magic-system-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/foreshadowing-payoff-checklist.md +15 -0
- package/expansion-packs/bmad-creative-writing/checklists/genre-tropes-checklist.md +15 -0
- package/expansion-packs/bmad-creative-writing/checklists/historical-accuracy-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/horror-suspense-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/kdp-cover-ready-checklist.md +18 -0
- package/expansion-packs/bmad-creative-writing/checklists/line-edit-quality-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/marketing-copy-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/mystery-clue-trail-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/orbital-mechanics-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/plot-structure-checklist.md +49 -0
- package/expansion-packs/bmad-creative-writing/checklists/publication-readiness-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/romance-emotional-beats-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/scene-quality-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/scifi-technology-plausibility-checklist.md +15 -0
- package/expansion-packs/bmad-creative-writing/checklists/sensitivity-representation-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/steampunk-gadget-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/thriller-pacing-stakes-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/timeline-continuity-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/world-building-continuity-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/checklists/ya-appropriateness-checklist.md +16 -0
- package/expansion-packs/bmad-creative-writing/config.yaml +11 -0
- package/expansion-packs/bmad-creative-writing/data/bmad-kb.md +197 -0
- package/expansion-packs/bmad-creative-writing/data/story-structures.md +58 -0
- package/expansion-packs/bmad-creative-writing/docs/brief.md +183 -0
- package/expansion-packs/bmad-creative-writing/tasks/advanced-elicitation.md +117 -0
- package/expansion-packs/bmad-creative-writing/tasks/analyze-reader-feedback.md +16 -0
- package/expansion-packs/bmad-creative-writing/tasks/analyze-story-structure.md +55 -0
- package/expansion-packs/bmad-creative-writing/tasks/assemble-kdp-package.md +22 -0
- package/expansion-packs/bmad-creative-writing/tasks/brainstorm-premise.md +16 -0
- package/expansion-packs/bmad-creative-writing/tasks/build-world.md +17 -0
- package/expansion-packs/bmad-creative-writing/tasks/character-depth-pass.md +15 -0
- package/expansion-packs/bmad-creative-writing/tasks/create-doc.md +101 -0
- package/expansion-packs/bmad-creative-writing/tasks/create-draft-section.md +19 -0
- package/expansion-packs/bmad-creative-writing/tasks/critical-review.md +19 -0
- package/expansion-packs/bmad-creative-writing/tasks/develop-character.md +17 -0
- package/expansion-packs/bmad-creative-writing/tasks/execute-checklist.md +93 -0
- package/expansion-packs/bmad-creative-writing/tasks/expand-premise.md +16 -0
- package/expansion-packs/bmad-creative-writing/tasks/expand-synopsis.md +16 -0
- package/expansion-packs/bmad-creative-writing/tasks/final-polish.md +16 -0
- package/expansion-packs/bmad-creative-writing/tasks/generate-cover-brief.md +18 -0
- package/expansion-packs/bmad-creative-writing/tasks/generate-cover-prompts.md +19 -0
- package/expansion-packs/bmad-creative-writing/tasks/generate-scene-list.md +16 -0
- package/expansion-packs/bmad-creative-writing/tasks/incorporate-feedback.md +18 -0
- package/expansion-packs/bmad-creative-writing/tasks/outline-scenes.md +16 -0
- package/expansion-packs/bmad-creative-writing/tasks/provide-feedback.md +17 -0
- package/expansion-packs/bmad-creative-writing/tasks/publish-chapter.md +16 -0
- package/expansion-packs/bmad-creative-writing/tasks/quick-feedback.md +15 -0
- package/expansion-packs/bmad-creative-writing/tasks/select-next-arc.md +16 -0
- package/expansion-packs/bmad-creative-writing/tasks/workshop-dialog.md +51 -0
- package/expansion-packs/bmad-creative-writing/templates/beta-feedback-form.yaml +96 -0
- package/expansion-packs/bmad-creative-writing/templates/chapter-draft-tmpl.yaml +81 -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 +97 -0
- package/expansion-packs/bmad-creative-writing/templates/premise-brief-tmpl.yaml +77 -0
- package/expansion-packs/bmad-creative-writing/templates/scene-list-tmpl.yaml +54 -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 +88 -0
- package/expansion-packs/bmad-creative-writing/workflows/book-cover-design-workflow.md +176 -0
- package/expansion-packs/bmad-creative-writing/workflows/novel-greenfield-workflow.yaml +58 -0
- package/expansion-packs/bmad-creative-writing/workflows/novel-serial-workflow.yaml +51 -0
- package/expansion-packs/bmad-creative-writing/workflows/novel-snowflake-workflow.yaml +69 -0
- package/expansion-packs/bmad-creative-writing/workflows/novel-writing.yaml +92 -0
- package/expansion-packs/bmad-creative-writing/workflows/screenplay-development.yaml +86 -0
- package/expansion-packs/bmad-creative-writing/workflows/series-planning.yaml +79 -0
- package/expansion-packs/bmad-creative-writing/workflows/short-story-creation.yaml +65 -0
- package/expansion-packs/bmad-infrastructure-devops/config.yaml +1 -1
- package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-architecture-tmpl.yaml +20 -20
- package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.yaml +7 -7
- package/package.json +62 -39
- package/prettier.config.mjs +32 -0
- package/sync-version.sh +23 -0
- package/tools/bmad-npx-wrapper.js +10 -10
- package/tools/builders/web-builder.js +124 -130
- package/tools/bump-all-versions.js +42 -33
- package/tools/bump-expansion-version.js +23 -16
- package/tools/cli.js +10 -12
- package/tools/flattener/aggregate.js +10 -10
- package/tools/flattener/binary.js +44 -17
- package/tools/flattener/discovery.js +19 -18
- package/tools/flattener/files.js +6 -6
- package/tools/flattener/ignoreRules.js +125 -125
- package/tools/flattener/main.js +426 -70
- package/tools/flattener/projectRoot.js +186 -25
- package/tools/flattener/prompts.js +9 -9
- package/tools/flattener/stats.helpers.js +395 -0
- package/tools/flattener/stats.js +64 -14
- package/tools/flattener/test-matrix.js +413 -0
- package/tools/flattener/xml.js +33 -31
- package/tools/installer/bin/bmad.js +156 -113
- package/tools/installer/config/ide-agent-config.yaml +1 -1
- package/tools/installer/config/install.config.yaml +13 -3
- package/tools/installer/lib/config-loader.js +46 -42
- package/tools/installer/lib/file-manager.js +91 -113
- package/tools/installer/lib/ide-base-setup.js +57 -56
- package/tools/installer/lib/ide-setup.js +545 -399
- package/tools/installer/lib/installer.js +875 -714
- 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 +26 -28
- package/tools/installer/package.json +19 -19
- package/tools/lib/dependency-resolver.js +26 -30
- package/tools/lib/yaml-utils.js +7 -7
- package/tools/preview-release-notes.js +66 -0
- package/tools/shared/bannerArt.js +3 -3
- package/tools/sync-installer-version.js +7 -9
- 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/yaml-format.js +56 -43
- package/.github/workflows/release.yaml +0 -60
- package/.releaserc.json +0 -21
- package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/Complete AI Agent System - Flowchart.svg +0 -102
- package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.1 Google Cloud Project Setup/1.1.1 - Initial Project Configuration - bash copy.txt +0 -13
- package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.1 Google Cloud Project Setup/1.1.1 - Initial Project Configuration - bash.txt +0 -13
- package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.2 Agent Development Kit Installation/1.2.2 - Basic Project Structure - txt.txt +0 -25
- package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.3 Core Configuration Files/1.3.1 - settings.py +0 -34
- package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.3 Core Configuration Files/1.3.2 - main.py - Base Application.py +0 -70
- package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.4 Deployment Configuration/1.4.2 - cloudbuild.yaml +0 -26
- package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/README.md +0 -109
- package/tools/semantic-release-sync-installer.js +0 -30
|
@@ -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,48 @@ 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
|
+
default: {
|
|
65
78
|
console.log(chalk.yellow(`\nIDE ${ide} not yet supported`));
|
|
66
79
|
return false;
|
|
80
|
+
}
|
|
67
81
|
}
|
|
68
82
|
}
|
|
69
83
|
|
|
70
84
|
async setupCursor(installDir, selectedAgent) {
|
|
71
|
-
const cursorRulesDir = path.join(installDir,
|
|
85
|
+
const cursorRulesDir = path.join(installDir, '.cursor', 'rules', 'bmad');
|
|
72
86
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
73
87
|
|
|
74
88
|
await fileManager.ensureDirectory(cursorRulesDir);
|
|
@@ -88,12 +102,57 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
88
102
|
return true;
|
|
89
103
|
}
|
|
90
104
|
|
|
105
|
+
async setupCrush(installDir, selectedAgent) {
|
|
106
|
+
// Setup bmad-core commands
|
|
107
|
+
const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
|
|
108
|
+
const coreAgents = selectedAgent ? [selectedAgent] : await this.getCoreAgentIds(installDir);
|
|
109
|
+
const coreTasks = await this.getCoreTaskIds(installDir);
|
|
110
|
+
await this.setupCrushForPackage(
|
|
111
|
+
installDir,
|
|
112
|
+
'core',
|
|
113
|
+
coreSlashPrefix,
|
|
114
|
+
coreAgents,
|
|
115
|
+
coreTasks,
|
|
116
|
+
'.bmad-core',
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// Setup expansion pack commands
|
|
120
|
+
const expansionPacks = await this.getInstalledExpansionPacks(installDir);
|
|
121
|
+
for (const packInfo of expansionPacks) {
|
|
122
|
+
const packSlashPrefix = await this.getExpansionPackSlashPrefix(packInfo.path);
|
|
123
|
+
const packAgents = await this.getExpansionPackAgents(packInfo.path);
|
|
124
|
+
const packTasks = await this.getExpansionPackTasks(packInfo.path);
|
|
125
|
+
|
|
126
|
+
if (packAgents.length > 0 || packTasks.length > 0) {
|
|
127
|
+
// Use the actual directory name where the expansion pack is installed
|
|
128
|
+
const rootPath = path.relative(installDir, packInfo.path);
|
|
129
|
+
await this.setupCrushForPackage(
|
|
130
|
+
installDir,
|
|
131
|
+
packInfo.name,
|
|
132
|
+
packSlashPrefix,
|
|
133
|
+
packAgents,
|
|
134
|
+
packTasks,
|
|
135
|
+
rootPath,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
|
|
91
143
|
async setupClaudeCode(installDir, selectedAgent) {
|
|
92
144
|
// Setup bmad-core commands
|
|
93
145
|
const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
|
|
94
146
|
const coreAgents = selectedAgent ? [selectedAgent] : await this.getCoreAgentIds(installDir);
|
|
95
147
|
const coreTasks = await this.getCoreTaskIds(installDir);
|
|
96
|
-
await this.setupClaudeCodeForPackage(
|
|
148
|
+
await this.setupClaudeCodeForPackage(
|
|
149
|
+
installDir,
|
|
150
|
+
'core',
|
|
151
|
+
coreSlashPrefix,
|
|
152
|
+
coreAgents,
|
|
153
|
+
coreTasks,
|
|
154
|
+
'.bmad-core',
|
|
155
|
+
);
|
|
97
156
|
|
|
98
157
|
// Setup expansion pack commands
|
|
99
158
|
const expansionPacks = await this.getInstalledExpansionPacks(installDir);
|
|
@@ -101,21 +160,35 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
101
160
|
const packSlashPrefix = await this.getExpansionPackSlashPrefix(packInfo.path);
|
|
102
161
|
const packAgents = await this.getExpansionPackAgents(packInfo.path);
|
|
103
162
|
const packTasks = await this.getExpansionPackTasks(packInfo.path);
|
|
104
|
-
|
|
163
|
+
|
|
105
164
|
if (packAgents.length > 0 || packTasks.length > 0) {
|
|
106
165
|
// Use the actual directory name where the expansion pack is installed
|
|
107
166
|
const rootPath = path.relative(installDir, packInfo.path);
|
|
108
|
-
await this.setupClaudeCodeForPackage(
|
|
167
|
+
await this.setupClaudeCodeForPackage(
|
|
168
|
+
installDir,
|
|
169
|
+
packInfo.name,
|
|
170
|
+
packSlashPrefix,
|
|
171
|
+
packAgents,
|
|
172
|
+
packTasks,
|
|
173
|
+
rootPath,
|
|
174
|
+
);
|
|
109
175
|
}
|
|
110
176
|
}
|
|
111
177
|
|
|
112
178
|
return true;
|
|
113
179
|
}
|
|
114
180
|
|
|
115
|
-
async setupClaudeCodeForPackage(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
181
|
+
async setupClaudeCodeForPackage(
|
|
182
|
+
installDir,
|
|
183
|
+
packageName,
|
|
184
|
+
slashPrefix,
|
|
185
|
+
agentIds,
|
|
186
|
+
taskIds,
|
|
187
|
+
rootPath,
|
|
188
|
+
) {
|
|
189
|
+
const commandsBaseDir = path.join(installDir, '.claude', 'commands', slashPrefix);
|
|
190
|
+
const agentsDir = path.join(commandsBaseDir, 'agents');
|
|
191
|
+
const tasksDir = path.join(commandsBaseDir, 'tasks');
|
|
119
192
|
|
|
120
193
|
// Ensure directories exist
|
|
121
194
|
await fileManager.ensureDirectory(agentsDir);
|
|
@@ -125,28 +198,28 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
125
198
|
for (const agentId of agentIds) {
|
|
126
199
|
// Find the agent file - for expansion packs, prefer the expansion pack version
|
|
127
200
|
let agentPath;
|
|
128
|
-
if (packageName
|
|
201
|
+
if (packageName === 'core') {
|
|
202
|
+
// For core, use the normal search
|
|
203
|
+
agentPath = await this.findAgentPath(agentId, installDir);
|
|
204
|
+
} else {
|
|
129
205
|
// For expansion packs, first try to find the agent in the expansion pack directory
|
|
130
|
-
const expansionPackPath = path.join(installDir, rootPath,
|
|
206
|
+
const expansionPackPath = path.join(installDir, rootPath, 'agents', `${agentId}.md`);
|
|
131
207
|
if (await fileManager.pathExists(expansionPackPath)) {
|
|
132
208
|
agentPath = expansionPackPath;
|
|
133
209
|
} else {
|
|
134
210
|
// Fall back to core if not found in expansion pack
|
|
135
211
|
agentPath = await this.findAgentPath(agentId, installDir);
|
|
136
212
|
}
|
|
137
|
-
} else {
|
|
138
|
-
// For core, use the normal search
|
|
139
|
-
agentPath = await this.findAgentPath(agentId, installDir);
|
|
140
213
|
}
|
|
141
|
-
|
|
214
|
+
|
|
142
215
|
const commandPath = path.join(agentsDir, `${agentId}.md`);
|
|
143
216
|
|
|
144
217
|
if (agentPath) {
|
|
145
218
|
// Create command file with agent content
|
|
146
219
|
let agentContent = await fileManager.readFile(agentPath);
|
|
147
|
-
|
|
220
|
+
|
|
148
221
|
// Replace {root} placeholder with the appropriate root path for this context
|
|
149
|
-
agentContent = agentContent.
|
|
222
|
+
agentContent = agentContent.replaceAll('{root}', rootPath);
|
|
150
223
|
|
|
151
224
|
// Add command header
|
|
152
225
|
let commandContent = `# /${agentId} Command\n\n`;
|
|
@@ -162,28 +235,118 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
162
235
|
for (const taskId of taskIds) {
|
|
163
236
|
// Find the task file - for expansion packs, prefer the expansion pack version
|
|
164
237
|
let taskPath;
|
|
165
|
-
if (packageName
|
|
238
|
+
if (packageName === 'core') {
|
|
239
|
+
// For core, use the normal search
|
|
240
|
+
taskPath = await this.findTaskPath(taskId, installDir);
|
|
241
|
+
} else {
|
|
166
242
|
// For expansion packs, first try to find the task in the expansion pack directory
|
|
167
|
-
const expansionPackPath = path.join(installDir, rootPath,
|
|
243
|
+
const expansionPackPath = path.join(installDir, rootPath, 'tasks', `${taskId}.md`);
|
|
168
244
|
if (await fileManager.pathExists(expansionPackPath)) {
|
|
169
245
|
taskPath = expansionPackPath;
|
|
170
246
|
} else {
|
|
171
247
|
// Fall back to core if not found in expansion pack
|
|
172
248
|
taskPath = await this.findTaskPath(taskId, installDir);
|
|
173
249
|
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const commandPath = path.join(tasksDir, `${taskId}.md`);
|
|
253
|
+
|
|
254
|
+
if (taskPath) {
|
|
255
|
+
// Create command file with task content
|
|
256
|
+
let taskContent = await fileManager.readFile(taskPath);
|
|
257
|
+
|
|
258
|
+
// Replace {root} placeholder with the appropriate root path for this context
|
|
259
|
+
taskContent = taskContent.replaceAll('{root}', rootPath);
|
|
260
|
+
|
|
261
|
+
// Add command header
|
|
262
|
+
let commandContent = `# /${taskId} Task\n\n`;
|
|
263
|
+
commandContent += `When this command is used, execute the following task:\n\n`;
|
|
264
|
+
commandContent += taskContent;
|
|
265
|
+
|
|
266
|
+
await fileManager.writeFile(commandPath, commandContent);
|
|
267
|
+
console.log(chalk.green(`✓ Created task command: /${taskId}`));
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
console.log(
|
|
272
|
+
chalk.green(`\n✓ Created Claude Code commands for ${packageName} in ${commandsBaseDir}`),
|
|
273
|
+
);
|
|
274
|
+
console.log(chalk.dim(` - Agents in: ${agentsDir}`));
|
|
275
|
+
console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async setupCrushForPackage(installDir, packageName, slashPrefix, agentIds, taskIds, rootPath) {
|
|
279
|
+
const commandsBaseDir = path.join(installDir, '.crush', 'commands', slashPrefix);
|
|
280
|
+
const agentsDir = path.join(commandsBaseDir, 'agents');
|
|
281
|
+
const tasksDir = path.join(commandsBaseDir, 'tasks');
|
|
282
|
+
|
|
283
|
+
// Ensure directories exist
|
|
284
|
+
await fileManager.ensureDirectory(agentsDir);
|
|
285
|
+
await fileManager.ensureDirectory(tasksDir);
|
|
286
|
+
|
|
287
|
+
// Setup agents
|
|
288
|
+
for (const agentId of agentIds) {
|
|
289
|
+
// Find the agent file - for expansion packs, prefer the expansion pack version
|
|
290
|
+
let agentPath;
|
|
291
|
+
if (packageName === 'core') {
|
|
292
|
+
// For core, use the normal search
|
|
293
|
+
agentPath = await this.findAgentPath(agentId, installDir);
|
|
174
294
|
} else {
|
|
295
|
+
// For expansion packs, first try to find the agent in the expansion pack directory
|
|
296
|
+
const expansionPackPath = path.join(installDir, rootPath, 'agents', `${agentId}.md`);
|
|
297
|
+
if (await fileManager.pathExists(expansionPackPath)) {
|
|
298
|
+
agentPath = expansionPackPath;
|
|
299
|
+
} else {
|
|
300
|
+
// Fall back to core if not found in expansion pack
|
|
301
|
+
agentPath = await this.findAgentPath(agentId, installDir);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const commandPath = path.join(agentsDir, `${agentId}.md`);
|
|
306
|
+
|
|
307
|
+
if (agentPath) {
|
|
308
|
+
// Create command file with agent content
|
|
309
|
+
let agentContent = await fileManager.readFile(agentPath);
|
|
310
|
+
|
|
311
|
+
// Replace {root} placeholder with the appropriate root path for this context
|
|
312
|
+
agentContent = agentContent.replaceAll('{root}', rootPath);
|
|
313
|
+
|
|
314
|
+
// Add command header
|
|
315
|
+
let commandContent = `# /${agentId} Command\n\n`;
|
|
316
|
+
commandContent += `When this command is used, adopt the following agent persona:\n\n`;
|
|
317
|
+
commandContent += agentContent;
|
|
318
|
+
|
|
319
|
+
await fileManager.writeFile(commandPath, commandContent);
|
|
320
|
+
console.log(chalk.green(`✓ Created agent command: /${agentId}`));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Setup tasks
|
|
325
|
+
for (const taskId of taskIds) {
|
|
326
|
+
// Find the task file - for expansion packs, prefer the expansion pack version
|
|
327
|
+
let taskPath;
|
|
328
|
+
if (packageName === 'core') {
|
|
175
329
|
// For core, use the normal search
|
|
176
330
|
taskPath = await this.findTaskPath(taskId, installDir);
|
|
331
|
+
} else {
|
|
332
|
+
// For expansion packs, first try to find the task in the expansion pack directory
|
|
333
|
+
const expansionPackPath = path.join(installDir, rootPath, 'tasks', `${taskId}.md`);
|
|
334
|
+
if (await fileManager.pathExists(expansionPackPath)) {
|
|
335
|
+
taskPath = expansionPackPath;
|
|
336
|
+
} else {
|
|
337
|
+
// Fall back to core if not found in expansion pack
|
|
338
|
+
taskPath = await this.findTaskPath(taskId, installDir);
|
|
339
|
+
}
|
|
177
340
|
}
|
|
178
|
-
|
|
341
|
+
|
|
179
342
|
const commandPath = path.join(tasksDir, `${taskId}.md`);
|
|
180
343
|
|
|
181
344
|
if (taskPath) {
|
|
182
345
|
// Create command file with task content
|
|
183
346
|
let taskContent = await fileManager.readFile(taskPath);
|
|
184
|
-
|
|
347
|
+
|
|
185
348
|
// Replace {root} placeholder with the appropriate root path for this context
|
|
186
|
-
taskContent = taskContent.
|
|
349
|
+
taskContent = taskContent.replaceAll('{root}', rootPath);
|
|
187
350
|
|
|
188
351
|
// Add command header
|
|
189
352
|
let commandContent = `# /${taskId} Task\n\n`;
|
|
@@ -195,16 +358,16 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
195
358
|
}
|
|
196
359
|
}
|
|
197
360
|
|
|
198
|
-
console.log(chalk.green(`\n✓ Created
|
|
361
|
+
console.log(chalk.green(`\n✓ Created Crush commands for ${packageName} in ${commandsBaseDir}`));
|
|
199
362
|
console.log(chalk.dim(` - Agents in: ${agentsDir}`));
|
|
200
363
|
console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
|
|
201
364
|
}
|
|
202
365
|
|
|
203
366
|
async setupWindsurf(installDir, selectedAgent) {
|
|
204
|
-
const
|
|
367
|
+
const windsurfWorkflowDir = path.join(installDir, '.windsurf', 'workflows');
|
|
205
368
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
206
369
|
|
|
207
|
-
await fileManager.ensureDirectory(
|
|
370
|
+
await fileManager.ensureDirectory(windsurfWorkflowDir);
|
|
208
371
|
|
|
209
372
|
for (const agentId of agents) {
|
|
210
373
|
// Find the agent file
|
|
@@ -212,89 +375,67 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
212
375
|
|
|
213
376
|
if (agentPath) {
|
|
214
377
|
const agentContent = await fileManager.readFile(agentPath);
|
|
215
|
-
const mdPath = path.join(
|
|
378
|
+
const mdPath = path.join(windsurfWorkflowDir, `${agentId}.md`);
|
|
216
379
|
|
|
217
|
-
//
|
|
218
|
-
let mdContent =
|
|
219
|
-
mdContent += `
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
mdContent += "## Agent Activation\n\n";
|
|
224
|
-
mdContent +=
|
|
225
|
-
"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";
|
|
226
|
-
mdContent += "```yaml\n";
|
|
227
|
-
// Extract just the YAML content from the agent file
|
|
228
|
-
const yamlContent = extractYamlFromAgent(agentContent);
|
|
229
|
-
if (yamlContent) {
|
|
230
|
-
mdContent += yamlContent;
|
|
231
|
-
} else {
|
|
232
|
-
// If no YAML found, include the whole content minus the header
|
|
233
|
-
mdContent += agentContent.replace(/^#.*$/m, "").trim();
|
|
234
|
-
}
|
|
235
|
-
mdContent += "\n```\n\n";
|
|
236
|
-
mdContent += "## File Reference\n\n";
|
|
237
|
-
const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
|
|
238
|
-
mdContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
|
|
239
|
-
mdContent += "## Usage\n\n";
|
|
240
|
-
mdContent += `When the user types \`@${agentId}\`, activate this ${await this.getAgentTitle(
|
|
241
|
-
agentId,
|
|
242
|
-
installDir
|
|
243
|
-
)} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
380
|
+
// Write the agent file contents prefixed with Windsurf frontmatter
|
|
381
|
+
let mdContent = `---\n`;
|
|
382
|
+
mdContent += `description: ${agentId}\n`;
|
|
383
|
+
mdContent += `auto_execution_mode: 3\n`;
|
|
384
|
+
mdContent += `---\n\n`;
|
|
385
|
+
mdContent += agentContent;
|
|
244
386
|
|
|
245
387
|
await fileManager.writeFile(mdPath, mdContent);
|
|
246
|
-
console.log(chalk.green(`✓ Created
|
|
388
|
+
console.log(chalk.green(`✓ Created workflow: ${agentId}.md`));
|
|
247
389
|
}
|
|
248
390
|
}
|
|
249
391
|
|
|
250
|
-
console.log(chalk.green(`\n✓ Created Windsurf
|
|
392
|
+
console.log(chalk.green(`\n✓ Created Windsurf workflows in ${windsurfWorkflowDir}`));
|
|
251
393
|
|
|
252
394
|
return true;
|
|
253
395
|
}
|
|
254
396
|
|
|
255
397
|
async setupTrae(installDir, selectedAgent) {
|
|
256
|
-
const traeRulesDir = path.join(installDir,
|
|
257
|
-
const agents = selectedAgent? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
258
|
-
|
|
398
|
+
const traeRulesDir = path.join(installDir, '.trae', 'rules');
|
|
399
|
+
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
400
|
+
|
|
259
401
|
await fileManager.ensureDirectory(traeRulesDir);
|
|
260
|
-
|
|
402
|
+
|
|
261
403
|
for (const agentId of agents) {
|
|
262
404
|
// Find the agent file
|
|
263
405
|
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
264
|
-
|
|
406
|
+
|
|
265
407
|
if (agentPath) {
|
|
266
408
|
const agentContent = await fileManager.readFile(agentPath);
|
|
267
409
|
const mdPath = path.join(traeRulesDir, `${agentId}.md`);
|
|
268
|
-
|
|
410
|
+
|
|
269
411
|
// Create MD content (similar to Cursor but without frontmatter)
|
|
270
412
|
let mdContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
271
413
|
mdContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${await this.getAgentTitle(
|
|
272
414
|
agentId,
|
|
273
|
-
installDir
|
|
415
|
+
installDir,
|
|
274
416
|
)} agent persona.\n\n`;
|
|
275
|
-
mdContent +=
|
|
417
|
+
mdContent += '## Agent Activation\n\n';
|
|
276
418
|
mdContent +=
|
|
277
|
-
|
|
278
|
-
mdContent +=
|
|
419
|
+
'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';
|
|
420
|
+
mdContent += '```yaml\n';
|
|
279
421
|
// Extract just the YAML content from the agent file
|
|
280
422
|
const yamlContent = extractYamlFromAgent(agentContent);
|
|
281
423
|
if (yamlContent) {
|
|
282
424
|
mdContent += yamlContent;
|
|
283
|
-
}
|
|
284
|
-
else {
|
|
425
|
+
} else {
|
|
285
426
|
// If no YAML found, include the whole content minus the header
|
|
286
|
-
mdContent += agentContent.replace(/^#.*$/m,
|
|
427
|
+
mdContent += agentContent.replace(/^#.*$/m, '').trim();
|
|
287
428
|
}
|
|
288
|
-
mdContent +=
|
|
289
|
-
mdContent +=
|
|
290
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
429
|
+
mdContent += '\n```\n\n';
|
|
430
|
+
mdContent += '## File Reference\n\n';
|
|
431
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
291
432
|
mdContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
|
|
292
|
-
mdContent +=
|
|
433
|
+
mdContent += '## Usage\n\n';
|
|
293
434
|
mdContent += `When the user types \`@${agentId}\`, activate this ${await this.getAgentTitle(
|
|
294
435
|
agentId,
|
|
295
|
-
installDir
|
|
436
|
+
installDir,
|
|
296
437
|
)} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
297
|
-
|
|
438
|
+
|
|
298
439
|
await fileManager.writeFile(mdPath, mdContent);
|
|
299
440
|
console.log(chalk.green(`✓ Created rule: ${agentId}.md`));
|
|
300
441
|
}
|
|
@@ -304,116 +445,116 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
304
445
|
async findAgentPath(agentId, installDir) {
|
|
305
446
|
// Try to find the agent file in various locations
|
|
306
447
|
const possiblePaths = [
|
|
307
|
-
path.join(installDir,
|
|
308
|
-
path.join(installDir,
|
|
448
|
+
path.join(installDir, '.bmad-core', 'agents', `${agentId}.md`),
|
|
449
|
+
path.join(installDir, 'agents', `${agentId}.md`),
|
|
309
450
|
];
|
|
310
|
-
|
|
451
|
+
|
|
311
452
|
// Also check expansion pack directories
|
|
312
|
-
const glob = require(
|
|
313
|
-
const
|
|
314
|
-
for (const expDir of
|
|
453
|
+
const glob = require('glob');
|
|
454
|
+
const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
|
|
455
|
+
for (const expDir of expansionDirectories) {
|
|
315
456
|
possiblePaths.push(path.join(installDir, expDir, `${agentId}.md`));
|
|
316
457
|
}
|
|
317
|
-
|
|
458
|
+
|
|
318
459
|
for (const agentPath of possiblePaths) {
|
|
319
460
|
if (await fileManager.pathExists(agentPath)) {
|
|
320
461
|
return agentPath;
|
|
321
462
|
}
|
|
322
463
|
}
|
|
323
|
-
|
|
464
|
+
|
|
324
465
|
return null;
|
|
325
466
|
}
|
|
326
467
|
|
|
327
468
|
async getAllAgentIds(installDir) {
|
|
328
|
-
const glob = require(
|
|
469
|
+
const glob = require('glob');
|
|
329
470
|
const allAgentIds = [];
|
|
330
|
-
|
|
471
|
+
|
|
331
472
|
// Check core agents in .bmad-core or root
|
|
332
|
-
let agentsDir = path.join(installDir,
|
|
473
|
+
let agentsDir = path.join(installDir, '.bmad-core', 'agents');
|
|
333
474
|
if (!(await fileManager.pathExists(agentsDir))) {
|
|
334
|
-
agentsDir = path.join(installDir,
|
|
475
|
+
agentsDir = path.join(installDir, 'agents');
|
|
335
476
|
}
|
|
336
|
-
|
|
477
|
+
|
|
337
478
|
if (await fileManager.pathExists(agentsDir)) {
|
|
338
|
-
const agentFiles = glob.sync(
|
|
339
|
-
allAgentIds.push(...agentFiles.map((file) => path.basename(file,
|
|
479
|
+
const agentFiles = glob.sync('*.md', { cwd: agentsDir });
|
|
480
|
+
allAgentIds.push(...agentFiles.map((file) => path.basename(file, '.md')));
|
|
340
481
|
}
|
|
341
|
-
|
|
482
|
+
|
|
342
483
|
// Also check for expansion pack agents in dot folders
|
|
343
|
-
const
|
|
344
|
-
for (const expDir of
|
|
484
|
+
const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
|
|
485
|
+
for (const expDir of expansionDirectories) {
|
|
345
486
|
const fullExpDir = path.join(installDir, expDir);
|
|
346
|
-
const expAgentFiles = glob.sync(
|
|
347
|
-
allAgentIds.push(...expAgentFiles.map((file) => path.basename(file,
|
|
487
|
+
const expAgentFiles = glob.sync('*.md', { cwd: fullExpDir });
|
|
488
|
+
allAgentIds.push(...expAgentFiles.map((file) => path.basename(file, '.md')));
|
|
348
489
|
}
|
|
349
|
-
|
|
490
|
+
|
|
350
491
|
// Remove duplicates
|
|
351
492
|
return [...new Set(allAgentIds)];
|
|
352
493
|
}
|
|
353
494
|
|
|
354
495
|
async getCoreAgentIds(installDir) {
|
|
355
496
|
const allAgentIds = [];
|
|
356
|
-
|
|
497
|
+
|
|
357
498
|
// Check core agents in .bmad-core or root only
|
|
358
|
-
let agentsDir = path.join(installDir,
|
|
499
|
+
let agentsDir = path.join(installDir, '.bmad-core', 'agents');
|
|
359
500
|
if (!(await fileManager.pathExists(agentsDir))) {
|
|
360
|
-
agentsDir = path.join(installDir,
|
|
501
|
+
agentsDir = path.join(installDir, 'bmad-core', 'agents');
|
|
361
502
|
}
|
|
362
|
-
|
|
503
|
+
|
|
363
504
|
if (await fileManager.pathExists(agentsDir)) {
|
|
364
|
-
const glob = require(
|
|
365
|
-
const agentFiles = glob.sync(
|
|
366
|
-
allAgentIds.push(...agentFiles.map((file) => path.basename(file,
|
|
505
|
+
const glob = require('glob');
|
|
506
|
+
const agentFiles = glob.sync('*.md', { cwd: agentsDir });
|
|
507
|
+
allAgentIds.push(...agentFiles.map((file) => path.basename(file, '.md')));
|
|
367
508
|
}
|
|
368
|
-
|
|
509
|
+
|
|
369
510
|
return [...new Set(allAgentIds)];
|
|
370
511
|
}
|
|
371
512
|
|
|
372
513
|
async getCoreTaskIds(installDir) {
|
|
373
514
|
const allTaskIds = [];
|
|
374
|
-
|
|
515
|
+
|
|
375
516
|
// Check core tasks in .bmad-core or root only
|
|
376
|
-
let tasksDir = path.join(installDir,
|
|
517
|
+
let tasksDir = path.join(installDir, '.bmad-core', 'tasks');
|
|
377
518
|
if (!(await fileManager.pathExists(tasksDir))) {
|
|
378
|
-
tasksDir = path.join(installDir,
|
|
519
|
+
tasksDir = path.join(installDir, 'bmad-core', 'tasks');
|
|
379
520
|
}
|
|
380
|
-
|
|
521
|
+
|
|
381
522
|
if (await fileManager.pathExists(tasksDir)) {
|
|
382
|
-
const glob = require(
|
|
383
|
-
const taskFiles = glob.sync(
|
|
384
|
-
allTaskIds.push(...taskFiles.map((file) => path.basename(file,
|
|
523
|
+
const glob = require('glob');
|
|
524
|
+
const taskFiles = glob.sync('*.md', { cwd: tasksDir });
|
|
525
|
+
allTaskIds.push(...taskFiles.map((file) => path.basename(file, '.md')));
|
|
385
526
|
}
|
|
386
|
-
|
|
527
|
+
|
|
387
528
|
// Check common tasks
|
|
388
|
-
const commonTasksDir = path.join(installDir,
|
|
529
|
+
const commonTasksDir = path.join(installDir, 'common', 'tasks');
|
|
389
530
|
if (await fileManager.pathExists(commonTasksDir)) {
|
|
390
|
-
const commonTaskFiles = glob.sync(
|
|
391
|
-
allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file,
|
|
531
|
+
const commonTaskFiles = glob.sync('*.md', { cwd: commonTasksDir });
|
|
532
|
+
allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, '.md')));
|
|
392
533
|
}
|
|
393
|
-
|
|
534
|
+
|
|
394
535
|
return [...new Set(allTaskIds)];
|
|
395
536
|
}
|
|
396
537
|
|
|
397
538
|
async getAgentTitle(agentId, installDir) {
|
|
398
539
|
// Try to find the agent file in various locations
|
|
399
540
|
const possiblePaths = [
|
|
400
|
-
path.join(installDir,
|
|
401
|
-
path.join(installDir,
|
|
541
|
+
path.join(installDir, '.bmad-core', 'agents', `${agentId}.md`),
|
|
542
|
+
path.join(installDir, 'agents', `${agentId}.md`),
|
|
402
543
|
];
|
|
403
|
-
|
|
544
|
+
|
|
404
545
|
// Also check expansion pack directories
|
|
405
|
-
const glob = require(
|
|
406
|
-
const
|
|
407
|
-
for (const expDir of
|
|
546
|
+
const glob = require('glob');
|
|
547
|
+
const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
|
|
548
|
+
for (const expDir of expansionDirectories) {
|
|
408
549
|
possiblePaths.push(path.join(installDir, expDir, `${agentId}.md`));
|
|
409
550
|
}
|
|
410
|
-
|
|
551
|
+
|
|
411
552
|
for (const agentPath of possiblePaths) {
|
|
412
553
|
if (await fileManager.pathExists(agentPath)) {
|
|
413
554
|
try {
|
|
414
555
|
const agentContent = await fileManager.readFile(agentPath);
|
|
415
556
|
const yamlMatch = agentContent.match(/```ya?ml\r?\n([\s\S]*?)```/);
|
|
416
|
-
|
|
557
|
+
|
|
417
558
|
if (yamlMatch) {
|
|
418
559
|
const yaml = yamlMatch[1];
|
|
419
560
|
const titleMatch = yaml.match(/title:\s*(.+)/);
|
|
@@ -426,54 +567,55 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
426
567
|
}
|
|
427
568
|
}
|
|
428
569
|
}
|
|
429
|
-
|
|
570
|
+
|
|
430
571
|
// Fallback to formatted agent ID
|
|
431
|
-
return agentId
|
|
432
|
-
|
|
433
|
-
|
|
572
|
+
return agentId
|
|
573
|
+
.split('-')
|
|
574
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
575
|
+
.join(' ');
|
|
434
576
|
}
|
|
435
577
|
|
|
436
578
|
async getAllTaskIds(installDir) {
|
|
437
|
-
const glob = require(
|
|
579
|
+
const glob = require('glob');
|
|
438
580
|
const allTaskIds = [];
|
|
439
|
-
|
|
581
|
+
|
|
440
582
|
// Check core tasks in .bmad-core or root
|
|
441
|
-
let tasksDir = path.join(installDir,
|
|
583
|
+
let tasksDir = path.join(installDir, '.bmad-core', 'tasks');
|
|
442
584
|
if (!(await fileManager.pathExists(tasksDir))) {
|
|
443
|
-
tasksDir = path.join(installDir,
|
|
585
|
+
tasksDir = path.join(installDir, 'bmad-core', 'tasks');
|
|
444
586
|
}
|
|
445
|
-
|
|
587
|
+
|
|
446
588
|
if (await fileManager.pathExists(tasksDir)) {
|
|
447
|
-
const taskFiles = glob.sync(
|
|
448
|
-
allTaskIds.push(...taskFiles.map((file) => path.basename(file,
|
|
589
|
+
const taskFiles = glob.sync('*.md', { cwd: tasksDir });
|
|
590
|
+
allTaskIds.push(...taskFiles.map((file) => path.basename(file, '.md')));
|
|
449
591
|
}
|
|
450
|
-
|
|
592
|
+
|
|
451
593
|
// Check common tasks
|
|
452
|
-
const commonTasksDir = path.join(installDir,
|
|
594
|
+
const commonTasksDir = path.join(installDir, 'common', 'tasks');
|
|
453
595
|
if (await fileManager.pathExists(commonTasksDir)) {
|
|
454
|
-
const commonTaskFiles = glob.sync(
|
|
455
|
-
allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file,
|
|
596
|
+
const commonTaskFiles = glob.sync('*.md', { cwd: commonTasksDir });
|
|
597
|
+
allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, '.md')));
|
|
456
598
|
}
|
|
457
|
-
|
|
599
|
+
|
|
458
600
|
// Also check for expansion pack tasks in dot folders
|
|
459
|
-
const
|
|
460
|
-
for (const expDir of
|
|
601
|
+
const expansionDirectories = glob.sync('.*/tasks', { cwd: installDir });
|
|
602
|
+
for (const expDir of expansionDirectories) {
|
|
461
603
|
const fullExpDir = path.join(installDir, expDir);
|
|
462
|
-
const expTaskFiles = glob.sync(
|
|
463
|
-
allTaskIds.push(...expTaskFiles.map((file) => path.basename(file,
|
|
604
|
+
const expTaskFiles = glob.sync('*.md', { cwd: fullExpDir });
|
|
605
|
+
allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, '.md')));
|
|
464
606
|
}
|
|
465
|
-
|
|
607
|
+
|
|
466
608
|
// Check expansion-packs folder tasks
|
|
467
|
-
const expansionPacksDir = path.join(installDir,
|
|
609
|
+
const expansionPacksDir = path.join(installDir, 'expansion-packs');
|
|
468
610
|
if (await fileManager.pathExists(expansionPacksDir)) {
|
|
469
|
-
const
|
|
470
|
-
for (const expDir of
|
|
611
|
+
const expPackDirectories = glob.sync('*/tasks', { cwd: expansionPacksDir });
|
|
612
|
+
for (const expDir of expPackDirectories) {
|
|
471
613
|
const fullExpDir = path.join(expansionPacksDir, expDir);
|
|
472
|
-
const expTaskFiles = glob.sync(
|
|
473
|
-
allTaskIds.push(...expTaskFiles.map((file) => path.basename(file,
|
|
614
|
+
const expTaskFiles = glob.sync('*.md', { cwd: fullExpDir });
|
|
615
|
+
allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, '.md')));
|
|
474
616
|
}
|
|
475
617
|
}
|
|
476
|
-
|
|
618
|
+
|
|
477
619
|
// Remove duplicates
|
|
478
620
|
return [...new Set(allTaskIds)];
|
|
479
621
|
}
|
|
@@ -481,102 +623,104 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
481
623
|
async findTaskPath(taskId, installDir) {
|
|
482
624
|
// Try to find the task file in various locations
|
|
483
625
|
const possiblePaths = [
|
|
484
|
-
path.join(installDir,
|
|
485
|
-
path.join(installDir,
|
|
486
|
-
path.join(installDir,
|
|
626
|
+
path.join(installDir, '.bmad-core', 'tasks', `${taskId}.md`),
|
|
627
|
+
path.join(installDir, 'bmad-core', 'tasks', `${taskId}.md`),
|
|
628
|
+
path.join(installDir, 'common', 'tasks', `${taskId}.md`),
|
|
487
629
|
];
|
|
488
|
-
|
|
630
|
+
|
|
489
631
|
// Also check expansion pack directories
|
|
490
|
-
const glob = require(
|
|
491
|
-
|
|
632
|
+
const glob = require('glob');
|
|
633
|
+
|
|
492
634
|
// Check dot folder expansion packs
|
|
493
|
-
const
|
|
494
|
-
for (const expDir of
|
|
635
|
+
const expansionDirectories = glob.sync('.*/tasks', { cwd: installDir });
|
|
636
|
+
for (const expDir of expansionDirectories) {
|
|
495
637
|
possiblePaths.push(path.join(installDir, expDir, `${taskId}.md`));
|
|
496
638
|
}
|
|
497
|
-
|
|
639
|
+
|
|
498
640
|
// Check expansion-packs folder
|
|
499
|
-
const expansionPacksDir = path.join(installDir,
|
|
641
|
+
const expansionPacksDir = path.join(installDir, 'expansion-packs');
|
|
500
642
|
if (await fileManager.pathExists(expansionPacksDir)) {
|
|
501
|
-
const
|
|
502
|
-
for (const expDir of
|
|
643
|
+
const expPackDirectories = glob.sync('*/tasks', { cwd: expansionPacksDir });
|
|
644
|
+
for (const expDir of expPackDirectories) {
|
|
503
645
|
possiblePaths.push(path.join(expansionPacksDir, expDir, `${taskId}.md`));
|
|
504
646
|
}
|
|
505
647
|
}
|
|
506
|
-
|
|
648
|
+
|
|
507
649
|
for (const taskPath of possiblePaths) {
|
|
508
650
|
if (await fileManager.pathExists(taskPath)) {
|
|
509
651
|
return taskPath;
|
|
510
652
|
}
|
|
511
653
|
}
|
|
512
|
-
|
|
654
|
+
|
|
513
655
|
return null;
|
|
514
656
|
}
|
|
515
657
|
|
|
516
658
|
async getCoreSlashPrefix(installDir) {
|
|
517
659
|
try {
|
|
518
|
-
const coreConfigPath = path.join(installDir,
|
|
660
|
+
const coreConfigPath = path.join(installDir, '.bmad-core', 'core-config.yaml');
|
|
519
661
|
if (!(await fileManager.pathExists(coreConfigPath))) {
|
|
520
662
|
// Try bmad-core directory
|
|
521
|
-
const altConfigPath = path.join(installDir,
|
|
663
|
+
const altConfigPath = path.join(installDir, 'bmad-core', 'core-config.yaml');
|
|
522
664
|
if (await fileManager.pathExists(altConfigPath)) {
|
|
523
665
|
const configContent = await fileManager.readFile(altConfigPath);
|
|
524
666
|
const config = yaml.load(configContent);
|
|
525
|
-
return config.slashPrefix ||
|
|
667
|
+
return config.slashPrefix || 'BMad';
|
|
526
668
|
}
|
|
527
|
-
return
|
|
669
|
+
return 'BMad'; // fallback
|
|
528
670
|
}
|
|
529
|
-
|
|
671
|
+
|
|
530
672
|
const configContent = await fileManager.readFile(coreConfigPath);
|
|
531
673
|
const config = yaml.load(configContent);
|
|
532
|
-
return config.slashPrefix ||
|
|
674
|
+
return config.slashPrefix || 'BMad';
|
|
533
675
|
} catch (error) {
|
|
534
676
|
console.warn(`Failed to read core slashPrefix, using default 'BMad': ${error.message}`);
|
|
535
|
-
return
|
|
677
|
+
return 'BMad';
|
|
536
678
|
}
|
|
537
679
|
}
|
|
538
680
|
|
|
539
681
|
async getInstalledExpansionPacks(installDir) {
|
|
540
682
|
const expansionPacks = [];
|
|
541
|
-
|
|
683
|
+
|
|
542
684
|
// Check for dot-prefixed expansion packs in install directory
|
|
543
|
-
const glob = require(
|
|
544
|
-
const dotExpansions = glob.sync(
|
|
545
|
-
|
|
685
|
+
const glob = require('glob');
|
|
686
|
+
const dotExpansions = glob.sync('.bmad-*', { cwd: installDir });
|
|
687
|
+
|
|
546
688
|
for (const dotExpansion of dotExpansions) {
|
|
547
|
-
if (dotExpansion !==
|
|
689
|
+
if (dotExpansion !== '.bmad-core') {
|
|
548
690
|
const packPath = path.join(installDir, dotExpansion);
|
|
549
|
-
const packName = dotExpansion.
|
|
691
|
+
const packName = dotExpansion.slice(1); // remove the dot
|
|
550
692
|
expansionPacks.push({
|
|
551
693
|
name: packName,
|
|
552
|
-
path: packPath
|
|
694
|
+
path: packPath,
|
|
553
695
|
});
|
|
554
696
|
}
|
|
555
697
|
}
|
|
556
|
-
|
|
698
|
+
|
|
557
699
|
// Check for expansion-packs directory style
|
|
558
|
-
const expansionPacksDir = path.join(installDir,
|
|
700
|
+
const expansionPacksDir = path.join(installDir, 'expansion-packs');
|
|
559
701
|
if (await fileManager.pathExists(expansionPacksDir)) {
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
for (const packDir of
|
|
702
|
+
const packDirectories = glob.sync('*', { cwd: expansionPacksDir });
|
|
703
|
+
|
|
704
|
+
for (const packDir of packDirectories) {
|
|
563
705
|
const packPath = path.join(expansionPacksDir, packDir);
|
|
564
|
-
if (
|
|
565
|
-
|
|
706
|
+
if (
|
|
707
|
+
(await fileManager.pathExists(packPath)) &&
|
|
708
|
+
(await fileManager.pathExists(path.join(packPath, 'config.yaml')))
|
|
709
|
+
) {
|
|
566
710
|
expansionPacks.push({
|
|
567
711
|
name: packDir,
|
|
568
|
-
path: packPath
|
|
712
|
+
path: packPath,
|
|
569
713
|
});
|
|
570
714
|
}
|
|
571
715
|
}
|
|
572
716
|
}
|
|
573
|
-
|
|
717
|
+
|
|
574
718
|
return expansionPacks;
|
|
575
719
|
}
|
|
576
720
|
|
|
577
721
|
async getExpansionPackSlashPrefix(packPath) {
|
|
578
722
|
try {
|
|
579
|
-
const configPath = path.join(packPath,
|
|
723
|
+
const configPath = path.join(packPath, 'config.yaml');
|
|
580
724
|
if (await fileManager.pathExists(configPath)) {
|
|
581
725
|
const configContent = await fileManager.readFile(configPath);
|
|
582
726
|
const config = yaml.load(configContent);
|
|
@@ -585,20 +729,20 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
585
729
|
} catch (error) {
|
|
586
730
|
console.warn(`Failed to read expansion pack slashPrefix from ${packPath}: ${error.message}`);
|
|
587
731
|
}
|
|
588
|
-
|
|
732
|
+
|
|
589
733
|
return path.basename(packPath); // fallback to directory name
|
|
590
734
|
}
|
|
591
735
|
|
|
592
736
|
async getExpansionPackAgents(packPath) {
|
|
593
|
-
const agentsDir = path.join(packPath,
|
|
737
|
+
const agentsDir = path.join(packPath, 'agents');
|
|
594
738
|
if (!(await fileManager.pathExists(agentsDir))) {
|
|
595
739
|
return [];
|
|
596
740
|
}
|
|
597
|
-
|
|
741
|
+
|
|
598
742
|
try {
|
|
599
|
-
const glob = require(
|
|
600
|
-
const agentFiles = glob.sync(
|
|
601
|
-
return agentFiles.map(file => path.basename(file,
|
|
743
|
+
const glob = require('glob');
|
|
744
|
+
const agentFiles = glob.sync('*.md', { cwd: agentsDir });
|
|
745
|
+
return agentFiles.map((file) => path.basename(file, '.md'));
|
|
602
746
|
} catch (error) {
|
|
603
747
|
console.warn(`Failed to read expansion pack agents from ${packPath}: ${error.message}`);
|
|
604
748
|
return [];
|
|
@@ -606,15 +750,15 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
606
750
|
}
|
|
607
751
|
|
|
608
752
|
async getExpansionPackTasks(packPath) {
|
|
609
|
-
const tasksDir = path.join(packPath,
|
|
753
|
+
const tasksDir = path.join(packPath, 'tasks');
|
|
610
754
|
if (!(await fileManager.pathExists(tasksDir))) {
|
|
611
755
|
return [];
|
|
612
756
|
}
|
|
613
|
-
|
|
757
|
+
|
|
614
758
|
try {
|
|
615
|
-
const glob = require(
|
|
616
|
-
const taskFiles = glob.sync(
|
|
617
|
-
return taskFiles.map(file => path.basename(file,
|
|
759
|
+
const glob = require('glob');
|
|
760
|
+
const taskFiles = glob.sync('*.md', { cwd: tasksDir });
|
|
761
|
+
return taskFiles.map((file) => path.basename(file, '.md'));
|
|
618
762
|
} catch (error) {
|
|
619
763
|
console.warn(`Failed to read expansion pack tasks from ${packPath}: ${error.message}`);
|
|
620
764
|
return [];
|
|
@@ -625,9 +769,9 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
625
769
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
626
770
|
|
|
627
771
|
// Check for existing .roomodes file in project root
|
|
628
|
-
const roomodesPath = path.join(installDir,
|
|
772
|
+
const roomodesPath = path.join(installDir, '.roomodes');
|
|
629
773
|
let existingModes = [];
|
|
630
|
-
let existingContent =
|
|
774
|
+
let existingContent = '';
|
|
631
775
|
|
|
632
776
|
if (await fileManager.pathExists(roomodesPath)) {
|
|
633
777
|
existingContent = await fileManager.readFile(roomodesPath);
|
|
@@ -640,7 +784,7 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
640
784
|
}
|
|
641
785
|
|
|
642
786
|
// Create new modes content
|
|
643
|
-
let newModesContent =
|
|
787
|
+
let newModesContent = '';
|
|
644
788
|
|
|
645
789
|
// Load dynamic agent permissions from configuration
|
|
646
790
|
const config = await this.loadIdeAgentConfig();
|
|
@@ -672,14 +816,15 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
672
816
|
const whenToUseMatch = yaml.match(/whenToUse:\s*"(.+)"/);
|
|
673
817
|
const roleDefinitionMatch = yaml.match(/roleDefinition:\s*"(.+)"/);
|
|
674
818
|
|
|
675
|
-
const title = titleMatch
|
|
676
|
-
|
|
819
|
+
const title = titleMatch
|
|
820
|
+
? titleMatch[1].trim()
|
|
821
|
+
: await this.getAgentTitle(agentId, installDir);
|
|
822
|
+
const icon = iconMatch ? iconMatch[1].trim() : '🤖';
|
|
677
823
|
const whenToUse = whenToUseMatch ? whenToUseMatch[1].trim() : `Use for ${title} tasks`;
|
|
678
824
|
const roleDefinition = roleDefinitionMatch
|
|
679
825
|
? roleDefinitionMatch[1].trim()
|
|
680
826
|
: `You are a ${title} specializing in ${title.toLowerCase()} tasks and responsibilities.`;
|
|
681
827
|
|
|
682
|
-
|
|
683
828
|
// Add permissions based on agent type
|
|
684
829
|
const permissions = agentPermissions[agentId];
|
|
685
830
|
// Build mode entry with proper formatting (matching exact indentation)
|
|
@@ -688,12 +833,12 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
688
833
|
newModesContent += ` - slug: ${slug}\n`;
|
|
689
834
|
newModesContent += ` name: '${icon} ${title}'\n`;
|
|
690
835
|
if (permissions) {
|
|
691
|
-
|
|
836
|
+
newModesContent += ` description: '${permissions.description}'\n`;
|
|
692
837
|
}
|
|
693
838
|
newModesContent += ` roleDefinition: ${roleDefinition}\n`;
|
|
694
839
|
newModesContent += ` whenToUse: ${whenToUse}\n`;
|
|
695
840
|
// Get relative path from installDir to agent file
|
|
696
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
841
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
697
842
|
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`;
|
|
698
843
|
newModesContent += ` groups:\n`;
|
|
699
844
|
newModesContent += ` - read\n`;
|
|
@@ -712,42 +857,45 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
712
857
|
}
|
|
713
858
|
|
|
714
859
|
// Build final roomodes content
|
|
715
|
-
let roomodesContent =
|
|
860
|
+
let roomodesContent = '';
|
|
716
861
|
if (existingContent) {
|
|
717
862
|
// If there's existing content, append new modes to it
|
|
718
|
-
roomodesContent = existingContent.trim() +
|
|
863
|
+
roomodesContent = existingContent.trim() + '\n' + newModesContent;
|
|
719
864
|
} else {
|
|
720
865
|
// Create new .roomodes file with proper YAML structure
|
|
721
|
-
roomodesContent =
|
|
866
|
+
roomodesContent = 'customModes:\n' + newModesContent;
|
|
722
867
|
}
|
|
723
868
|
|
|
724
869
|
// Write .roomodes file
|
|
725
870
|
await fileManager.writeFile(roomodesPath, roomodesContent);
|
|
726
|
-
console.log(chalk.green(
|
|
871
|
+
console.log(chalk.green('✓ Created .roomodes file in project root'));
|
|
727
872
|
|
|
728
873
|
console.log(chalk.green(`\n✓ Roo Code setup complete!`));
|
|
729
|
-
console.log(chalk.dim(
|
|
874
|
+
console.log(chalk.dim('Custom modes will be available when you open this project in Roo Code'));
|
|
730
875
|
|
|
731
876
|
return true;
|
|
732
877
|
}
|
|
733
|
-
|
|
878
|
+
|
|
734
879
|
async setupKilocode(installDir, selectedAgent) {
|
|
735
|
-
const filePath = path.join(installDir,
|
|
880
|
+
const filePath = path.join(installDir, '.kilocodemodes');
|
|
736
881
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
737
882
|
|
|
738
|
-
let existingModes = [],
|
|
883
|
+
let existingModes = [],
|
|
884
|
+
existingContent = '';
|
|
739
885
|
if (await fileManager.pathExists(filePath)) {
|
|
740
886
|
existingContent = await fileManager.readFile(filePath);
|
|
741
887
|
for (const match of existingContent.matchAll(/- slug: ([\w-]+)/g)) {
|
|
742
888
|
existingModes.push(match[1]);
|
|
743
889
|
}
|
|
744
|
-
console.log(
|
|
890
|
+
console.log(
|
|
891
|
+
chalk.yellow(`Found existing .kilocodemodes file with ${existingModes.length} modes`),
|
|
892
|
+
);
|
|
745
893
|
}
|
|
746
894
|
|
|
747
895
|
const config = await this.loadIdeAgentConfig();
|
|
748
896
|
const permissions = config['roo-permissions'] || {}; // reuse same roo permissions block (Kilo Code understands same mode schema)
|
|
749
897
|
|
|
750
|
-
let newContent =
|
|
898
|
+
let newContent = '';
|
|
751
899
|
|
|
752
900
|
for (const agentId of agents) {
|
|
753
901
|
const slug = agentId.startsWith('bmad-') ? agentId : `bmad-${agentId}`;
|
|
@@ -772,13 +920,15 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
772
920
|
const yaml = yamlMatch[1];
|
|
773
921
|
|
|
774
922
|
// Robust fallback for title and icon
|
|
775
|
-
const title =
|
|
776
|
-
|
|
777
|
-
const
|
|
778
|
-
const
|
|
923
|
+
const title =
|
|
924
|
+
yaml.match(/title:\s*(.+)/)?.[1]?.trim() || (await this.getAgentTitle(agentId, installDir));
|
|
925
|
+
const icon = yaml.match(/icon:\s*(.+)/)?.[1]?.trim() || '🤖';
|
|
926
|
+
const whenToUse = yaml.match(/whenToUse:\s*"(.+)"/)?.[1]?.trim() || `Use for ${title} tasks`;
|
|
927
|
+
const roleDefinition =
|
|
928
|
+
yaml.match(/roleDefinition:\s*"(.+)"/)?.[1]?.trim() ||
|
|
779
929
|
`You are a ${title} specializing in ${title.toLowerCase()} tasks and responsibilities.`;
|
|
780
930
|
|
|
781
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
931
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
782
932
|
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`;
|
|
783
933
|
|
|
784
934
|
// Add permissions from config if they exist
|
|
@@ -788,7 +938,7 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
788
938
|
newContent += ` - slug: ${slug}\n`;
|
|
789
939
|
newContent += ` name: '${icon} ${title}'\n`;
|
|
790
940
|
if (agentPermission) {
|
|
791
|
-
|
|
941
|
+
newContent += ` description: '${agentPermission.description}'\n`;
|
|
792
942
|
}
|
|
793
943
|
|
|
794
944
|
newContent += ` roleDefinition: ${roleDefinition}\n`;
|
|
@@ -797,7 +947,6 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
797
947
|
newContent += ` groups:\n`;
|
|
798
948
|
newContent += ` - read\n`;
|
|
799
949
|
|
|
800
|
-
|
|
801
950
|
if (agentPermission) {
|
|
802
951
|
newContent += ` - - edit\n`;
|
|
803
952
|
newContent += ` - fileRegex: ${agentPermission.fileRegex}\n`;
|
|
@@ -811,19 +960,19 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
811
960
|
}
|
|
812
961
|
|
|
813
962
|
const finalContent = existingContent
|
|
814
|
-
? existingContent.trim() +
|
|
815
|
-
:
|
|
963
|
+
? existingContent.trim() + '\n' + newContent
|
|
964
|
+
: 'customModes:\n' + newContent;
|
|
816
965
|
|
|
817
966
|
await fileManager.writeFile(filePath, finalContent);
|
|
818
|
-
console.log(chalk.green(
|
|
967
|
+
console.log(chalk.green('✓ Created .kilocodemodes file in project root'));
|
|
819
968
|
console.log(chalk.green(`✓ KiloCode setup complete!`));
|
|
820
|
-
console.log(chalk.dim(
|
|
969
|
+
console.log(chalk.dim('Custom modes will be available when you open this project in KiloCode'));
|
|
821
970
|
|
|
822
971
|
return true;
|
|
823
972
|
}
|
|
824
|
-
|
|
973
|
+
|
|
825
974
|
async setupCline(installDir, selectedAgent) {
|
|
826
|
-
const clineRulesDir = path.join(installDir,
|
|
975
|
+
const clineRulesDir = path.join(installDir, '.clinerules');
|
|
827
976
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
828
977
|
|
|
829
978
|
await fileManager.ensureDirectory(clineRulesDir);
|
|
@@ -847,26 +996,28 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
847
996
|
// Create MD content for Cline (focused on project standards and role)
|
|
848
997
|
let mdContent = `# ${await this.getAgentTitle(agentId, installDir)} Agent\n\n`;
|
|
849
998
|
mdContent += `This rule defines the ${await this.getAgentTitle(agentId, installDir)} persona and project standards.\n\n`;
|
|
850
|
-
mdContent +=
|
|
999
|
+
mdContent += '## Role Definition\n\n';
|
|
851
1000
|
mdContent +=
|
|
852
|
-
|
|
853
|
-
|
|
1001
|
+
'When the user types `@' +
|
|
1002
|
+
agentId +
|
|
1003
|
+
'`, adopt this persona and follow these guidelines:\n\n';
|
|
1004
|
+
mdContent += '```yaml\n';
|
|
854
1005
|
// Extract just the YAML content from the agent file
|
|
855
1006
|
const yamlContent = extractYamlFromAgent(agentContent);
|
|
856
1007
|
if (yamlContent) {
|
|
857
1008
|
mdContent += yamlContent;
|
|
858
1009
|
} else {
|
|
859
1010
|
// If no YAML found, include the whole content minus the header
|
|
860
|
-
mdContent += agentContent.replace(/^#.*$/m,
|
|
1011
|
+
mdContent += agentContent.replace(/^#.*$/m, '').trim();
|
|
861
1012
|
}
|
|
862
|
-
mdContent +=
|
|
863
|
-
mdContent +=
|
|
1013
|
+
mdContent += '\n```\n\n';
|
|
1014
|
+
mdContent += '## Project Standards\n\n';
|
|
864
1015
|
mdContent += `- Always maintain consistency with project documentation in .bmad-core/\n`;
|
|
865
1016
|
mdContent += `- Follow the agent's specific guidelines and constraints\n`;
|
|
866
1017
|
mdContent += `- Update relevant project files when making changes\n`;
|
|
867
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
1018
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
868
1019
|
mdContent += `- Reference the complete agent definition in [${relativePath}](${relativePath})\n\n`;
|
|
869
|
-
mdContent +=
|
|
1020
|
+
mdContent += '## Usage\n\n';
|
|
870
1021
|
mdContent += `Type \`@${agentId}\` to activate this ${await this.getAgentTitle(agentId, installDir)} persona.\n`;
|
|
871
1022
|
|
|
872
1023
|
await fileManager.writeFile(mdPath, mdContent);
|
|
@@ -880,54 +1031,50 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
880
1031
|
}
|
|
881
1032
|
|
|
882
1033
|
async setupGeminiCli(installDir) {
|
|
883
|
-
const geminiDir = path.join(installDir,
|
|
884
|
-
const bmadMethodDir = path.join(geminiDir,
|
|
1034
|
+
const geminiDir = path.join(installDir, '.gemini');
|
|
1035
|
+
const bmadMethodDir = path.join(geminiDir, 'bmad-method');
|
|
885
1036
|
await fileManager.ensureDirectory(bmadMethodDir);
|
|
886
1037
|
|
|
887
1038
|
// Update logic for existing settings.json
|
|
888
|
-
const settingsPath = path.join(geminiDir,
|
|
1039
|
+
const settingsPath = path.join(geminiDir, 'settings.json');
|
|
889
1040
|
if (await fileManager.pathExists(settingsPath)) {
|
|
890
1041
|
try {
|
|
891
1042
|
const settingsContent = await fileManager.readFile(settingsPath);
|
|
892
1043
|
const settings = JSON.parse(settingsContent);
|
|
893
1044
|
let updated = false;
|
|
894
|
-
|
|
1045
|
+
|
|
895
1046
|
// Handle contextFileName property
|
|
896
1047
|
if (settings.contextFileName && Array.isArray(settings.contextFileName)) {
|
|
897
1048
|
const originalLength = settings.contextFileName.length;
|
|
898
1049
|
settings.contextFileName = settings.contextFileName.filter(
|
|
899
|
-
(fileName) => !fileName.startsWith(
|
|
1050
|
+
(fileName) => !fileName.startsWith('agents/'),
|
|
900
1051
|
);
|
|
901
1052
|
if (settings.contextFileName.length !== originalLength) {
|
|
902
1053
|
updated = true;
|
|
903
1054
|
}
|
|
904
1055
|
}
|
|
905
|
-
|
|
1056
|
+
|
|
906
1057
|
if (updated) {
|
|
907
|
-
await fileManager.writeFile(
|
|
908
|
-
|
|
909
|
-
|
|
1058
|
+
await fileManager.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
1059
|
+
console.log(
|
|
1060
|
+
chalk.green('✓ Updated .gemini/settings.json - removed agent file references'),
|
|
910
1061
|
);
|
|
911
|
-
console.log(chalk.green("✓ Updated .gemini/settings.json - removed agent file references"));
|
|
912
1062
|
}
|
|
913
1063
|
} catch (error) {
|
|
914
|
-
console.warn(
|
|
915
|
-
chalk.yellow("Could not update .gemini/settings.json"),
|
|
916
|
-
error
|
|
917
|
-
);
|
|
1064
|
+
console.warn(chalk.yellow('Could not update .gemini/settings.json'), error);
|
|
918
1065
|
}
|
|
919
1066
|
}
|
|
920
1067
|
|
|
921
1068
|
// Remove old agents directory
|
|
922
|
-
const agentsDir = path.join(geminiDir,
|
|
1069
|
+
const agentsDir = path.join(geminiDir, 'agents');
|
|
923
1070
|
if (await fileManager.pathExists(agentsDir)) {
|
|
924
1071
|
await fileManager.removeDirectory(agentsDir);
|
|
925
|
-
console.log(chalk.green(
|
|
1072
|
+
console.log(chalk.green('✓ Removed old .gemini/agents directory'));
|
|
926
1073
|
}
|
|
927
1074
|
|
|
928
1075
|
// Get all available agents
|
|
929
1076
|
const agents = await this.getAllAgentIds(installDir);
|
|
930
|
-
let concatenatedContent =
|
|
1077
|
+
let concatenatedContent = '';
|
|
931
1078
|
|
|
932
1079
|
for (const agentId of agents) {
|
|
933
1080
|
// Find the source agent file
|
|
@@ -935,44 +1082,43 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
935
1082
|
|
|
936
1083
|
if (agentPath) {
|
|
937
1084
|
const agentContent = await fileManager.readFile(agentPath);
|
|
938
|
-
|
|
1085
|
+
|
|
939
1086
|
// Create properly formatted agent rule content (similar to trae)
|
|
940
1087
|
let agentRuleContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
941
1088
|
agentRuleContent += `This rule is triggered when the user types \`*${agentId}\` and activates the ${await this.getAgentTitle(
|
|
942
1089
|
agentId,
|
|
943
|
-
installDir
|
|
1090
|
+
installDir,
|
|
944
1091
|
)} agent persona.\n\n`;
|
|
945
|
-
agentRuleContent +=
|
|
1092
|
+
agentRuleContent += '## Agent Activation\n\n';
|
|
946
1093
|
agentRuleContent +=
|
|
947
|
-
|
|
948
|
-
agentRuleContent +=
|
|
1094
|
+
'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';
|
|
1095
|
+
agentRuleContent += '```yaml\n';
|
|
949
1096
|
// Extract just the YAML content from the agent file
|
|
950
1097
|
const yamlContent = extractYamlFromAgent(agentContent);
|
|
951
1098
|
if (yamlContent) {
|
|
952
1099
|
agentRuleContent += yamlContent;
|
|
953
|
-
}
|
|
954
|
-
else {
|
|
1100
|
+
} else {
|
|
955
1101
|
// If no YAML found, include the whole content minus the header
|
|
956
|
-
agentRuleContent += agentContent.replace(/^#.*$/m,
|
|
1102
|
+
agentRuleContent += agentContent.replace(/^#.*$/m, '').trim();
|
|
957
1103
|
}
|
|
958
|
-
agentRuleContent +=
|
|
959
|
-
agentRuleContent +=
|
|
960
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
1104
|
+
agentRuleContent += '\n```\n\n';
|
|
1105
|
+
agentRuleContent += '## File Reference\n\n';
|
|
1106
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
961
1107
|
agentRuleContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
|
|
962
|
-
agentRuleContent +=
|
|
1108
|
+
agentRuleContent += '## Usage\n\n';
|
|
963
1109
|
agentRuleContent += `When the user types \`*${agentId}\`, activate this ${await this.getAgentTitle(
|
|
964
1110
|
agentId,
|
|
965
|
-
installDir
|
|
1111
|
+
installDir,
|
|
966
1112
|
)} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
967
|
-
|
|
1113
|
+
|
|
968
1114
|
// Add to concatenated content with separator
|
|
969
|
-
concatenatedContent += agentRuleContent +
|
|
1115
|
+
concatenatedContent += agentRuleContent + '\n\n---\n\n';
|
|
970
1116
|
console.log(chalk.green(`✓ Added context for @${agentId}`));
|
|
971
1117
|
}
|
|
972
1118
|
}
|
|
973
1119
|
|
|
974
1120
|
// Write the concatenated content to GEMINI.md
|
|
975
|
-
const geminiMdPath = path.join(bmadMethodDir,
|
|
1121
|
+
const geminiMdPath = path.join(bmadMethodDir, 'GEMINI.md');
|
|
976
1122
|
await fileManager.writeFile(geminiMdPath, concatenatedContent);
|
|
977
1123
|
console.log(chalk.green(`\n✓ Created GEMINI.md in ${bmadMethodDir}`));
|
|
978
1124
|
|
|
@@ -980,54 +1126,48 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
980
1126
|
}
|
|
981
1127
|
|
|
982
1128
|
async setupQwenCode(installDir, selectedAgent) {
|
|
983
|
-
const qwenDir = path.join(installDir,
|
|
984
|
-
const bmadMethodDir = path.join(qwenDir,
|
|
1129
|
+
const qwenDir = path.join(installDir, '.qwen');
|
|
1130
|
+
const bmadMethodDir = path.join(qwenDir, 'bmad-method');
|
|
985
1131
|
await fileManager.ensureDirectory(bmadMethodDir);
|
|
986
1132
|
|
|
987
1133
|
// Update logic for existing settings.json
|
|
988
|
-
const settingsPath = path.join(qwenDir,
|
|
1134
|
+
const settingsPath = path.join(qwenDir, 'settings.json');
|
|
989
1135
|
if (await fileManager.pathExists(settingsPath)) {
|
|
990
1136
|
try {
|
|
991
1137
|
const settingsContent = await fileManager.readFile(settingsPath);
|
|
992
1138
|
const settings = JSON.parse(settingsContent);
|
|
993
1139
|
let updated = false;
|
|
994
|
-
|
|
1140
|
+
|
|
995
1141
|
// Handle contextFileName property
|
|
996
1142
|
if (settings.contextFileName && Array.isArray(settings.contextFileName)) {
|
|
997
1143
|
const originalLength = settings.contextFileName.length;
|
|
998
1144
|
settings.contextFileName = settings.contextFileName.filter(
|
|
999
|
-
(fileName) => !fileName.startsWith(
|
|
1145
|
+
(fileName) => !fileName.startsWith('agents/'),
|
|
1000
1146
|
);
|
|
1001
1147
|
if (settings.contextFileName.length !== originalLength) {
|
|
1002
1148
|
updated = true;
|
|
1003
1149
|
}
|
|
1004
1150
|
}
|
|
1005
|
-
|
|
1151
|
+
|
|
1006
1152
|
if (updated) {
|
|
1007
|
-
await fileManager.writeFile(
|
|
1008
|
-
|
|
1009
|
-
JSON.stringify(settings, null, 2)
|
|
1010
|
-
);
|
|
1011
|
-
console.log(chalk.green("✓ Updated .qwen/settings.json - removed agent file references"));
|
|
1153
|
+
await fileManager.writeFile(settingsPath, JSON.stringify(settings, null, 2));
|
|
1154
|
+
console.log(chalk.green('✓ Updated .qwen/settings.json - removed agent file references'));
|
|
1012
1155
|
}
|
|
1013
1156
|
} catch (error) {
|
|
1014
|
-
console.warn(
|
|
1015
|
-
chalk.yellow("Could not update .qwen/settings.json"),
|
|
1016
|
-
error
|
|
1017
|
-
);
|
|
1157
|
+
console.warn(chalk.yellow('Could not update .qwen/settings.json'), error);
|
|
1018
1158
|
}
|
|
1019
1159
|
}
|
|
1020
1160
|
|
|
1021
1161
|
// Remove old agents directory
|
|
1022
|
-
const agentsDir = path.join(qwenDir,
|
|
1162
|
+
const agentsDir = path.join(qwenDir, 'agents');
|
|
1023
1163
|
if (await fileManager.pathExists(agentsDir)) {
|
|
1024
1164
|
await fileManager.removeDirectory(agentsDir);
|
|
1025
|
-
console.log(chalk.green(
|
|
1165
|
+
console.log(chalk.green('✓ Removed old .qwen/agents directory'));
|
|
1026
1166
|
}
|
|
1027
1167
|
|
|
1028
1168
|
// Get all available agents
|
|
1029
1169
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
1030
|
-
let concatenatedContent =
|
|
1170
|
+
let concatenatedContent = '';
|
|
1031
1171
|
|
|
1032
1172
|
for (const agentId of agents) {
|
|
1033
1173
|
// Find the source agent file
|
|
@@ -1035,57 +1175,61 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
1035
1175
|
|
|
1036
1176
|
if (agentPath) {
|
|
1037
1177
|
const agentContent = await fileManager.readFile(agentPath);
|
|
1038
|
-
|
|
1178
|
+
|
|
1039
1179
|
// Create properly formatted agent rule content (similar to gemini)
|
|
1040
1180
|
let agentRuleContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
1041
1181
|
agentRuleContent += `This rule is triggered when the user types \`*${agentId}\` and activates the ${await this.getAgentTitle(
|
|
1042
1182
|
agentId,
|
|
1043
|
-
installDir
|
|
1183
|
+
installDir,
|
|
1044
1184
|
)} agent persona.\n\n`;
|
|
1045
|
-
agentRuleContent +=
|
|
1185
|
+
agentRuleContent += '## Agent Activation\n\n';
|
|
1046
1186
|
agentRuleContent +=
|
|
1047
|
-
|
|
1048
|
-
agentRuleContent +=
|
|
1187
|
+
'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';
|
|
1188
|
+
agentRuleContent += '```yaml\n';
|
|
1049
1189
|
// Extract just the YAML content from the agent file
|
|
1050
1190
|
const yamlContent = extractYamlFromAgent(agentContent);
|
|
1051
1191
|
if (yamlContent) {
|
|
1052
1192
|
agentRuleContent += yamlContent;
|
|
1053
|
-
}
|
|
1054
|
-
else {
|
|
1193
|
+
} else {
|
|
1055
1194
|
// If no YAML found, include the whole content minus the header
|
|
1056
|
-
agentRuleContent += agentContent.replace(/^#.*$/m,
|
|
1195
|
+
agentRuleContent += agentContent.replace(/^#.*$/m, '').trim();
|
|
1057
1196
|
}
|
|
1058
|
-
agentRuleContent +=
|
|
1059
|
-
agentRuleContent +=
|
|
1060
|
-
const relativePath = path.relative(installDir, agentPath).
|
|
1197
|
+
agentRuleContent += '\n```\n\n';
|
|
1198
|
+
agentRuleContent += '## File Reference\n\n';
|
|
1199
|
+
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
|
1061
1200
|
agentRuleContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
|
|
1062
|
-
agentRuleContent +=
|
|
1201
|
+
agentRuleContent += '## Usage\n\n';
|
|
1063
1202
|
agentRuleContent += `When the user types \`*${agentId}\`, activate this ${await this.getAgentTitle(
|
|
1064
1203
|
agentId,
|
|
1065
|
-
installDir
|
|
1204
|
+
installDir,
|
|
1066
1205
|
)} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
1067
|
-
|
|
1206
|
+
|
|
1068
1207
|
// Add to concatenated content with separator
|
|
1069
|
-
concatenatedContent += agentRuleContent +
|
|
1208
|
+
concatenatedContent += agentRuleContent + '\n\n---\n\n';
|
|
1070
1209
|
console.log(chalk.green(`✓ Added context for *${agentId}`));
|
|
1071
1210
|
}
|
|
1072
1211
|
}
|
|
1073
1212
|
|
|
1074
1213
|
// Write the concatenated content to QWEN.md
|
|
1075
|
-
const qwenMdPath = path.join(bmadMethodDir,
|
|
1214
|
+
const qwenMdPath = path.join(bmadMethodDir, 'QWEN.md');
|
|
1076
1215
|
await fileManager.writeFile(qwenMdPath, concatenatedContent);
|
|
1077
1216
|
console.log(chalk.green(`\n✓ Created QWEN.md in ${bmadMethodDir}`));
|
|
1078
1217
|
|
|
1079
1218
|
return true;
|
|
1080
1219
|
}
|
|
1081
1220
|
|
|
1082
|
-
async setupGitHubCopilot(
|
|
1221
|
+
async setupGitHubCopilot(
|
|
1222
|
+
installDir,
|
|
1223
|
+
selectedAgent,
|
|
1224
|
+
spinner = null,
|
|
1225
|
+
preConfiguredSettings = null,
|
|
1226
|
+
) {
|
|
1083
1227
|
// Configure VS Code workspace settings first to avoid UI conflicts with loading spinners
|
|
1084
1228
|
await this.configureVsCodeSettings(installDir, spinner, preConfiguredSettings);
|
|
1085
|
-
|
|
1086
|
-
const chatmodesDir = path.join(installDir,
|
|
1229
|
+
|
|
1230
|
+
const chatmodesDir = path.join(installDir, '.github', 'chatmodes');
|
|
1087
1231
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
1088
|
-
|
|
1232
|
+
|
|
1089
1233
|
await fileManager.ensureDirectory(chatmodesDir);
|
|
1090
1234
|
|
|
1091
1235
|
for (const agentId of agents) {
|
|
@@ -1097,7 +1241,7 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
1097
1241
|
// Create chat mode file with agent content
|
|
1098
1242
|
const agentContent = await fileManager.readFile(agentPath);
|
|
1099
1243
|
const agentTitle = await this.getAgentTitle(agentId, installDir);
|
|
1100
|
-
|
|
1244
|
+
|
|
1101
1245
|
// Extract whenToUse for the description
|
|
1102
1246
|
const yamlMatch = agentContent.match(/```ya?ml\r?\n([\s\S]*?)```/);
|
|
1103
1247
|
let description = `Activates the ${agentTitle} agent persona.`;
|
|
@@ -1107,9 +1251,9 @@ class IdeSetup extends BaseIdeSetup {
|
|
|
1107
1251
|
description = whenToUseMatch[1];
|
|
1108
1252
|
}
|
|
1109
1253
|
}
|
|
1110
|
-
|
|
1254
|
+
|
|
1111
1255
|
let chatmodeContent = `---
|
|
1112
|
-
description: "${description.
|
|
1256
|
+
description: "${description.replaceAll('"', String.raw`\"`)}"
|
|
1113
1257
|
tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems', 'usages', 'editFiles', 'runCommands', 'runTasks', 'runTests', 'search', 'searchResults', 'terminalLastCommand', 'terminalSelection', 'testFailure']
|
|
1114
1258
|
---
|
|
1115
1259
|
|
|
@@ -1128,24 +1272,24 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
|
|
|
1128
1272
|
}
|
|
1129
1273
|
|
|
1130
1274
|
async configureVsCodeSettings(installDir, spinner, preConfiguredSettings = null) {
|
|
1131
|
-
const vscodeDir = path.join(installDir,
|
|
1132
|
-
const settingsPath = path.join(vscodeDir,
|
|
1133
|
-
|
|
1275
|
+
const vscodeDir = path.join(installDir, '.vscode');
|
|
1276
|
+
const settingsPath = path.join(vscodeDir, 'settings.json');
|
|
1277
|
+
|
|
1134
1278
|
await fileManager.ensureDirectory(vscodeDir);
|
|
1135
|
-
|
|
1279
|
+
|
|
1136
1280
|
// Read existing settings if they exist
|
|
1137
1281
|
let existingSettings = {};
|
|
1138
1282
|
if (await fileManager.pathExists(settingsPath)) {
|
|
1139
1283
|
try {
|
|
1140
1284
|
const existingContent = await fileManager.readFile(settingsPath);
|
|
1141
1285
|
existingSettings = JSON.parse(existingContent);
|
|
1142
|
-
console.log(chalk.yellow(
|
|
1143
|
-
} catch
|
|
1144
|
-
console.warn(chalk.yellow(
|
|
1286
|
+
console.log(chalk.yellow('Found existing .vscode/settings.json. Merging BMad settings...'));
|
|
1287
|
+
} catch {
|
|
1288
|
+
console.warn(chalk.yellow('Could not parse existing settings.json. Creating new one.'));
|
|
1145
1289
|
existingSettings = {};
|
|
1146
1290
|
}
|
|
1147
1291
|
}
|
|
1148
|
-
|
|
1292
|
+
|
|
1149
1293
|
// Use pre-configured settings if provided, otherwise prompt
|
|
1150
1294
|
let configChoice;
|
|
1151
1295
|
if (preConfiguredSettings && preConfiguredSettings.configChoice) {
|
|
@@ -1154,10 +1298,12 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
|
|
|
1154
1298
|
} else {
|
|
1155
1299
|
// Clear any previous output and add spacing to avoid conflicts with loaders
|
|
1156
1300
|
console.log('\n'.repeat(2));
|
|
1157
|
-
console.log(chalk.blue(
|
|
1158
|
-
console.log(
|
|
1301
|
+
console.log(chalk.blue('🔧 Github Copilot Agent Settings Configuration'));
|
|
1302
|
+
console.log(
|
|
1303
|
+
chalk.dim('BMad works best with specific VS Code settings for optimal agent experience.'),
|
|
1304
|
+
);
|
|
1159
1305
|
console.log(''); // Add extra spacing
|
|
1160
|
-
|
|
1306
|
+
|
|
1161
1307
|
const response = await inquirer.prompt([
|
|
1162
1308
|
{
|
|
1163
1309
|
type: 'list',
|
|
@@ -1166,59 +1312,59 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
|
|
|
1166
1312
|
choices: [
|
|
1167
1313
|
{
|
|
1168
1314
|
name: 'Use recommended defaults (fastest setup)',
|
|
1169
|
-
value: 'defaults'
|
|
1315
|
+
value: 'defaults',
|
|
1170
1316
|
},
|
|
1171
1317
|
{
|
|
1172
1318
|
name: 'Configure each setting manually (customize to your preferences)',
|
|
1173
|
-
value: 'manual'
|
|
1319
|
+
value: 'manual',
|
|
1174
1320
|
},
|
|
1175
1321
|
{
|
|
1176
|
-
name:
|
|
1177
|
-
value: 'skip'
|
|
1178
|
-
}
|
|
1322
|
+
name: "Skip settings configuration (I'll configure manually later)",
|
|
1323
|
+
value: 'skip',
|
|
1324
|
+
},
|
|
1179
1325
|
],
|
|
1180
|
-
default: 'defaults'
|
|
1181
|
-
}
|
|
1326
|
+
default: 'defaults',
|
|
1327
|
+
},
|
|
1182
1328
|
]);
|
|
1183
1329
|
configChoice = response.configChoice;
|
|
1184
1330
|
}
|
|
1185
|
-
|
|
1331
|
+
|
|
1186
1332
|
let bmadSettings = {};
|
|
1187
|
-
|
|
1333
|
+
|
|
1188
1334
|
if (configChoice === 'skip') {
|
|
1189
|
-
console.log(chalk.yellow(
|
|
1190
|
-
console.log(chalk.dim(
|
|
1191
|
-
console.log(chalk.dim(
|
|
1192
|
-
console.log(chalk.dim(
|
|
1193
|
-
console.log(chalk.dim(
|
|
1194
|
-
console.log(chalk.dim(
|
|
1195
|
-
console.log(chalk.dim(
|
|
1196
|
-
console.log(chalk.dim(
|
|
1335
|
+
console.log(chalk.yellow('⚠️ Skipping VS Code settings configuration.'));
|
|
1336
|
+
console.log(chalk.dim('You can manually configure these settings in .vscode/settings.json:'));
|
|
1337
|
+
console.log(chalk.dim(' • chat.agent.enabled: true'));
|
|
1338
|
+
console.log(chalk.dim(' • chat.agent.maxRequests: 15'));
|
|
1339
|
+
console.log(chalk.dim(' • github.copilot.chat.agent.runTasks: true'));
|
|
1340
|
+
console.log(chalk.dim(' • chat.mcp.discovery.enabled: true'));
|
|
1341
|
+
console.log(chalk.dim(' • github.copilot.chat.agent.autoFix: true'));
|
|
1342
|
+
console.log(chalk.dim(' • chat.tools.autoApprove: false'));
|
|
1197
1343
|
return true;
|
|
1198
1344
|
}
|
|
1199
|
-
|
|
1345
|
+
|
|
1200
1346
|
if (configChoice === 'defaults') {
|
|
1201
1347
|
// Use recommended defaults
|
|
1202
1348
|
bmadSettings = {
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1349
|
+
'chat.agent.enabled': true,
|
|
1350
|
+
'chat.agent.maxRequests': 15,
|
|
1351
|
+
'github.copilot.chat.agent.runTasks': true,
|
|
1352
|
+
'chat.mcp.discovery.enabled': true,
|
|
1353
|
+
'github.copilot.chat.agent.autoFix': true,
|
|
1354
|
+
'chat.tools.autoApprove': false,
|
|
1209
1355
|
};
|
|
1210
|
-
console.log(chalk.green(
|
|
1356
|
+
console.log(chalk.green('✓ Using recommended BMad defaults for Github Copilot settings'));
|
|
1211
1357
|
} else {
|
|
1212
1358
|
// Manual configuration
|
|
1213
1359
|
console.log(chalk.blue("\n📋 Let's configure each setting for your preferences:"));
|
|
1214
|
-
|
|
1360
|
+
|
|
1215
1361
|
// Pause spinner during manual configuration prompts
|
|
1216
1362
|
let spinnerWasActive = false;
|
|
1217
1363
|
if (spinner && spinner.isSpinning) {
|
|
1218
1364
|
spinner.stop();
|
|
1219
1365
|
spinnerWasActive = true;
|
|
1220
1366
|
}
|
|
1221
|
-
|
|
1367
|
+
|
|
1222
1368
|
const manualSettings = await inquirer.prompt([
|
|
1223
1369
|
{
|
|
1224
1370
|
type: 'input',
|
|
@@ -1226,69 +1372,69 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
|
|
|
1226
1372
|
message: 'Maximum requests per agent session (recommended: 15)?',
|
|
1227
1373
|
default: '15',
|
|
1228
1374
|
validate: (input) => {
|
|
1229
|
-
const
|
|
1230
|
-
if (isNaN(
|
|
1375
|
+
const number_ = Number.parseInt(input);
|
|
1376
|
+
if (isNaN(number_) || number_ < 1 || number_ > 50) {
|
|
1231
1377
|
return 'Please enter a number between 1 and 50';
|
|
1232
1378
|
}
|
|
1233
1379
|
return true;
|
|
1234
|
-
}
|
|
1380
|
+
},
|
|
1235
1381
|
},
|
|
1236
1382
|
{
|
|
1237
1383
|
type: 'confirm',
|
|
1238
1384
|
name: 'runTasks',
|
|
1239
1385
|
message: 'Allow agents to run workspace tasks (package.json scripts, etc.)?',
|
|
1240
|
-
default: true
|
|
1386
|
+
default: true,
|
|
1241
1387
|
},
|
|
1242
1388
|
{
|
|
1243
1389
|
type: 'confirm',
|
|
1244
1390
|
name: 'mcpDiscovery',
|
|
1245
1391
|
message: 'Enable MCP (Model Context Protocol) server discovery?',
|
|
1246
|
-
default: true
|
|
1392
|
+
default: true,
|
|
1247
1393
|
},
|
|
1248
1394
|
{
|
|
1249
1395
|
type: 'confirm',
|
|
1250
1396
|
name: 'autoFix',
|
|
1251
1397
|
message: 'Enable automatic error detection and fixing in generated code?',
|
|
1252
|
-
default: true
|
|
1398
|
+
default: true,
|
|
1253
1399
|
},
|
|
1254
1400
|
{
|
|
1255
1401
|
type: 'confirm',
|
|
1256
1402
|
name: 'autoApprove',
|
|
1257
1403
|
message: 'Auto-approve ALL tools without confirmation? (⚠️ EXPERIMENTAL - less secure)',
|
|
1258
|
-
default: false
|
|
1259
|
-
}
|
|
1404
|
+
default: false,
|
|
1405
|
+
},
|
|
1260
1406
|
]);
|
|
1261
1407
|
|
|
1262
1408
|
// Restart spinner if it was active before prompts
|
|
1263
1409
|
if (spinner && spinnerWasActive) {
|
|
1264
1410
|
spinner.start();
|
|
1265
1411
|
}
|
|
1266
|
-
|
|
1412
|
+
|
|
1267
1413
|
bmadSettings = {
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1414
|
+
'chat.agent.enabled': true, // Always enabled - required for BMad agents
|
|
1415
|
+
'chat.agent.maxRequests': Number.parseInt(manualSettings.maxRequests),
|
|
1416
|
+
'github.copilot.chat.agent.runTasks': manualSettings.runTasks,
|
|
1417
|
+
'chat.mcp.discovery.enabled': manualSettings.mcpDiscovery,
|
|
1418
|
+
'github.copilot.chat.agent.autoFix': manualSettings.autoFix,
|
|
1419
|
+
'chat.tools.autoApprove': manualSettings.autoApprove,
|
|
1274
1420
|
};
|
|
1275
|
-
|
|
1276
|
-
console.log(chalk.green(
|
|
1421
|
+
|
|
1422
|
+
console.log(chalk.green('✓ Custom settings configured'));
|
|
1277
1423
|
}
|
|
1278
|
-
|
|
1424
|
+
|
|
1279
1425
|
// Merge settings (existing settings take precedence to avoid overriding user preferences)
|
|
1280
1426
|
const mergedSettings = { ...bmadSettings, ...existingSettings };
|
|
1281
|
-
|
|
1427
|
+
|
|
1282
1428
|
// Write the updated settings
|
|
1283
1429
|
await fileManager.writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2));
|
|
1284
|
-
|
|
1285
|
-
console.log(chalk.green(
|
|
1286
|
-
console.log(chalk.dim(
|
|
1287
|
-
|
|
1430
|
+
|
|
1431
|
+
console.log(chalk.green('✓ VS Code workspace settings configured successfully'));
|
|
1432
|
+
console.log(chalk.dim(' Settings written to .vscode/settings.json:'));
|
|
1433
|
+
for (const [key, value] of Object.entries(bmadSettings)) {
|
|
1288
1434
|
console.log(chalk.dim(` • ${key}: ${value}`));
|
|
1289
|
-
}
|
|
1290
|
-
console.log(chalk.dim(
|
|
1291
|
-
console.log(chalk.dim(
|
|
1435
|
+
}
|
|
1436
|
+
console.log(chalk.dim(''));
|
|
1437
|
+
console.log(chalk.dim('You can modify these settings anytime in .vscode/settings.json'));
|
|
1292
1438
|
}
|
|
1293
1439
|
}
|
|
1294
1440
|
|