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.
Files changed (131) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +3 -3
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +3 -3
  3. package/.github/workflows/discord.yaml +11 -2
  4. package/.github/workflows/format-check.yaml +42 -0
  5. package/.github/workflows/manual-release.yaml +173 -0
  6. package/.husky/pre-commit +3 -0
  7. package/.vscode/settings.json +26 -1
  8. package/CHANGELOG.md +0 -11
  9. package/README.md +2 -0
  10. package/bmad-core/agent-teams/team-all.yaml +1 -1
  11. package/bmad-core/agents/bmad-orchestrator.md +1 -1
  12. package/bmad-core/agents/dev.md +4 -4
  13. package/bmad-core/data/bmad-kb.md +1 -1
  14. package/bmad-core/data/test-levels-framework.md +12 -12
  15. package/bmad-core/tasks/facilitate-brainstorming-session.md +1 -1
  16. package/bmad-core/tasks/nfr-assess.md +10 -10
  17. package/bmad-core/tasks/qa-gate.md +23 -23
  18. package/bmad-core/tasks/review-story.md +18 -18
  19. package/bmad-core/tasks/risk-profile.md +25 -25
  20. package/bmad-core/tasks/test-design.md +9 -9
  21. package/bmad-core/tasks/trace-requirements.md +21 -21
  22. package/bmad-core/templates/architecture-tmpl.yaml +49 -49
  23. package/bmad-core/templates/brainstorming-output-tmpl.yaml +5 -5
  24. package/bmad-core/templates/brownfield-architecture-tmpl.yaml +31 -31
  25. package/bmad-core/templates/brownfield-prd-tmpl.yaml +13 -13
  26. package/bmad-core/templates/competitor-analysis-tmpl.yaml +19 -6
  27. package/bmad-core/templates/front-end-architecture-tmpl.yaml +21 -9
  28. package/bmad-core/templates/front-end-spec-tmpl.yaml +24 -24
  29. package/bmad-core/templates/fullstack-architecture-tmpl.yaml +122 -104
  30. package/bmad-core/templates/market-research-tmpl.yaml +2 -2
  31. package/bmad-core/templates/prd-tmpl.yaml +9 -9
  32. package/bmad-core/templates/project-brief-tmpl.yaml +4 -4
  33. package/bmad-core/templates/qa-gate-tmpl.yaml +9 -9
  34. package/bmad-core/templates/story-tmpl.yaml +12 -12
  35. package/bmad-core/workflows/brownfield-fullstack.yaml +9 -9
  36. package/bmad-core/workflows/brownfield-service.yaml +1 -1
  37. package/bmad-core/workflows/brownfield-ui.yaml +1 -1
  38. package/bmad-core/workflows/greenfield-fullstack.yaml +1 -1
  39. package/bmad-core/workflows/greenfield-service.yaml +1 -1
  40. package/bmad-core/workflows/greenfield-ui.yaml +1 -1
  41. package/common/utils/bmad-doc-template.md +5 -5
  42. package/dist/agents/analyst.txt +28 -15
  43. package/dist/agents/architect.txt +220 -190
  44. package/dist/agents/bmad-master.txt +298 -255
  45. package/dist/agents/bmad-orchestrator.txt +1 -1
  46. package/dist/agents/pm.txt +20 -20
  47. package/dist/agents/po.txt +11 -11
  48. package/dist/agents/qa.txt +275 -618
  49. package/dist/agents/sm.txt +11 -11
  50. package/dist/agents/ux-expert.txt +23 -23
  51. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +109 -109
  52. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.txt +75 -77
  53. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.txt +41 -41
  54. package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +483 -474
  55. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.txt +1 -1
  56. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.txt +149 -149
  57. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.txt +20 -20
  58. package/dist/expansion-packs/bmad-2d-unity-game-dev/teams/unity-2d-game-team.txt +371 -358
  59. package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +25 -25
  60. package/dist/teams/team-all.txt +581 -881
  61. package/dist/teams/team-fullstack.txt +316 -273
  62. package/dist/teams/team-ide-minimal.txt +276 -619
  63. package/dist/teams/team-no-ui.txt +281 -238
  64. package/docs/versioning-and-releases.md +114 -44
  65. package/eslint.config.mjs +119 -0
  66. 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
  67. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.md +4 -4
  68. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.md +1 -1
  69. package/expansion-packs/bmad-2d-phaser-game-dev/data/development-guidelines.md +26 -28
  70. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-architecture-tmpl.yaml +50 -50
  71. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-brief-tmpl.yaml +23 -23
  72. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-design-doc-tmpl.yaml +24 -24
  73. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-story-tmpl.yaml +42 -42
  74. package/expansion-packs/bmad-2d-phaser-game-dev/templates/level-design-doc-tmpl.yaml +65 -65
  75. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-dev-greenfield.yaml +5 -5
  76. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-prototype.yaml +1 -1
  77. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.md +3 -3
  78. package/expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md +1 -1
  79. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-brief-tmpl.yaml +23 -23
  80. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml +63 -63
  81. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-story-tmpl.yaml +20 -20
  82. package/expansion-packs/bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml +65 -65
  83. package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-dev-greenfield.yaml +5 -5
  84. package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-prototype.yaml +1 -1
  85. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-architecture-tmpl.yaml +20 -20
  86. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.yaml +7 -7
  87. package/package.json +62 -39
  88. package/prettier.config.mjs +32 -0
  89. package/release_notes.md +30 -0
  90. package/tools/bmad-npx-wrapper.js +10 -10
  91. package/tools/builders/web-builder.js +124 -130
  92. package/tools/bump-all-versions.js +42 -33
  93. package/tools/bump-expansion-version.js +23 -16
  94. package/tools/cli.js +10 -12
  95. package/tools/flattener/aggregate.js +10 -10
  96. package/tools/flattener/binary.js +44 -17
  97. package/tools/flattener/discovery.js +19 -18
  98. package/tools/flattener/files.js +6 -6
  99. package/tools/flattener/ignoreRules.js +125 -125
  100. package/tools/flattener/main.js +201 -304
  101. package/tools/flattener/projectRoot.js +75 -73
  102. package/tools/flattener/prompts.js +9 -9
  103. package/tools/flattener/stats.helpers.js +131 -67
  104. package/tools/flattener/stats.js +3 -3
  105. package/tools/flattener/test-matrix.js +201 -193
  106. package/tools/flattener/xml.js +33 -31
  107. package/tools/installer/bin/bmad.js +130 -89
  108. package/tools/installer/config/ide-agent-config.yaml +1 -1
  109. package/tools/installer/config/install.config.yaml +2 -2
  110. package/tools/installer/lib/config-loader.js +46 -42
  111. package/tools/installer/lib/file-manager.js +91 -113
  112. package/tools/installer/lib/ide-base-setup.js +57 -56
  113. package/tools/installer/lib/ide-setup.js +375 -343
  114. package/tools/installer/lib/installer.js +875 -714
  115. package/tools/installer/lib/memory-profiler.js +54 -53
  116. package/tools/installer/lib/module-manager.js +19 -15
  117. package/tools/installer/lib/resource-locator.js +26 -28
  118. package/tools/installer/package.json +19 -19
  119. package/tools/lib/dependency-resolver.js +26 -30
  120. package/tools/lib/yaml-utils.js +7 -7
  121. package/tools/preview-release-notes.js +66 -0
  122. package/tools/shared/bannerArt.js +3 -3
  123. package/tools/sync-installer-version.js +7 -9
  124. package/tools/update-expansion-version.js +14 -15
  125. package/tools/upgraders/v3-to-v4-upgrader.js +203 -294
  126. package/tools/version-bump.js +41 -26
  127. package/tools/yaml-format.js +56 -43
  128. package/.github/workflows/promote-to-stable.yml +0 -144
  129. package/.github/workflows/release.yaml +0 -60
  130. package/.releaserc.json +0 -21
  131. package/tools/semantic-release-sync-installer.js +0 -30
@@ -1,13 +1,13 @@
1
- const path = require("path");
2
- const fs = require("fs-extra");
3
- const yaml = require("js-yaml");
4
- const chalk = require("chalk").default || require("chalk");
5
- const inquirer = require("inquirer").default || 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");
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 (error) {
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 "cursor":
44
+ case 'cursor': {
45
45
  return this.setupCursor(installDir, selectedAgent);
46
- case "claude-code":
46
+ }
47
+ case 'claude-code': {
47
48
  return this.setupClaudeCode(installDir, selectedAgent);
48
- case "crush":
49
+ }
50
+ case 'crush': {
49
51
  return this.setupCrush(installDir, selectedAgent);
50
- case "windsurf":
52
+ }
53
+ case 'windsurf': {
51
54
  return this.setupWindsurf(installDir, selectedAgent);
52
- case "trae":
55
+ }
56
+ case 'trae': {
53
57
  return this.setupTrae(installDir, selectedAgent);
54
- case "roo":
58
+ }
59
+ case 'roo': {
55
60
  return this.setupRoo(installDir, selectedAgent);
56
- case "cline":
61
+ }
62
+ case 'cline': {
57
63
  return this.setupCline(installDir, selectedAgent);
58
- case "kilo":
64
+ }
65
+ case 'kilo': {
59
66
  return this.setupKilocode(installDir, selectedAgent);
60
- case "gemini":
67
+ }
68
+ case 'gemini': {
61
69
  return this.setupGeminiCli(installDir, selectedAgent);
62
- case "github-copilot":
70
+ }
71
+ case 'github-copilot': {
63
72
  return this.setupGitHubCopilot(installDir, selectedAgent, spinner, preConfiguredSettings);
64
- case "qwen-code":
73
+ }
74
+ case 'qwen-code': {
65
75
  return this.setupQwenCode(installDir, selectedAgent);
66
- default:
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, ".cursor", "rules", "bmad");
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(installDir, "core", coreSlashPrefix, coreAgents, coreTasks, ".bmad-core");
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(installDir, packInfo.name, packSlashPrefix, packAgents, packTasks, rootPath);
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(installDir, "core", coreSlashPrefix, coreAgents, coreTasks, ".bmad-core");
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(installDir, packInfo.name, packSlashPrefix, packAgents, packTasks, rootPath);
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(installDir, packageName, slashPrefix, agentIds, taskIds, rootPath) {
142
- const commandsBaseDir = path.join(installDir, ".claude", "commands", slashPrefix);
143
- const agentsDir = path.join(commandsBaseDir, "agents");
144
- const tasksDir = path.join(commandsBaseDir, "tasks");
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 !== "core") {
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, "agents", `${agentId}.md`);
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.replace(/{root}/g, rootPath);
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 !== "core") {
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, "tasks", `${taskId}.md`);
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.replace(/{root}/g, rootPath);
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(chalk.green(`\n✓ Created Claude Code commands for ${packageName} in ${commandsBaseDir}`));
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, ".crush", "commands", slashPrefix);
231
- const agentsDir = path.join(commandsBaseDir, "agents");
232
- const tasksDir = path.join(commandsBaseDir, "tasks");
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 !== "core") {
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, "agents", `${agentId}.md`);
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.replace(/{root}/g, rootPath);
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 !== "core") {
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, "tasks", `${taskId}.md`);
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.replace(/{root}/g, rootPath);
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 windsurfRulesDir = path.join(installDir, ".windsurf", "rules");
367
+ const windsurfWorkflowDir = path.join(installDir, '.windsurf', 'workflows');
319
368
  const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
320
369
 
321
- await fileManager.ensureDirectory(windsurfRulesDir);
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(windsurfRulesDir, `${agentId}.md`);
378
+ const mdPath = path.join(windsurfWorkflowDir, `${agentId}.md`);
330
379
 
331
- // Create MD content (similar to Cursor but without frontmatter)
332
- let mdContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
333
- mdContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${await this.getAgentTitle(
334
- agentId,
335
- installDir
336
- )} agent persona.\n\n`;
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 rule: ${agentId}.md`));
388
+ console.log(chalk.green(`✓ Created workflow: ${agentId}.md`));
361
389
  }
362
390
  }
363
391
 
364
- console.log(chalk.green(`\n✓ Created Windsurf rules in ${windsurfRulesDir}`));
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, ".trae", "rules");
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 += "## Agent Activation\n\n";
417
+ mdContent += '## Agent Activation\n\n';
390
418
  mdContent +=
391
- "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";
392
- mdContent += "```yaml\n";
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, "").trim();
427
+ mdContent += agentContent.replace(/^#.*$/m, '').trim();
401
428
  }
402
- mdContent += "\n```\n\n";
403
- mdContent += "## File Reference\n\n";
404
- const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
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 += "## Usage\n\n";
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, ".bmad-core", "agents", `${agentId}.md`),
422
- path.join(installDir, "agents", `${agentId}.md`)
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("glob");
427
- const expansionDirs = glob.sync(".*/agents", { cwd: installDir });
428
- for (const expDir of expansionDirs) {
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("glob");
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, ".bmad-core", "agents");
473
+ let agentsDir = path.join(installDir, '.bmad-core', 'agents');
447
474
  if (!(await fileManager.pathExists(agentsDir))) {
448
- agentsDir = path.join(installDir, "agents");
475
+ agentsDir = path.join(installDir, 'agents');
449
476
  }
450
477
 
451
478
  if (await fileManager.pathExists(agentsDir)) {
452
- const agentFiles = glob.sync("*.md", { cwd: agentsDir });
453
- allAgentIds.push(...agentFiles.map((file) => path.basename(file, ".md")));
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 expansionDirs = glob.sync(".*/agents", { cwd: installDir });
458
- for (const expDir of expansionDirs) {
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("*.md", { cwd: fullExpDir });
461
- allAgentIds.push(...expAgentFiles.map((file) => path.basename(file, ".md")));
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, ".bmad-core", "agents");
499
+ let agentsDir = path.join(installDir, '.bmad-core', 'agents');
473
500
  if (!(await fileManager.pathExists(agentsDir))) {
474
- agentsDir = path.join(installDir, "bmad-core", "agents");
501
+ agentsDir = path.join(installDir, 'bmad-core', 'agents');
475
502
  }
476
503
 
477
504
  if (await fileManager.pathExists(agentsDir)) {
478
- const glob = require("glob");
479
- const agentFiles = glob.sync("*.md", { cwd: agentsDir });
480
- allAgentIds.push(...agentFiles.map((file) => path.basename(file, ".md")));
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, ".bmad-core", "tasks");
517
+ let tasksDir = path.join(installDir, '.bmad-core', 'tasks');
491
518
  if (!(await fileManager.pathExists(tasksDir))) {
492
- tasksDir = path.join(installDir, "bmad-core", "tasks");
519
+ tasksDir = path.join(installDir, 'bmad-core', 'tasks');
493
520
  }
494
521
 
495
522
  if (await fileManager.pathExists(tasksDir)) {
496
- const glob = require("glob");
497
- const taskFiles = glob.sync("*.md", { cwd: tasksDir });
498
- allTaskIds.push(...taskFiles.map((file) => path.basename(file, ".md")));
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, "common", "tasks");
529
+ const commonTasksDir = path.join(installDir, 'common', 'tasks');
503
530
  if (await fileManager.pathExists(commonTasksDir)) {
504
- const commonTaskFiles = glob.sync("*.md", { cwd: commonTasksDir });
505
- allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, ".md")));
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, ".bmad-core", "agents", `${agentId}.md`),
515
- path.join(installDir, "agents", `${agentId}.md`)
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("glob");
520
- const expansionDirs = glob.sync(".*/agents", { cwd: installDir });
521
- for (const expDir of expansionDirs) {
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.split('-').map(word =>
546
- word.charAt(0).toUpperCase() + word.slice(1)
547
- ).join(' ');
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("glob");
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, ".bmad-core", "tasks");
583
+ let tasksDir = path.join(installDir, '.bmad-core', 'tasks');
556
584
  if (!(await fileManager.pathExists(tasksDir))) {
557
- tasksDir = path.join(installDir, "bmad-core", "tasks");
585
+ tasksDir = path.join(installDir, 'bmad-core', 'tasks');
558
586
  }
559
587
 
560
588
  if (await fileManager.pathExists(tasksDir)) {
561
- const taskFiles = glob.sync("*.md", { cwd: tasksDir });
562
- allTaskIds.push(...taskFiles.map((file) => path.basename(file, ".md")));
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, "common", "tasks");
594
+ const commonTasksDir = path.join(installDir, 'common', 'tasks');
567
595
  if (await fileManager.pathExists(commonTasksDir)) {
568
- const commonTaskFiles = glob.sync("*.md", { cwd: commonTasksDir });
569
- allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, ".md")));
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 expansionDirs = glob.sync(".*/tasks", { cwd: installDir });
574
- for (const expDir of expansionDirs) {
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("*.md", { cwd: fullExpDir });
577
- allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, ".md")));
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, "expansion-packs");
609
+ const expansionPacksDir = path.join(installDir, 'expansion-packs');
582
610
  if (await fileManager.pathExists(expansionPacksDir)) {
583
- const expPackDirs = glob.sync("*/tasks", { cwd: expansionPacksDir });
584
- for (const expDir of expPackDirs) {
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("*.md", { cwd: fullExpDir });
587
- allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, ".md")));
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, ".bmad-core", "tasks", `${taskId}.md`),
599
- path.join(installDir, "bmad-core", "tasks", `${taskId}.md`),
600
- path.join(installDir, "common", "tasks", `${taskId}.md`)
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("glob");
632
+ const glob = require('glob');
605
633
 
606
634
  // Check dot folder expansion packs
607
- const expansionDirs = glob.sync(".*/tasks", { cwd: installDir });
608
- for (const expDir of expansionDirs) {
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, "expansion-packs");
641
+ const expansionPacksDir = path.join(installDir, 'expansion-packs');
614
642
  if (await fileManager.pathExists(expansionPacksDir)) {
615
- const expPackDirs = glob.sync("*/tasks", { cwd: expansionPacksDir });
616
- for (const expDir of expPackDirs) {
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, ".bmad-core", "core-config.yaml");
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, "bmad-core", "core-config.yaml");
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 || "BMad";
667
+ return config.slashPrefix || 'BMad';
640
668
  }
641
- return "BMad"; // fallback
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 || "BMad";
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 "BMad";
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("glob");
658
- const dotExpansions = glob.sync(".bmad-*", { cwd: installDir });
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 !== ".bmad-core") {
689
+ if (dotExpansion !== '.bmad-core') {
662
690
  const packPath = path.join(installDir, dotExpansion);
663
- const packName = dotExpansion.substring(1); // remove the dot
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, "expansion-packs");
700
+ const expansionPacksDir = path.join(installDir, 'expansion-packs');
673
701
  if (await fileManager.pathExists(expansionPacksDir)) {
674
- const packDirs = glob.sync("*", { cwd: expansionPacksDir });
702
+ const packDirectories = glob.sync('*', { cwd: expansionPacksDir });
675
703
 
676
- for (const packDir of packDirs) {
704
+ for (const packDir of packDirectories) {
677
705
  const packPath = path.join(expansionPacksDir, packDir);
678
- if ((await fileManager.pathExists(packPath)) &&
679
- (await fileManager.pathExists(path.join(packPath, "config.yaml")))) {
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, "config.yaml");
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, "agents");
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("glob");
714
- const agentFiles = glob.sync("*.md", { cwd: agentsDir });
715
- return agentFiles.map(file => path.basename(file, ".md"));
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, "tasks");
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("glob");
730
- const taskFiles = glob.sync("*.md", { cwd: tasksDir });
731
- return taskFiles.map(file => path.basename(file, ".md"));
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, ".roomodes");
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 ? titleMatch[1].trim() : await this.getAgentTitle(agentId, installDir);
790
- const icon = iconMatch ? iconMatch[1].trim() : "🤖";
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
- newModesContent += ` description: '${permissions.description}'\n`;
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).replace(/\\/g, '/');
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() + "\n" + newModesContent;
863
+ roomodesContent = existingContent.trim() + '\n' + newModesContent;
833
864
  } else {
834
865
  // Create new .roomodes file with proper YAML structure
835
- roomodesContent = "customModes:\n" + newModesContent;
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("✓ Created .roomodes file in project root"));
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("Custom modes will be available when you open this project in Roo Code"));
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, ".kilocodemodes");
880
+ const filePath = path.join(installDir, '.kilocodemodes');
850
881
  const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
851
882
 
852
- let existingModes = [], existingContent = "";
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(chalk.yellow(`Found existing .kilocodemodes file with ${existingModes.length} modes`));
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 = (yaml.match(/title:\s*(.+)/)?.[1]?.trim()) || await this.getAgentTitle(agentId, installDir);
890
- const icon = (yaml.match(/icon:\s*(.+)/)?.[1]?.trim()) || '🤖';
891
- const whenToUse = (yaml.match(/whenToUse:\s*"(.+)"/)?.[1]?.trim()) || `Use for ${title} tasks`;
892
- const roleDefinition = (yaml.match(/roleDefinition:\s*"(.+)"/)?.[1]?.trim()) ||
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).replace(/\\/g, '/');
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
- newContent += ` description: '${agentPermission.description}'\n`;
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() + "\n" + newContent
929
- : "customModes:\n" + newContent;
963
+ ? existingContent.trim() + '\n' + newContent
964
+ : 'customModes:\n' + newContent;
930
965
 
931
966
  await fileManager.writeFile(filePath, finalContent);
932
- console.log(chalk.green("✓ Created .kilocodemodes file in project root"));
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("Custom modes will be available when you open this project in KiloCode"));
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, ".clinerules");
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 += "## Role Definition\n\n";
999
+ mdContent += '## Role Definition\n\n';
965
1000
  mdContent +=
966
- "When the user types `@" + agentId + "`, adopt this persona and follow these guidelines:\n\n";
967
- mdContent += "```yaml\n";
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, "").trim();
1011
+ mdContent += agentContent.replace(/^#.*$/m, '').trim();
975
1012
  }
976
- mdContent += "\n```\n\n";
977
- mdContent += "## Project Standards\n\n";
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).replace(/\\/g, '/');
1018
+ const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
982
1019
  mdContent += `- Reference the complete agent definition in [${relativePath}](${relativePath})\n\n`;
983
- mdContent += "## Usage\n\n";
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, ".gemini");
998
- const bmadMethodDir = path.join(geminiDir, "bmad-method");
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, "settings.json");
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("agents/")
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
- settingsPath,
1023
- JSON.stringify(settings, null, 2)
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, "agents");
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("✓ Removed old .gemini/agents directory"));
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 += "## Agent Activation\n\n";
1092
+ agentRuleContent += '## Agent Activation\n\n';
1060
1093
  agentRuleContent +=
1061
- "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";
1062
- agentRuleContent += "```yaml\n";
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, "").trim();
1102
+ agentRuleContent += agentContent.replace(/^#.*$/m, '').trim();
1071
1103
  }
1072
- agentRuleContent += "\n```\n\n";
1073
- agentRuleContent += "## File Reference\n\n";
1074
- const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
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 += "## Usage\n\n";
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 + "\n\n---\n\n";
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, "GEMINI.md");
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, ".qwen");
1098
- const bmadMethodDir = path.join(qwenDir, "bmad-method");
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, "settings.json");
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("agents/")
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
- settingsPath,
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, "agents");
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("✓ Removed old .qwen/agents directory"));
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 += "## Agent Activation\n\n";
1185
+ agentRuleContent += '## Agent Activation\n\n';
1160
1186
  agentRuleContent +=
1161
- "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";
1162
- agentRuleContent += "```yaml\n";
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, "").trim();
1195
+ agentRuleContent += agentContent.replace(/^#.*$/m, '').trim();
1171
1196
  }
1172
- agentRuleContent += "\n```\n\n";
1173
- agentRuleContent += "## File Reference\n\n";
1174
- const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
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 += "## Usage\n\n";
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 + "\n\n---\n\n";
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, "QWEN.md");
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(installDir, selectedAgent, spinner = null, preConfiguredSettings = null) {
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, ".github", "chatmodes");
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.replace(/"/g, '\\"')}"
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, ".vscode");
1246
- const settingsPath = path.join(vscodeDir, "settings.json");
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("Found existing .vscode/settings.json. Merging BMad settings..."));
1257
- } catch (error) {
1258
- console.warn(chalk.yellow("Could not parse existing settings.json. Creating new one."));
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("🔧 Github Copilot Agent Settings Configuration"));
1272
- console.log(chalk.dim("BMad works best with specific VS Code settings for optimal agent experience."));
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: 'Skip settings configuration (I\'ll configure manually later)',
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("⚠️ Skipping VS Code settings configuration."));
1304
- console.log(chalk.dim("You can manually configure these settings in .vscode/settings.json:"));
1305
- console.log(chalk.dim(" • chat.agent.enabled: true"));
1306
- console.log(chalk.dim(" • chat.agent.maxRequests: 15"));
1307
- console.log(chalk.dim(" • github.copilot.chat.agent.runTasks: true"));
1308
- console.log(chalk.dim(" • chat.mcp.discovery.enabled: true"));
1309
- console.log(chalk.dim(" • github.copilot.chat.agent.autoFix: true"));
1310
- console.log(chalk.dim(" • chat.tools.autoApprove: false"));
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
- "chat.agent.enabled": true,
1318
- "chat.agent.maxRequests": 15,
1319
- "github.copilot.chat.agent.runTasks": true,
1320
- "chat.mcp.discovery.enabled": true,
1321
- "github.copilot.chat.agent.autoFix": true,
1322
- "chat.tools.autoApprove": false
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("✓ Using recommended BMad defaults for Github Copilot settings"));
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 num = parseInt(input);
1344
- if (isNaN(num) || num < 1 || num > 50) {
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
- "chat.agent.enabled": true, // Always enabled - required for BMad agents
1383
- "chat.agent.maxRequests": parseInt(manualSettings.maxRequests),
1384
- "github.copilot.chat.agent.runTasks": manualSettings.runTasks,
1385
- "chat.mcp.discovery.enabled": manualSettings.mcpDiscovery,
1386
- "github.copilot.chat.agent.autoFix": manualSettings.autoFix,
1387
- "chat.tools.autoApprove": manualSettings.autoApprove
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("✓ Custom settings configured"));
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("✓ VS Code workspace settings configured successfully"));
1400
- console.log(chalk.dim(" Settings written to .vscode/settings.json:"));
1401
- Object.entries(bmadSettings).forEach(([key, value]) => {
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("You can modify these settings anytime in .vscode/settings.json"));
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