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