@zeyue0329/xiaoma-cli 1.0.37 → 1.0.39

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 (89) hide show
  1. package/.idea/workspace.xml +27 -26
  2. package/JAVA-BACKEND-COMMANDS-REFERENCE.md +62 -52
  3. package/JAVA-BACKEND-ITERATION-GUIDE.md +125 -18
  4. package/README.md +1 -1
  5. package/common/utils/bmad-doc-template.md +5 -5
  6. package/dist/agents/analyst.txt +35 -5
  7. package/dist/agents/architect.txt +217 -31
  8. package/dist/agents/automation-orchestrator.txt +4 -4
  9. package/dist/agents/dev.txt +3 -3
  10. package/dist/agents/full-requirement-orchestrator.txt +11 -11
  11. package/dist/agents/qa.txt +102 -102
  12. package/dist/agents/sm.txt +6 -6
  13. package/dist/agents/ux-expert.txt +6 -1
  14. package/dist/agents/workflow-executor.txt +879 -0
  15. package/dist/agents/xiaoma-master.txt +258 -37
  16. package/dist/teams/team-all.txt +1223 -445
  17. package/dist/teams/team-fullstack-with-database.txt +384 -446
  18. package/dist/teams/team-fullstack.txt +258 -37
  19. package/dist/teams/team-ide-minimal.txt +111 -111
  20. package/dist/teams/team-no-ui.txt +252 -36
  21. package/docs/architecture-sharding-modification.md +623 -0
  22. package/docs/automated-requirements-analysis-outputs.md +896 -0
  23. package/package.json +1 -1
  24. package/tools/builders/web-builder.js +292 -142
  25. package/tools/bump-all-versions.js +50 -32
  26. package/tools/cli.js +52 -47
  27. package/tools/flattener/aggregate.js +30 -12
  28. package/tools/flattener/binary.js +46 -43
  29. package/tools/flattener/discovery.js +23 -15
  30. package/tools/flattener/files.js +6 -6
  31. package/tools/flattener/ignoreRules.js +122 -121
  32. package/tools/flattener/main.js +249 -144
  33. package/tools/flattener/projectRoot.js +74 -69
  34. package/tools/flattener/prompts.js +12 -10
  35. package/tools/flattener/stats.helpers.js +90 -61
  36. package/tools/flattener/stats.js +1 -1
  37. package/tools/flattener/test-matrix.js +225 -170
  38. package/tools/flattener/xml.js +31 -23
  39. package/tools/installer/bin/xiaoma.js +199 -153
  40. package/tools/installer/lib/config-loader.js +76 -47
  41. package/tools/installer/lib/file-manager.js +101 -44
  42. package/tools/installer/lib/ide-base-setup.js +49 -39
  43. package/tools/installer/lib/ide-setup.js +694 -380
  44. package/tools/installer/lib/installer.js +802 -469
  45. package/tools/installer/lib/memory-profiler.js +22 -12
  46. package/tools/installer/lib/module-manager.js +16 -14
  47. package/tools/installer/lib/resource-locator.js +61 -35
  48. package/tools/lib/dependency-resolver.js +34 -23
  49. package/tools/lib/yaml-utils.js +7 -2
  50. package/tools/preview-release-notes.js +33 -25
  51. package/tools/shared/bannerArt.js +3 -3
  52. package/tools/sync-installer-version.js +16 -7
  53. package/tools/upgraders/v3-to-v4-upgrader.js +244 -163
  54. package/tools/version-bump.js +24 -18
  55. package/tools/xiaoma-npx-wrapper.js +15 -10
  56. package/tools/yaml-format.js +60 -36
  57. package/xiaoma-core/agent-teams/team-fullstack-with-database.yaml +0 -1
  58. package/xiaoma-core/agents/automated-fix-validator.yaml +2 -1
  59. package/xiaoma-core/agents/automated-quality-validator.yaml +10 -5
  60. package/xiaoma-core/agents/automation-orchestrator.md +4 -4
  61. package/xiaoma-core/agents/dev.md +4 -4
  62. package/xiaoma-core/agents/enhanced-workflow-orchestrator.yaml +2 -1
  63. package/xiaoma-core/agents/full-requirement-orchestrator.md +11 -11
  64. package/xiaoma-core/agents/global-requirements-auditor.yaml +11 -3
  65. package/xiaoma-core/agents/intelligent-template-adapter.yaml +19 -5
  66. package/xiaoma-core/agents/master-execution-engine.yaml +19 -5
  67. package/xiaoma-core/agents/workflow-executor.md +8 -4
  68. package/xiaoma-core/agents/xiaoma-master.md +1 -1
  69. package/xiaoma-core/data/test-levels-framework.md +12 -12
  70. package/xiaoma-core/tasks/analyze-existing-database.md +1 -1
  71. package/xiaoma-core/tasks/apply-qa-fixes.md +3 -3
  72. package/xiaoma-core/tasks/batch-story-generation.md +22 -22
  73. package/xiaoma-core/tasks/create-enhanced-story-with-database.md +6 -6
  74. package/xiaoma-core/tasks/nfr-assess.md +6 -6
  75. package/xiaoma-core/tasks/project-integration-testing.md +42 -42
  76. package/xiaoma-core/tasks/qa-gate.md +23 -23
  77. package/xiaoma-core/tasks/review-story.md +18 -18
  78. package/xiaoma-core/tasks/risk-profile.md +25 -25
  79. package/xiaoma-core/tasks/serial-development-orchestration.md +51 -51
  80. package/xiaoma-core/tasks/test-design.md +9 -9
  81. package/xiaoma-core/tasks/trace-requirements.md +21 -21
  82. package/xiaoma-core/templates/competitor-analysis-tmpl.yaml +35 -5
  83. package/xiaoma-core/templates/front-end-architecture-tmpl.yaml +77 -11
  84. package/xiaoma-core/templates/front-end-spec-tmpl.yaml +6 -1
  85. package/xiaoma-core/templates/fullstack-architecture-tmpl.yaml +140 -20
  86. package/xiaoma-core/templates/global-qa-monitoring-tmpl.yaml +2 -1
  87. package/xiaoma-core/templates/requirements-coverage-audit.yaml +2 -1
  88. package/xiaoma-core/workflows/automated-requirements-analysis.yaml +283 -6
  89. package/dist/agents/database-architect.txt +0 -322
@@ -1,13 +1,13 @@
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');
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() {
@@ -19,20 +19,31 @@ class IdeSetup extends BaseIdeSetup {
19
19
  if (this.ideAgentConfig) return this.ideAgentConfig;
20
20
 
21
21
  try {
22
- const configPath = path.join(__dirname, '..', 'config', 'ide-agent-config.yaml');
23
- const configContent = await fs.readFile(configPath, 'utf8');
22
+ const configPath = path.join(
23
+ __dirname,
24
+ "..",
25
+ "config",
26
+ "ide-agent-config.yaml",
27
+ );
28
+ const configContent = await fs.readFile(configPath, "utf8");
24
29
  this.ideAgentConfig = yaml.load(configContent);
25
30
  return this.ideAgentConfig;
26
31
  } catch {
27
- console.warn('Failed to load IDE agent configuration, using defaults');
32
+ console.warn("Failed to load IDE agent configuration, using defaults");
28
33
  return {
29
- 'roo-permissions': {},
30
- 'cline-order': {},
34
+ "roo-permissions": {},
35
+ "cline-order": {},
31
36
  };
32
37
  }
33
38
  }
34
39
 
35
- async setup(ide, installDir, selectedAgent = null, spinner = null, preConfiguredSettings = null) {
40
+ async setup(
41
+ ide,
42
+ installDir,
43
+ selectedAgent = null,
44
+ spinner = null,
45
+ preConfiguredSettings = null,
46
+ ) {
36
47
  const ideConfig = await configLoader.getIdeConfiguration(ide);
37
48
 
38
49
  if (!ideConfig) {
@@ -41,46 +52,58 @@ class IdeSetup extends BaseIdeSetup {
41
52
  }
42
53
 
43
54
  switch (ide) {
44
- case 'cursor': {
55
+ case "cursor": {
45
56
  return this.setupCursor(installDir, selectedAgent);
46
57
  }
47
- case 'claude-code': {
58
+ case "claude-code": {
48
59
  return this.setupClaudeCode(installDir, selectedAgent);
49
60
  }
50
- case 'crush': {
61
+ case "crush": {
51
62
  return this.setupCrush(installDir, selectedAgent);
52
63
  }
53
- case 'windsurf': {
64
+ case "windsurf": {
54
65
  return this.setupWindsurf(installDir, selectedAgent);
55
66
  }
56
- case 'trae': {
67
+ case "trae": {
57
68
  return this.setupTrae(installDir, selectedAgent);
58
69
  }
59
- case 'roo': {
70
+ case "roo": {
60
71
  return this.setupRoo(installDir, selectedAgent);
61
72
  }
62
- case 'cline': {
73
+ case "cline": {
63
74
  return this.setupCline(installDir, selectedAgent);
64
75
  }
65
- case 'kilo': {
76
+ case "kilo": {
66
77
  return this.setupKilocode(installDir, selectedAgent);
67
78
  }
68
- case 'gemini': {
79
+ case "gemini": {
69
80
  return this.setupGeminiCli(installDir, selectedAgent);
70
81
  }
71
- case 'github-copilot': {
72
- return this.setupGitHubCopilot(installDir, selectedAgent, spinner, preConfiguredSettings);
82
+ case "github-copilot": {
83
+ return this.setupGitHubCopilot(
84
+ installDir,
85
+ selectedAgent,
86
+ spinner,
87
+ preConfiguredSettings,
88
+ );
73
89
  }
74
- case 'qwen-code': {
90
+ case "qwen-code": {
75
91
  return this.setupQwenCode(installDir, selectedAgent);
76
92
  }
77
- case 'auggie-cli': {
78
- return this.setupAuggieCLI(installDir, selectedAgent, spinner, preConfiguredSettings);
93
+ case "auggie-cli": {
94
+ return this.setupAuggieCLI(
95
+ installDir,
96
+ selectedAgent,
97
+ spinner,
98
+ preConfiguredSettings,
99
+ );
79
100
  }
80
- case 'codex': {
81
- return this.setupCodex(installDir, selectedAgent, { webEnabled: false });
101
+ case "codex": {
102
+ return this.setupCodex(installDir, selectedAgent, {
103
+ webEnabled: false,
104
+ });
82
105
  }
83
- case 'codex-web': {
106
+ case "codex-web": {
84
107
  return this.setupCodex(installDir, selectedAgent, { webEnabled: true });
85
108
  }
86
109
  default: {
@@ -94,15 +117,17 @@ class IdeSetup extends BaseIdeSetup {
94
117
  options = options ?? { webEnabled: false };
95
118
  // Codex reads AGENTS.md at the project root as project memory (CLI & Web).
96
119
  // Inject/update a XIAOMAMA section with guidance, directory, and details.
97
- const filePath = path.join(installDir, 'AGENTS.md');
98
- const startMarker = '<!-- BEGIN: XIAOMAMA-AGENTS -->';
99
- const endMarker = '<!-- END: XIAOMAMA-AGENTS -->';
120
+ const filePath = path.join(installDir, "AGENTS.md");
121
+ const startMarker = "<!-- BEGIN: XIAOMAMA-AGENTS -->";
122
+ const endMarker = "<!-- END: XIAOMAMA-AGENTS -->";
100
123
 
101
- const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
124
+ const agents = selectedAgent
125
+ ? [selectedAgent]
126
+ : await this.getAllAgentIds(installDir);
102
127
  const tasks = await this.getAllTaskIds(installDir);
103
128
 
104
129
  // Build XIAOMAMA section content
105
- let section = '';
130
+ let section = "";
106
131
  section += `${startMarker}\n`;
107
132
  section += `# XIAOMA-CLI Agents and Tasks\n\n`;
108
133
  section += `This section is auto-generated by XIAOMA-CLI for Codex. Codex merges this AGENTS.md into context.\n\n`;
@@ -129,23 +154,40 @@ class IdeSetup extends BaseIdeSetup {
129
154
  const yamlMatch = raw.match(/```ya?ml\r?\n([\s\S]*?)```/);
130
155
  const yamlBlock = yamlMatch ? yamlMatch[1].trim() : null;
131
156
  const title = await this.getAgentTitle(agentId, installDir);
132
- const whenToUse = yamlBlock?.match(/whenToUse:\s*"?([^\n"]+)"?/i)?.[1]?.trim() || '';
133
- agentSummaries.push({ agentId, title, whenToUse, yamlBlock, raw, path: agentPath });
134
- section += `| ${title} | ${agentId} | ${whenToUse || '—'} |\n`;
157
+ const whenToUse =
158
+ yamlBlock?.match(/whenToUse:\s*"?([^\n"]+)"?/i)?.[1]?.trim() || "";
159
+ agentSummaries.push({
160
+ agentId,
161
+ title,
162
+ whenToUse,
163
+ yamlBlock,
164
+ raw,
165
+ path: agentPath,
166
+ });
167
+ section += `| ${title} | ${agentId} | ${whenToUse || "—"} |\n`;
135
168
  }
136
169
  section += `\n`;
137
170
 
138
171
  // Detailed agent sections
139
- for (const { agentId, title, whenToUse, yamlBlock, raw, path: agentPath } of agentSummaries) {
140
- const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
172
+ for (const {
173
+ agentId,
174
+ title,
175
+ whenToUse,
176
+ yamlBlock,
177
+ raw,
178
+ path: agentPath,
179
+ } of agentSummaries) {
180
+ const relativePath = path
181
+ .relative(installDir, agentPath)
182
+ .replaceAll("\\", "/");
141
183
  section += `### ${title} (id: ${agentId})\n`;
142
184
  section += `Source: ${relativePath}\n\n`;
143
185
  if (whenToUse) section += `- When to use: ${whenToUse}\n`;
144
186
  section += `- How to activate: Mention "As ${agentId}, ..." or "Use ${title} to ..."\n\n`;
145
187
  if (yamlBlock) {
146
- section += '```yaml\n' + yamlBlock + '\n```\n\n';
188
+ section += "```yaml\n" + yamlBlock + "\n```\n\n";
147
189
  } else {
148
- section += '```md\n' + raw.trim() + '\n```\n\n';
190
+ section += "```md\n" + raw.trim() + "\n```\n\n";
149
191
  }
150
192
  }
151
193
 
@@ -157,24 +199,26 @@ class IdeSetup extends BaseIdeSetup {
157
199
  const taskPath = await this.findTaskPath(taskId, installDir);
158
200
  if (!taskPath) continue;
159
201
  const raw = await fileManager.readFile(taskPath);
160
- const relativePath = path.relative(installDir, taskPath).replaceAll('\\', '/');
202
+ const relativePath = path
203
+ .relative(installDir, taskPath)
204
+ .replaceAll("\\", "/");
161
205
  section += `### Task: ${taskId}\n`;
162
206
  section += `Source: ${relativePath}\n`;
163
207
  section += `- How to use: "Use task ${taskId} with the appropriate agent" and paste relevant parts as needed.\n\n`;
164
- section += '```md\n' + raw.trim() + '\n```\n\n';
208
+ section += "```md\n" + raw.trim() + "\n```\n\n";
165
209
  }
166
210
  }
167
211
 
168
212
  section += `${endMarker}\n`;
169
213
 
170
214
  // Write or update AGENTS.md
171
- let finalContent = '';
215
+ let finalContent = "";
172
216
  if (await fileManager.pathExists(filePath)) {
173
217
  const existing = await fileManager.readFile(filePath);
174
218
  if (existing.includes(startMarker) && existing.includes(endMarker)) {
175
219
  // Replace existing XIAOMAMA block
176
220
  const pattern = String.raw`${startMarker}[\s\S]*?${endMarker}`;
177
- const replaced = existing.replace(new RegExp(pattern, 'm'), section);
221
+ const replaced = existing.replace(new RegExp(pattern, "m"), section);
178
222
  finalContent = replaced;
179
223
  } else {
180
224
  // Append XIAOMAMA block to existing file
@@ -182,47 +226,66 @@ class IdeSetup extends BaseIdeSetup {
182
226
  }
183
227
  } else {
184
228
  // Create fresh AGENTS.md with a small header and XIAOMAMA block
185
- finalContent += '# Project Agents\n\n';
186
- finalContent += 'This file provides guidance and memory for Codex CLI.\n\n';
229
+ finalContent += "# Project Agents\n\n";
230
+ finalContent +=
231
+ "This file provides guidance and memory for Codex CLI.\n\n";
187
232
  finalContent += section;
188
233
  }
189
234
 
190
235
  await fileManager.writeFile(filePath, finalContent);
191
- console.log(chalk.green('✓ Created/updated AGENTS.md for Codex CLI integration'));
236
+ console.log(
237
+ chalk.green("✓ Created/updated AGENTS.md for Codex CLI integration"),
238
+ );
192
239
  console.log(
193
240
  chalk.dim(
194
- 'Codex reads AGENTS.md automatically. Run `codex` in this project to use XIAOMAMA agents.',
241
+ "Codex reads AGENTS.md automatically. Run `codex` in this project to use XIAOMAMA agents.",
195
242
  ),
196
243
  );
197
244
 
198
245
  // Optionally add helpful npm scripts if a package.json exists
199
246
  try {
200
- const pkgPath = path.join(installDir, 'package.json');
247
+ const pkgPath = path.join(installDir, "package.json");
201
248
  if (await fileManager.pathExists(pkgPath)) {
202
249
  const pkgRaw = await fileManager.readFile(pkgPath);
203
250
  const pkg = JSON.parse(pkgRaw);
204
251
  pkg.scripts = pkg.scripts || {};
205
252
  const updated = { ...pkg.scripts };
206
- if (!updated['bmad:refresh']) updated['bmad:refresh'] = 'xiaoma-cli install -f -i codex';
207
- if (!updated['bmad:list']) updated['bmad:list'] = 'xiaoma-cli list:agents';
208
- if (!updated['bmad:validate']) updated['bmad:validate'] = 'xiaoma-cli validate';
253
+ if (!updated["bmad:refresh"])
254
+ updated["bmad:refresh"] = "xiaoma-cli install -f -i codex";
255
+ if (!updated["bmad:list"])
256
+ updated["bmad:list"] = "xiaoma-cli list:agents";
257
+ if (!updated["bmad:validate"])
258
+ updated["bmad:validate"] = "xiaoma-cli validate";
209
259
  const changed = JSON.stringify(updated) !== JSON.stringify(pkg.scripts);
210
260
  if (changed) {
211
261
  const newPkg = { ...pkg, scripts: updated };
212
- await fileManager.writeFile(pkgPath, JSON.stringify(newPkg, null, 2) + '\n');
213
- console.log(chalk.green('✓ Added npm scripts: bmad:refresh, bmad:list, bmad:validate'));
262
+ await fileManager.writeFile(
263
+ pkgPath,
264
+ JSON.stringify(newPkg, null, 2) + "\n",
265
+ );
266
+ console.log(
267
+ chalk.green(
268
+ "✓ Added npm scripts: bmad:refresh, bmad:list, bmad:validate",
269
+ ),
270
+ );
214
271
  }
215
272
  }
216
273
  } catch {
217
274
  console.log(
218
- chalk.yellow('⚠︎ Skipped adding npm scripts (package.json not writable or invalid)'),
275
+ chalk.yellow(
276
+ "⚠︎ Skipped adding npm scripts (package.json not writable or invalid)",
277
+ ),
219
278
  );
220
279
  }
221
280
 
222
281
  // Adjust .gitignore behavior depending on Codex mode
223
282
  try {
224
- const gitignorePath = path.join(installDir, '.gitignore');
225
- const ignoreLines = ['# XIAOMAMA (local only)', '.xiaoma-core/', '.bmad-*/'];
283
+ const gitignorePath = path.join(installDir, ".gitignore");
284
+ const ignoreLines = [
285
+ "# XIAOMAMA (local only)",
286
+ ".xiaoma-core/",
287
+ ".bmad-*/",
288
+ ];
226
289
  const exists = await fileManager.pathExists(gitignorePath);
227
290
  if (options.webEnabled) {
228
291
  if (exists) {
@@ -230,40 +293,55 @@ class IdeSetup extends BaseIdeSetup {
230
293
  // Remove lines that ignore XIAOMAMA dot-folders
231
294
  const updated = gi
232
295
  .split(/\r?\n/)
233
- .filter((l) => !/^\s*\.xiaoma-core\/?\s*$/.test(l) && !/^\s*\.bmad-\*\/?\s*$/.test(l))
234
- .join('\n');
296
+ .filter(
297
+ (l) =>
298
+ !/^\s*\.xiaoma-core\/?\s*$/.test(l) &&
299
+ !/^\s*\.bmad-\*\/?\s*$/.test(l),
300
+ )
301
+ .join("\n");
235
302
  if (updated !== gi) {
236
- await fileManager.writeFile(gitignorePath, updated.trimEnd() + '\n');
237
- console.log(chalk.green('✓ Updated .gitignore to include .xiaoma-core in commits'));
303
+ await fileManager.writeFile(
304
+ gitignorePath,
305
+ updated.trimEnd() + "\n",
306
+ );
307
+ console.log(
308
+ chalk.green(
309
+ "✓ Updated .gitignore to include .xiaoma-core in commits",
310
+ ),
311
+ );
238
312
  }
239
313
  }
240
314
  } else {
241
315
  // Local-only: add ignores if missing
242
- let base = exists ? await fileManager.readFile(gitignorePath) : '';
243
- const haveCore = base.includes('.xiaoma-core/');
244
- const haveStar = base.includes('.bmad-*/');
316
+ let base = exists ? await fileManager.readFile(gitignorePath) : "";
317
+ const haveCore = base.includes(".xiaoma-core/");
318
+ const haveStar = base.includes(".bmad-*/");
245
319
  if (!haveCore || !haveStar) {
246
- const sep = base.endsWith('\n') || base.length === 0 ? '' : '\n';
247
- const add = [!haveCore || !haveStar ? ignoreLines.join('\n') : '']
320
+ const sep = base.endsWith("\n") || base.length === 0 ? "" : "\n";
321
+ const add = [!haveCore || !haveStar ? ignoreLines.join("\n") : ""]
248
322
  .filter(Boolean)
249
- .join('\n');
250
- const out = base + sep + add + '\n';
323
+ .join("\n");
324
+ const out = base + sep + add + "\n";
251
325
  await fileManager.writeFile(gitignorePath, out);
252
326
  console.log(
253
- chalk.green('✓ Added .xiaoma-core/* to .gitignore for local-only Codex setup'),
327
+ chalk.green(
328
+ "✓ Added .xiaoma-core/* to .gitignore for local-only Codex setup",
329
+ ),
254
330
  );
255
331
  }
256
332
  }
257
333
  } catch {
258
- console.log(chalk.yellow('⚠︎ Could not update .gitignore (skipping)'));
334
+ console.log(chalk.yellow("⚠︎ Could not update .gitignore (skipping)"));
259
335
  }
260
336
 
261
337
  return true;
262
338
  }
263
339
 
264
340
  async setupCursor(installDir, selectedAgent) {
265
- const cursorRulesDir = path.join(installDir, '.cursor', 'rules', 'bmad');
266
- const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
341
+ const cursorRulesDir = path.join(installDir, ".cursor", "rules", "bmad");
342
+ const agents = selectedAgent
343
+ ? [selectedAgent]
344
+ : await this.getAllAgentIds(installDir);
267
345
 
268
346
  await fileManager.ensureDirectory(cursorRulesDir);
269
347
 
@@ -271,7 +349,12 @@ class IdeSetup extends BaseIdeSetup {
271
349
  const agentPath = await this.findAgentPath(agentId, installDir);
272
350
 
273
351
  if (agentPath) {
274
- const mdcContent = await this.createAgentRuleContent(agentId, agentPath, installDir, 'mdc');
352
+ const mdcContent = await this.createAgentRuleContent(
353
+ agentId,
354
+ agentPath,
355
+ installDir,
356
+ "mdc",
357
+ );
275
358
  const mdcPath = path.join(cursorRulesDir, `${agentId}.mdc`);
276
359
  await fileManager.writeFile(mdcPath, mdcContent);
277
360
  console.log(chalk.green(`✓ Created rule: ${agentId}.mdc`));
@@ -285,21 +368,25 @@ class IdeSetup extends BaseIdeSetup {
285
368
  async setupCrush(installDir, selectedAgent) {
286
369
  // Setup xiaoma-core commands
287
370
  const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
288
- const coreAgents = selectedAgent ? [selectedAgent] : await this.getCoreAgentIds(installDir);
371
+ const coreAgents = selectedAgent
372
+ ? [selectedAgent]
373
+ : await this.getCoreAgentIds(installDir);
289
374
  const coreTasks = await this.getCoreTaskIds(installDir);
290
375
  await this.setupCrushForPackage(
291
376
  installDir,
292
- 'core',
377
+ "core",
293
378
  coreSlashPrefix,
294
379
  coreAgents,
295
380
  coreTasks,
296
- '.xiaoma-core',
381
+ ".xiaoma-core",
297
382
  );
298
383
 
299
384
  // Setup expansion pack commands
300
385
  const expansionPacks = await this.getInstalledExpansionPacks(installDir);
301
386
  for (const packInfo of expansionPacks) {
302
- const packSlashPrefix = await this.getExpansionPackSlashPrefix(packInfo.path);
387
+ const packSlashPrefix = await this.getExpansionPackSlashPrefix(
388
+ packInfo.path,
389
+ );
303
390
  const packAgents = await this.getExpansionPackAgents(packInfo.path);
304
391
  const packTasks = await this.getExpansionPackTasks(packInfo.path);
305
392
 
@@ -323,21 +410,25 @@ class IdeSetup extends BaseIdeSetup {
323
410
  async setupClaudeCode(installDir, selectedAgent) {
324
411
  // Setup xiaoma-core commands
325
412
  const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
326
- const coreAgents = selectedAgent ? [selectedAgent] : await this.getCoreAgentIds(installDir);
413
+ const coreAgents = selectedAgent
414
+ ? [selectedAgent]
415
+ : await this.getCoreAgentIds(installDir);
327
416
  const coreTasks = await this.getCoreTaskIds(installDir);
328
417
  await this.setupClaudeCodeForPackage(
329
418
  installDir,
330
- 'core',
419
+ "core",
331
420
  coreSlashPrefix,
332
421
  coreAgents,
333
422
  coreTasks,
334
- '.xiaoma-core',
423
+ ".xiaoma-core",
335
424
  );
336
425
 
337
426
  // Setup expansion pack commands
338
427
  const expansionPacks = await this.getInstalledExpansionPacks(installDir);
339
428
  for (const packInfo of expansionPacks) {
340
- const packSlashPrefix = await this.getExpansionPackSlashPrefix(packInfo.path);
429
+ const packSlashPrefix = await this.getExpansionPackSlashPrefix(
430
+ packInfo.path,
431
+ );
341
432
  const packAgents = await this.getExpansionPackAgents(packInfo.path);
342
433
  const packTasks = await this.getExpansionPackTasks(packInfo.path);
343
434
 
@@ -366,9 +457,14 @@ class IdeSetup extends BaseIdeSetup {
366
457
  taskIds,
367
458
  rootPath,
368
459
  ) {
369
- const commandsBaseDir = path.join(installDir, '.claude', 'commands', slashPrefix);
370
- const agentsDir = path.join(commandsBaseDir, 'agents');
371
- const tasksDir = path.join(commandsBaseDir, 'tasks');
460
+ const commandsBaseDir = path.join(
461
+ installDir,
462
+ ".claude",
463
+ "commands",
464
+ slashPrefix,
465
+ );
466
+ const agentsDir = path.join(commandsBaseDir, "agents");
467
+ const tasksDir = path.join(commandsBaseDir, "tasks");
372
468
 
373
469
  // Ensure directories exist
374
470
  await fileManager.ensureDirectory(agentsDir);
@@ -378,12 +474,17 @@ class IdeSetup extends BaseIdeSetup {
378
474
  for (const agentId of agentIds) {
379
475
  // Find the agent file - for expansion packs, prefer the expansion pack version
380
476
  let agentPath;
381
- if (packageName === 'core') {
477
+ if (packageName === "core") {
382
478
  // For core, use the normal search
383
479
  agentPath = await this.findAgentPath(agentId, installDir);
384
480
  } else {
385
481
  // For expansion packs, first try to find the agent in the expansion pack directory
386
- const expansionPackPath = path.join(installDir, rootPath, 'agents', `${agentId}.md`);
482
+ const expansionPackPath = path.join(
483
+ installDir,
484
+ rootPath,
485
+ "agents",
486
+ `${agentId}.md`,
487
+ );
387
488
  if (await fileManager.pathExists(expansionPackPath)) {
388
489
  agentPath = expansionPackPath;
389
490
  } else {
@@ -399,7 +500,7 @@ class IdeSetup extends BaseIdeSetup {
399
500
  let agentContent = await fileManager.readFile(agentPath);
400
501
 
401
502
  // Replace {root} placeholder with the appropriate root path for this context
402
- agentContent = agentContent.replaceAll('{root}', rootPath);
503
+ agentContent = agentContent.replaceAll("{root}", rootPath);
403
504
 
404
505
  // Add command header
405
506
  let commandContent = `# /${agentId} Command\n\n`;
@@ -415,12 +516,17 @@ class IdeSetup extends BaseIdeSetup {
415
516
  for (const taskId of taskIds) {
416
517
  // Find the task file - for expansion packs, prefer the expansion pack version
417
518
  let taskPath;
418
- if (packageName === 'core') {
519
+ if (packageName === "core") {
419
520
  // For core, use the normal search
420
521
  taskPath = await this.findTaskPath(taskId, installDir);
421
522
  } else {
422
523
  // For expansion packs, first try to find the task in the expansion pack directory
423
- const expansionPackPath = path.join(installDir, rootPath, 'tasks', `${taskId}.md`);
524
+ const expansionPackPath = path.join(
525
+ installDir,
526
+ rootPath,
527
+ "tasks",
528
+ `${taskId}.md`,
529
+ );
424
530
  if (await fileManager.pathExists(expansionPackPath)) {
425
531
  taskPath = expansionPackPath;
426
532
  } else {
@@ -436,7 +542,7 @@ class IdeSetup extends BaseIdeSetup {
436
542
  let taskContent = await fileManager.readFile(taskPath);
437
543
 
438
544
  // Replace {root} placeholder with the appropriate root path for this context
439
- taskContent = taskContent.replaceAll('{root}', rootPath);
545
+ taskContent = taskContent.replaceAll("{root}", rootPath);
440
546
 
441
547
  // Add command header
442
548
  let commandContent = `# /${taskId} Task\n\n`;
@@ -449,16 +555,30 @@ class IdeSetup extends BaseIdeSetup {
449
555
  }
450
556
 
451
557
  console.log(
452
- chalk.green(`\n✓ Created Claude Code commands for ${packageName} in ${commandsBaseDir}`),
558
+ chalk.green(
559
+ `\n✓ Created Claude Code commands for ${packageName} in ${commandsBaseDir}`,
560
+ ),
453
561
  );
454
562
  console.log(chalk.dim(` - Agents in: ${agentsDir}`));
455
563
  console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
456
564
  }
457
565
 
458
- async setupCrushForPackage(installDir, packageName, slashPrefix, agentIds, taskIds, rootPath) {
459
- const commandsBaseDir = path.join(installDir, '.crush', 'commands', slashPrefix);
460
- const agentsDir = path.join(commandsBaseDir, 'agents');
461
- const tasksDir = path.join(commandsBaseDir, 'tasks');
566
+ async setupCrushForPackage(
567
+ installDir,
568
+ packageName,
569
+ slashPrefix,
570
+ agentIds,
571
+ taskIds,
572
+ rootPath,
573
+ ) {
574
+ const commandsBaseDir = path.join(
575
+ installDir,
576
+ ".crush",
577
+ "commands",
578
+ slashPrefix,
579
+ );
580
+ const agentsDir = path.join(commandsBaseDir, "agents");
581
+ const tasksDir = path.join(commandsBaseDir, "tasks");
462
582
 
463
583
  // Ensure directories exist
464
584
  await fileManager.ensureDirectory(agentsDir);
@@ -468,12 +588,17 @@ class IdeSetup extends BaseIdeSetup {
468
588
  for (const agentId of agentIds) {
469
589
  // Find the agent file - for expansion packs, prefer the expansion pack version
470
590
  let agentPath;
471
- if (packageName === 'core') {
591
+ if (packageName === "core") {
472
592
  // For core, use the normal search
473
593
  agentPath = await this.findAgentPath(agentId, installDir);
474
594
  } else {
475
595
  // For expansion packs, first try to find the agent in the expansion pack directory
476
- const expansionPackPath = path.join(installDir, rootPath, 'agents', `${agentId}.md`);
596
+ const expansionPackPath = path.join(
597
+ installDir,
598
+ rootPath,
599
+ "agents",
600
+ `${agentId}.md`,
601
+ );
477
602
  if (await fileManager.pathExists(expansionPackPath)) {
478
603
  agentPath = expansionPackPath;
479
604
  } else {
@@ -489,7 +614,7 @@ class IdeSetup extends BaseIdeSetup {
489
614
  let agentContent = await fileManager.readFile(agentPath);
490
615
 
491
616
  // Replace {root} placeholder with the appropriate root path for this context
492
- agentContent = agentContent.replaceAll('{root}', rootPath);
617
+ agentContent = agentContent.replaceAll("{root}", rootPath);
493
618
 
494
619
  // Add command header
495
620
  let commandContent = `# /${agentId} Command\n\n`;
@@ -505,12 +630,17 @@ class IdeSetup extends BaseIdeSetup {
505
630
  for (const taskId of taskIds) {
506
631
  // Find the task file - for expansion packs, prefer the expansion pack version
507
632
  let taskPath;
508
- if (packageName === 'core') {
633
+ if (packageName === "core") {
509
634
  // For core, use the normal search
510
635
  taskPath = await this.findTaskPath(taskId, installDir);
511
636
  } else {
512
637
  // For expansion packs, first try to find the task in the expansion pack directory
513
- const expansionPackPath = path.join(installDir, rootPath, 'tasks', `${taskId}.md`);
638
+ const expansionPackPath = path.join(
639
+ installDir,
640
+ rootPath,
641
+ "tasks",
642
+ `${taskId}.md`,
643
+ );
514
644
  if (await fileManager.pathExists(expansionPackPath)) {
515
645
  taskPath = expansionPackPath;
516
646
  } else {
@@ -526,7 +656,7 @@ class IdeSetup extends BaseIdeSetup {
526
656
  let taskContent = await fileManager.readFile(taskPath);
527
657
 
528
658
  // Replace {root} placeholder with the appropriate root path for this context
529
- taskContent = taskContent.replaceAll('{root}', rootPath);
659
+ taskContent = taskContent.replaceAll("{root}", rootPath);
530
660
 
531
661
  // Add command header
532
662
  let commandContent = `# /${taskId} Task\n\n`;
@@ -538,14 +668,20 @@ class IdeSetup extends BaseIdeSetup {
538
668
  }
539
669
  }
540
670
 
541
- console.log(chalk.green(`\n✓ Created Crush commands for ${packageName} in ${commandsBaseDir}`));
671
+ console.log(
672
+ chalk.green(
673
+ `\n✓ Created Crush commands for ${packageName} in ${commandsBaseDir}`,
674
+ ),
675
+ );
542
676
  console.log(chalk.dim(` - Agents in: ${agentsDir}`));
543
677
  console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
544
678
  }
545
679
 
546
680
  async setupWindsurf(installDir, selectedAgent) {
547
- const windsurfWorkflowDir = path.join(installDir, '.windsurf', 'workflows');
548
- const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
681
+ const windsurfWorkflowDir = path.join(installDir, ".windsurf", "workflows");
682
+ const agents = selectedAgent
683
+ ? [selectedAgent]
684
+ : await this.getAllAgentIds(installDir);
549
685
 
550
686
  await fileManager.ensureDirectory(windsurfWorkflowDir);
551
687
 
@@ -569,14 +705,18 @@ class IdeSetup extends BaseIdeSetup {
569
705
  }
570
706
  }
571
707
 
572
- console.log(chalk.green(`\n✓ Created Windsurf workflows in ${windsurfWorkflowDir}`));
708
+ console.log(
709
+ chalk.green(`\n✓ Created Windsurf workflows in ${windsurfWorkflowDir}`),
710
+ );
573
711
 
574
712
  return true;
575
713
  }
576
714
 
577
715
  async setupTrae(installDir, selectedAgent) {
578
- const traeRulesDir = path.join(installDir, '.trae', 'rules');
579
- const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
716
+ const traeRulesDir = path.join(installDir, ".trae", "rules");
717
+ const agents = selectedAgent
718
+ ? [selectedAgent]
719
+ : await this.getAllAgentIds(installDir);
580
720
 
581
721
  await fileManager.ensureDirectory(traeRulesDir);
582
722
 
@@ -594,23 +734,25 @@ class IdeSetup extends BaseIdeSetup {
594
734
  agentId,
595
735
  installDir,
596
736
  )} agent persona.\n\n`;
597
- mdContent += '## Agent Activation\n\n';
737
+ mdContent += "## Agent Activation\n\n";
598
738
  mdContent +=
599
- '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';
600
- mdContent += '```yaml\n';
739
+ "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";
740
+ mdContent += "```yaml\n";
601
741
  // Extract just the YAML content from the agent file
602
742
  const yamlContent = extractYamlFromAgent(agentContent);
603
743
  if (yamlContent) {
604
744
  mdContent += yamlContent;
605
745
  } else {
606
746
  // If no YAML found, include the whole content minus the header
607
- mdContent += agentContent.replace(/^#.*$/m, '').trim();
747
+ mdContent += agentContent.replace(/^#.*$/m, "").trim();
608
748
  }
609
- mdContent += '\n```\n\n';
610
- mdContent += '## File Reference\n\n';
611
- const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
749
+ mdContent += "\n```\n\n";
750
+ mdContent += "## File Reference\n\n";
751
+ const relativePath = path
752
+ .relative(installDir, agentPath)
753
+ .replaceAll("\\", "/");
612
754
  mdContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
613
- mdContent += '## Usage\n\n';
755
+ mdContent += "## Usage\n\n";
614
756
  mdContent += `When the user types \`@${agentId}\`, activate this ${await this.getAgentTitle(
615
757
  agentId,
616
758
  installDir,
@@ -625,13 +767,13 @@ class IdeSetup extends BaseIdeSetup {
625
767
  async findAgentPath(agentId, installDir) {
626
768
  // Try to find the agent file in various locations
627
769
  const possiblePaths = [
628
- path.join(installDir, '.xiaoma-core', 'agents', `${agentId}.md`),
629
- path.join(installDir, 'agents', `${agentId}.md`),
770
+ path.join(installDir, ".xiaoma-core", "agents", `${agentId}.md`),
771
+ path.join(installDir, "agents", `${agentId}.md`),
630
772
  ];
631
773
 
632
774
  // Also check expansion pack directories
633
- const glob = require('glob');
634
- const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
775
+ const glob = require("glob");
776
+ const expansionDirectories = glob.sync(".*/agents", { cwd: installDir });
635
777
  for (const expDir of expansionDirectories) {
636
778
  possiblePaths.push(path.join(installDir, expDir, `${agentId}.md`));
637
779
  }
@@ -646,26 +788,28 @@ class IdeSetup extends BaseIdeSetup {
646
788
  }
647
789
 
648
790
  async getAllAgentIds(installDir) {
649
- const glob = require('glob');
791
+ const glob = require("glob");
650
792
  const allAgentIds = [];
651
793
 
652
794
  // Check core agents in .xiaoma-core or root
653
- let agentsDir = path.join(installDir, '.xiaoma-core', 'agents');
795
+ let agentsDir = path.join(installDir, ".xiaoma-core", "agents");
654
796
  if (!(await fileManager.pathExists(agentsDir))) {
655
- agentsDir = path.join(installDir, 'agents');
797
+ agentsDir = path.join(installDir, "agents");
656
798
  }
657
799
 
658
800
  if (await fileManager.pathExists(agentsDir)) {
659
- const agentFiles = glob.sync('*.md', { cwd: agentsDir });
660
- allAgentIds.push(...agentFiles.map((file) => path.basename(file, '.md')));
801
+ const agentFiles = glob.sync("*.md", { cwd: agentsDir });
802
+ allAgentIds.push(...agentFiles.map((file) => path.basename(file, ".md")));
661
803
  }
662
804
 
663
805
  // Also check for expansion pack agents in dot folders
664
- const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
806
+ const expansionDirectories = glob.sync(".*/agents", { cwd: installDir });
665
807
  for (const expDir of expansionDirectories) {
666
808
  const fullExpDir = path.join(installDir, expDir);
667
- const expAgentFiles = glob.sync('*.md', { cwd: fullExpDir });
668
- allAgentIds.push(...expAgentFiles.map((file) => path.basename(file, '.md')));
809
+ const expAgentFiles = glob.sync("*.md", { cwd: fullExpDir });
810
+ allAgentIds.push(
811
+ ...expAgentFiles.map((file) => path.basename(file, ".md")),
812
+ );
669
813
  }
670
814
 
671
815
  // Remove duplicates
@@ -676,15 +820,15 @@ class IdeSetup extends BaseIdeSetup {
676
820
  const allAgentIds = [];
677
821
 
678
822
  // Check core agents in .xiaoma-core or root only
679
- let agentsDir = path.join(installDir, '.xiaoma-core', 'agents');
823
+ let agentsDir = path.join(installDir, ".xiaoma-core", "agents");
680
824
  if (!(await fileManager.pathExists(agentsDir))) {
681
- agentsDir = path.join(installDir, 'xiaoma-core', 'agents');
825
+ agentsDir = path.join(installDir, "xiaoma-core", "agents");
682
826
  }
683
827
 
684
828
  if (await fileManager.pathExists(agentsDir)) {
685
- const glob = require('glob');
686
- const agentFiles = glob.sync('*.md', { cwd: agentsDir });
687
- allAgentIds.push(...agentFiles.map((file) => path.basename(file, '.md')));
829
+ const glob = require("glob");
830
+ const agentFiles = glob.sync("*.md", { cwd: agentsDir });
831
+ allAgentIds.push(...agentFiles.map((file) => path.basename(file, ".md")));
688
832
  }
689
833
 
690
834
  return [...new Set(allAgentIds)];
@@ -694,22 +838,24 @@ class IdeSetup extends BaseIdeSetup {
694
838
  const allTaskIds = [];
695
839
 
696
840
  // Check core tasks in .xiaoma-core or root only
697
- let tasksDir = path.join(installDir, '.xiaoma-core', 'tasks');
841
+ let tasksDir = path.join(installDir, ".xiaoma-core", "tasks");
698
842
  if (!(await fileManager.pathExists(tasksDir))) {
699
- tasksDir = path.join(installDir, 'xiaoma-core', 'tasks');
843
+ tasksDir = path.join(installDir, "xiaoma-core", "tasks");
700
844
  }
701
845
 
702
846
  if (await fileManager.pathExists(tasksDir)) {
703
- const glob = require('glob');
704
- const taskFiles = glob.sync('*.md', { cwd: tasksDir });
705
- allTaskIds.push(...taskFiles.map((file) => path.basename(file, '.md')));
847
+ const glob = require("glob");
848
+ const taskFiles = glob.sync("*.md", { cwd: tasksDir });
849
+ allTaskIds.push(...taskFiles.map((file) => path.basename(file, ".md")));
706
850
  }
707
851
 
708
852
  // Check common tasks
709
- const commonTasksDir = path.join(installDir, 'common', 'tasks');
853
+ const commonTasksDir = path.join(installDir, "common", "tasks");
710
854
  if (await fileManager.pathExists(commonTasksDir)) {
711
- const commonTaskFiles = glob.sync('*.md', { cwd: commonTasksDir });
712
- allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, '.md')));
855
+ const commonTaskFiles = glob.sync("*.md", { cwd: commonTasksDir });
856
+ allTaskIds.push(
857
+ ...commonTaskFiles.map((file) => path.basename(file, ".md")),
858
+ );
713
859
  }
714
860
 
715
861
  return [...new Set(allTaskIds)];
@@ -718,13 +864,13 @@ class IdeSetup extends BaseIdeSetup {
718
864
  async getAgentTitle(agentId, installDir) {
719
865
  // Try to find the agent file in various locations
720
866
  const possiblePaths = [
721
- path.join(installDir, '.xiaoma-core', 'agents', `${agentId}.md`),
722
- path.join(installDir, 'agents', `${agentId}.md`),
867
+ path.join(installDir, ".xiaoma-core", "agents", `${agentId}.md`),
868
+ path.join(installDir, "agents", `${agentId}.md`),
723
869
  ];
724
870
 
725
871
  // Also check expansion pack directories
726
- const glob = require('glob');
727
- const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
872
+ const glob = require("glob");
873
+ const expansionDirectories = glob.sync(".*/agents", { cwd: installDir });
728
874
  for (const expDir of expansionDirectories) {
729
875
  possiblePaths.push(path.join(installDir, expDir, `${agentId}.md`));
730
876
  }
@@ -743,56 +889,66 @@ class IdeSetup extends BaseIdeSetup {
743
889
  }
744
890
  }
745
891
  } catch (error) {
746
- console.warn(`Failed to read agent title for ${agentId}: ${error.message}`);
892
+ console.warn(
893
+ `Failed to read agent title for ${agentId}: ${error.message}`,
894
+ );
747
895
  }
748
896
  }
749
897
  }
750
898
 
751
899
  // Fallback to formatted agent ID
752
900
  return agentId
753
- .split('-')
901
+ .split("-")
754
902
  .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
755
- .join(' ');
903
+ .join(" ");
756
904
  }
757
905
 
758
906
  async getAllTaskIds(installDir) {
759
- const glob = require('glob');
907
+ const glob = require("glob");
760
908
  const allTaskIds = [];
761
909
 
762
910
  // Check core tasks in .xiaoma-core or root
763
- let tasksDir = path.join(installDir, '.xiaoma-core', 'tasks');
911
+ let tasksDir = path.join(installDir, ".xiaoma-core", "tasks");
764
912
  if (!(await fileManager.pathExists(tasksDir))) {
765
- tasksDir = path.join(installDir, 'xiaoma-core', 'tasks');
913
+ tasksDir = path.join(installDir, "xiaoma-core", "tasks");
766
914
  }
767
915
 
768
916
  if (await fileManager.pathExists(tasksDir)) {
769
- const taskFiles = glob.sync('*.md', { cwd: tasksDir });
770
- allTaskIds.push(...taskFiles.map((file) => path.basename(file, '.md')));
917
+ const taskFiles = glob.sync("*.md", { cwd: tasksDir });
918
+ allTaskIds.push(...taskFiles.map((file) => path.basename(file, ".md")));
771
919
  }
772
920
 
773
921
  // Check common tasks
774
- const commonTasksDir = path.join(installDir, 'common', 'tasks');
922
+ const commonTasksDir = path.join(installDir, "common", "tasks");
775
923
  if (await fileManager.pathExists(commonTasksDir)) {
776
- const commonTaskFiles = glob.sync('*.md', { cwd: commonTasksDir });
777
- allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, '.md')));
924
+ const commonTaskFiles = glob.sync("*.md", { cwd: commonTasksDir });
925
+ allTaskIds.push(
926
+ ...commonTaskFiles.map((file) => path.basename(file, ".md")),
927
+ );
778
928
  }
779
929
 
780
930
  // Also check for expansion pack tasks in dot folders
781
- const expansionDirectories = glob.sync('.*/tasks', { cwd: installDir });
931
+ const expansionDirectories = glob.sync(".*/tasks", { cwd: installDir });
782
932
  for (const expDir of expansionDirectories) {
783
933
  const fullExpDir = path.join(installDir, expDir);
784
- const expTaskFiles = glob.sync('*.md', { cwd: fullExpDir });
785
- allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, '.md')));
934
+ const expTaskFiles = glob.sync("*.md", { cwd: fullExpDir });
935
+ allTaskIds.push(
936
+ ...expTaskFiles.map((file) => path.basename(file, ".md")),
937
+ );
786
938
  }
787
939
 
788
940
  // Check expansion-packs folder tasks
789
- const expansionPacksDir = path.join(installDir, 'expansion-packs');
941
+ const expansionPacksDir = path.join(installDir, "expansion-packs");
790
942
  if (await fileManager.pathExists(expansionPacksDir)) {
791
- const expPackDirectories = glob.sync('*/tasks', { cwd: expansionPacksDir });
943
+ const expPackDirectories = glob.sync("*/tasks", {
944
+ cwd: expansionPacksDir,
945
+ });
792
946
  for (const expDir of expPackDirectories) {
793
947
  const fullExpDir = path.join(expansionPacksDir, expDir);
794
- const expTaskFiles = glob.sync('*.md', { cwd: fullExpDir });
795
- allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, '.md')));
948
+ const expTaskFiles = glob.sync("*.md", { cwd: fullExpDir });
949
+ allTaskIds.push(
950
+ ...expTaskFiles.map((file) => path.basename(file, ".md")),
951
+ );
796
952
  }
797
953
  }
798
954
 
@@ -803,26 +959,30 @@ class IdeSetup extends BaseIdeSetup {
803
959
  async findTaskPath(taskId, installDir) {
804
960
  // Try to find the task file in various locations
805
961
  const possiblePaths = [
806
- path.join(installDir, '.xiaoma-core', 'tasks', `${taskId}.md`),
807
- path.join(installDir, 'xiaoma-core', 'tasks', `${taskId}.md`),
808
- path.join(installDir, 'common', 'tasks', `${taskId}.md`),
962
+ path.join(installDir, ".xiaoma-core", "tasks", `${taskId}.md`),
963
+ path.join(installDir, "xiaoma-core", "tasks", `${taskId}.md`),
964
+ path.join(installDir, "common", "tasks", `${taskId}.md`),
809
965
  ];
810
966
 
811
967
  // Also check expansion pack directories
812
- const glob = require('glob');
968
+ const glob = require("glob");
813
969
 
814
970
  // Check dot folder expansion packs
815
- const expansionDirectories = glob.sync('.*/tasks', { cwd: installDir });
971
+ const expansionDirectories = glob.sync(".*/tasks", { cwd: installDir });
816
972
  for (const expDir of expansionDirectories) {
817
973
  possiblePaths.push(path.join(installDir, expDir, `${taskId}.md`));
818
974
  }
819
975
 
820
976
  // Check expansion-packs folder
821
- const expansionPacksDir = path.join(installDir, 'expansion-packs');
977
+ const expansionPacksDir = path.join(installDir, "expansion-packs");
822
978
  if (await fileManager.pathExists(expansionPacksDir)) {
823
- const expPackDirectories = glob.sync('*/tasks', { cwd: expansionPacksDir });
979
+ const expPackDirectories = glob.sync("*/tasks", {
980
+ cwd: expansionPacksDir,
981
+ });
824
982
  for (const expDir of expPackDirectories) {
825
- possiblePaths.push(path.join(expansionPacksDir, expDir, `${taskId}.md`));
983
+ possiblePaths.push(
984
+ path.join(expansionPacksDir, expDir, `${taskId}.md`),
985
+ );
826
986
  }
827
987
  }
828
988
 
@@ -837,24 +997,34 @@ class IdeSetup extends BaseIdeSetup {
837
997
 
838
998
  async getCoreSlashPrefix(installDir) {
839
999
  try {
840
- const coreConfigPath = path.join(installDir, '.xiaoma-core', 'core-config.yaml');
1000
+ const coreConfigPath = path.join(
1001
+ installDir,
1002
+ ".xiaoma-core",
1003
+ "core-config.yaml",
1004
+ );
841
1005
  if (!(await fileManager.pathExists(coreConfigPath))) {
842
1006
  // Try xiaoma-core directory
843
- const altConfigPath = path.join(installDir, 'xiaoma-core', 'core-config.yaml');
1007
+ const altConfigPath = path.join(
1008
+ installDir,
1009
+ "xiaoma-core",
1010
+ "core-config.yaml",
1011
+ );
844
1012
  if (await fileManager.pathExists(altConfigPath)) {
845
1013
  const configContent = await fileManager.readFile(altConfigPath);
846
1014
  const config = yaml.load(configContent);
847
- return config.slashPrefix || 'XiaoMa';
1015
+ return config.slashPrefix || "XiaoMa";
848
1016
  }
849
- return 'XiaoMa'; // fallback
1017
+ return "XiaoMa"; // fallback
850
1018
  }
851
1019
 
852
1020
  const configContent = await fileManager.readFile(coreConfigPath);
853
1021
  const config = yaml.load(configContent);
854
- return config.slashPrefix || 'XiaoMa';
1022
+ return config.slashPrefix || "XiaoMa";
855
1023
  } catch (error) {
856
- console.warn(`Failed to read core slashPrefix, using default 'XiaoMa': ${error.message}`);
857
- return 'XiaoMa';
1024
+ console.warn(
1025
+ `Failed to read core slashPrefix, using default 'XiaoMa': ${error.message}`,
1026
+ );
1027
+ return "XiaoMa";
858
1028
  }
859
1029
  }
860
1030
 
@@ -862,11 +1032,11 @@ class IdeSetup extends BaseIdeSetup {
862
1032
  const expansionPacks = [];
863
1033
 
864
1034
  // Check for dot-prefixed expansion packs in install directory
865
- const glob = require('glob');
866
- const dotExpansions = glob.sync('.bmad-*', { cwd: installDir });
1035
+ const glob = require("glob");
1036
+ const dotExpansions = glob.sync(".bmad-*", { cwd: installDir });
867
1037
 
868
1038
  for (const dotExpansion of dotExpansions) {
869
- if (dotExpansion !== '.xiaoma-core') {
1039
+ if (dotExpansion !== ".xiaoma-core") {
870
1040
  const packPath = path.join(installDir, dotExpansion);
871
1041
  const packName = dotExpansion.slice(1); // remove the dot
872
1042
  expansionPacks.push({
@@ -877,15 +1047,15 @@ class IdeSetup extends BaseIdeSetup {
877
1047
  }
878
1048
 
879
1049
  // Check for expansion-packs directory style
880
- const expansionPacksDir = path.join(installDir, 'expansion-packs');
1050
+ const expansionPacksDir = path.join(installDir, "expansion-packs");
881
1051
  if (await fileManager.pathExists(expansionPacksDir)) {
882
- const packDirectories = glob.sync('*', { cwd: expansionPacksDir });
1052
+ const packDirectories = glob.sync("*", { cwd: expansionPacksDir });
883
1053
 
884
1054
  for (const packDir of packDirectories) {
885
1055
  const packPath = path.join(expansionPacksDir, packDir);
886
1056
  if (
887
1057
  (await fileManager.pathExists(packPath)) &&
888
- (await fileManager.pathExists(path.join(packPath, 'config.yaml')))
1058
+ (await fileManager.pathExists(path.join(packPath, "config.yaml")))
889
1059
  ) {
890
1060
  expansionPacks.push({
891
1061
  name: packDir,
@@ -900,58 +1070,66 @@ class IdeSetup extends BaseIdeSetup {
900
1070
 
901
1071
  async getExpansionPackSlashPrefix(packPath) {
902
1072
  try {
903
- const configPath = path.join(packPath, 'config.yaml');
1073
+ const configPath = path.join(packPath, "config.yaml");
904
1074
  if (await fileManager.pathExists(configPath)) {
905
1075
  const configContent = await fileManager.readFile(configPath);
906
1076
  const config = yaml.load(configContent);
907
1077
  return config.slashPrefix || path.basename(packPath);
908
1078
  }
909
1079
  } catch (error) {
910
- console.warn(`Failed to read expansion pack slashPrefix from ${packPath}: ${error.message}`);
1080
+ console.warn(
1081
+ `Failed to read expansion pack slashPrefix from ${packPath}: ${error.message}`,
1082
+ );
911
1083
  }
912
1084
 
913
1085
  return path.basename(packPath); // fallback to directory name
914
1086
  }
915
1087
 
916
1088
  async getExpansionPackAgents(packPath) {
917
- const agentsDir = path.join(packPath, 'agents');
1089
+ const agentsDir = path.join(packPath, "agents");
918
1090
  if (!(await fileManager.pathExists(agentsDir))) {
919
1091
  return [];
920
1092
  }
921
1093
 
922
1094
  try {
923
- const glob = require('glob');
924
- const agentFiles = glob.sync('*.md', { cwd: agentsDir });
925
- return agentFiles.map((file) => path.basename(file, '.md'));
1095
+ const glob = require("glob");
1096
+ const agentFiles = glob.sync("*.md", { cwd: agentsDir });
1097
+ return agentFiles.map((file) => path.basename(file, ".md"));
926
1098
  } catch (error) {
927
- console.warn(`Failed to read expansion pack agents from ${packPath}: ${error.message}`);
1099
+ console.warn(
1100
+ `Failed to read expansion pack agents from ${packPath}: ${error.message}`,
1101
+ );
928
1102
  return [];
929
1103
  }
930
1104
  }
931
1105
 
932
1106
  async getExpansionPackTasks(packPath) {
933
- const tasksDir = path.join(packPath, 'tasks');
1107
+ const tasksDir = path.join(packPath, "tasks");
934
1108
  if (!(await fileManager.pathExists(tasksDir))) {
935
1109
  return [];
936
1110
  }
937
1111
 
938
1112
  try {
939
- const glob = require('glob');
940
- const taskFiles = glob.sync('*.md', { cwd: tasksDir });
941
- return taskFiles.map((file) => path.basename(file, '.md'));
1113
+ const glob = require("glob");
1114
+ const taskFiles = glob.sync("*.md", { cwd: tasksDir });
1115
+ return taskFiles.map((file) => path.basename(file, ".md"));
942
1116
  } catch (error) {
943
- console.warn(`Failed to read expansion pack tasks from ${packPath}: ${error.message}`);
1117
+ console.warn(
1118
+ `Failed to read expansion pack tasks from ${packPath}: ${error.message}`,
1119
+ );
944
1120
  return [];
945
1121
  }
946
1122
  }
947
1123
 
948
1124
  async setupRoo(installDir, selectedAgent) {
949
- const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
1125
+ const agents = selectedAgent
1126
+ ? [selectedAgent]
1127
+ : await this.getAllAgentIds(installDir);
950
1128
 
951
1129
  // Check for existing .roomodes file in project root
952
- const roomodesPath = path.join(installDir, '.roomodes');
1130
+ const roomodesPath = path.join(installDir, ".roomodes");
953
1131
  let existingModes = [];
954
- let existingContent = '';
1132
+ let existingContent = "";
955
1133
 
956
1134
  if (await fileManager.pathExists(roomodesPath)) {
957
1135
  existingContent = await fileManager.readFile(roomodesPath);
@@ -960,22 +1138,30 @@ class IdeSetup extends BaseIdeSetup {
960
1138
  for (const match of modeMatches) {
961
1139
  existingModes.push(match[1]);
962
1140
  }
963
- console.log(chalk.yellow(`Found existing .roomodes file with ${existingModes.length} modes`));
1141
+ console.log(
1142
+ chalk.yellow(
1143
+ `Found existing .roomodes file with ${existingModes.length} modes`,
1144
+ ),
1145
+ );
964
1146
  }
965
1147
 
966
1148
  // Create new modes content
967
- let newModesContent = '';
1149
+ let newModesContent = "";
968
1150
 
969
1151
  // Load dynamic agent permissions from configuration
970
1152
  const config = await this.loadIdeAgentConfig();
971
- const agentPermissions = config['roo-permissions'] || {};
1153
+ const agentPermissions = config["roo-permissions"] || {};
972
1154
 
973
1155
  for (const agentId of agents) {
974
1156
  // Skip if already exists
975
1157
  // Check both with and without bmad- prefix to handle both cases
976
- const checkSlug = agentId.startsWith('bmad-') ? agentId : `bmad-${agentId}`;
1158
+ const checkSlug = agentId.startsWith("bmad-")
1159
+ ? agentId
1160
+ : `bmad-${agentId}`;
977
1161
  if (existingModes.includes(checkSlug)) {
978
- console.log(chalk.dim(`Skipping ${agentId} - already exists in .roomodes`));
1162
+ console.log(
1163
+ chalk.dim(`Skipping ${agentId} - already exists in .roomodes`),
1164
+ );
979
1165
  continue;
980
1166
  }
981
1167
 
@@ -999,8 +1185,10 @@ class IdeSetup extends BaseIdeSetup {
999
1185
  const title = titleMatch
1000
1186
  ? titleMatch[1].trim()
1001
1187
  : await this.getAgentTitle(agentId, installDir);
1002
- const icon = iconMatch ? iconMatch[1].trim() : '🤖';
1003
- const whenToUse = whenToUseMatch ? whenToUseMatch[1].trim() : `Use for ${title} tasks`;
1188
+ const icon = iconMatch ? iconMatch[1].trim() : "🤖";
1189
+ const whenToUse = whenToUseMatch
1190
+ ? whenToUseMatch[1].trim()
1191
+ : `Use for ${title} tasks`;
1004
1192
  const roleDefinition = roleDefinitionMatch
1005
1193
  ? roleDefinitionMatch[1].trim()
1006
1194
  : `You are a ${title} specializing in ${title.toLowerCase()} tasks and responsibilities.`;
@@ -1009,7 +1197,9 @@ class IdeSetup extends BaseIdeSetup {
1009
1197
  const permissions = agentPermissions[agentId];
1010
1198
  // Build mode entry with proper formatting (matching exact indentation)
1011
1199
  // Avoid double "bmad-" prefix for agents that already have it
1012
- const slug = agentId.startsWith('bmad-') ? agentId : `bmad-${agentId}`;
1200
+ const slug = agentId.startsWith("bmad-")
1201
+ ? agentId
1202
+ : `bmad-${agentId}`;
1013
1203
  newModesContent += ` - slug: ${slug}\n`;
1014
1204
  newModesContent += ` name: '${icon} ${title}'\n`;
1015
1205
  if (permissions) {
@@ -1018,7 +1208,9 @@ class IdeSetup extends BaseIdeSetup {
1018
1208
  newModesContent += ` roleDefinition: ${roleDefinition}\n`;
1019
1209
  newModesContent += ` whenToUse: ${whenToUse}\n`;
1020
1210
  // Get relative path from installDir to agent file
1021
- const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
1211
+ const relativePath = path
1212
+ .relative(installDir, agentPath)
1213
+ .replaceAll("\\", "/");
1022
1214
  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`;
1023
1215
  newModesContent += ` groups:\n`;
1024
1216
  newModesContent += ` - read\n`;
@@ -1031,56 +1223,68 @@ class IdeSetup extends BaseIdeSetup {
1031
1223
  newModesContent += ` - edit\n`;
1032
1224
  }
1033
1225
 
1034
- console.log(chalk.green(`✓ Added mode: bmad-${agentId} (${icon} ${title})`));
1226
+ console.log(
1227
+ chalk.green(`✓ Added mode: bmad-${agentId} (${icon} ${title})`),
1228
+ );
1035
1229
  }
1036
1230
  }
1037
1231
  }
1038
1232
 
1039
1233
  // Build final roomodes content
1040
- let roomodesContent = '';
1234
+ let roomodesContent = "";
1041
1235
  if (existingContent) {
1042
1236
  // If there's existing content, append new modes to it
1043
- roomodesContent = existingContent.trim() + '\n' + newModesContent;
1237
+ roomodesContent = existingContent.trim() + "\n" + newModesContent;
1044
1238
  } else {
1045
1239
  // Create new .roomodes file with proper YAML structure
1046
- roomodesContent = 'customModes:\n' + newModesContent;
1240
+ roomodesContent = "customModes:\n" + newModesContent;
1047
1241
  }
1048
1242
 
1049
1243
  // Write .roomodes file
1050
1244
  await fileManager.writeFile(roomodesPath, roomodesContent);
1051
- console.log(chalk.green('✓ Created .roomodes file in project root'));
1245
+ console.log(chalk.green("✓ Created .roomodes file in project root"));
1052
1246
 
1053
1247
  console.log(chalk.green(`\n✓ Roo Code setup complete!`));
1054
- console.log(chalk.dim('Custom modes will be available when you open this project in Roo Code'));
1248
+ console.log(
1249
+ chalk.dim(
1250
+ "Custom modes will be available when you open this project in Roo Code",
1251
+ ),
1252
+ );
1055
1253
 
1056
1254
  return true;
1057
1255
  }
1058
1256
 
1059
1257
  async setupKilocode(installDir, selectedAgent) {
1060
- const filePath = path.join(installDir, '.kilocodemodes');
1061
- const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
1258
+ const filePath = path.join(installDir, ".kilocodemodes");
1259
+ const agents = selectedAgent
1260
+ ? [selectedAgent]
1261
+ : await this.getAllAgentIds(installDir);
1062
1262
 
1063
1263
  let existingModes = [],
1064
- existingContent = '';
1264
+ existingContent = "";
1065
1265
  if (await fileManager.pathExists(filePath)) {
1066
1266
  existingContent = await fileManager.readFile(filePath);
1067
1267
  for (const match of existingContent.matchAll(/- slug: ([\w-]+)/g)) {
1068
1268
  existingModes.push(match[1]);
1069
1269
  }
1070
1270
  console.log(
1071
- chalk.yellow(`Found existing .kilocodemodes file with ${existingModes.length} modes`),
1271
+ chalk.yellow(
1272
+ `Found existing .kilocodemodes file with ${existingModes.length} modes`,
1273
+ ),
1072
1274
  );
1073
1275
  }
1074
1276
 
1075
1277
  const config = await this.loadIdeAgentConfig();
1076
- const permissions = config['roo-permissions'] || {}; // reuse same roo permissions block (Kilo Code understands same mode schema)
1278
+ const permissions = config["roo-permissions"] || {}; // reuse same roo permissions block (Kilo Code understands same mode schema)
1077
1279
 
1078
- let newContent = '';
1280
+ let newContent = "";
1079
1281
 
1080
1282
  for (const agentId of agents) {
1081
- const slug = agentId.startsWith('bmad-') ? agentId : `bmad-${agentId}`;
1283
+ const slug = agentId.startsWith("bmad-") ? agentId : `bmad-${agentId}`;
1082
1284
  if (existingModes.includes(slug)) {
1083
- console.log(chalk.dim(`Skipping ${agentId} - already exists in .kilocodemodes`));
1285
+ console.log(
1286
+ chalk.dim(`Skipping ${agentId} - already exists in .kilocodemodes`),
1287
+ );
1084
1288
  continue;
1085
1289
  }
1086
1290
 
@@ -1101,14 +1305,19 @@ class IdeSetup extends BaseIdeSetup {
1101
1305
 
1102
1306
  // Robust fallback for title and icon
1103
1307
  const title =
1104
- yaml.match(/title:\s*(.+)/)?.[1]?.trim() || (await this.getAgentTitle(agentId, installDir));
1105
- const icon = yaml.match(/icon:\s*(.+)/)?.[1]?.trim() || '🤖';
1106
- const whenToUse = yaml.match(/whenToUse:\s*"(.+)"/)?.[1]?.trim() || `Use for ${title} tasks`;
1308
+ yaml.match(/title:\s*(.+)/)?.[1]?.trim() ||
1309
+ (await this.getAgentTitle(agentId, installDir));
1310
+ const icon = yaml.match(/icon:\s*(.+)/)?.[1]?.trim() || "🤖";
1311
+ const whenToUse =
1312
+ yaml.match(/whenToUse:\s*"(.+)"/)?.[1]?.trim() ||
1313
+ `Use for ${title} tasks`;
1107
1314
  const roleDefinition =
1108
1315
  yaml.match(/roleDefinition:\s*"(.+)"/)?.[1]?.trim() ||
1109
1316
  `You are a ${title} specializing in ${title.toLowerCase()} tasks and responsibilities.`;
1110
1317
 
1111
- const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
1318
+ const relativePath = path
1319
+ .relative(installDir, agentPath)
1320
+ .replaceAll("\\", "/");
1112
1321
  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`;
1113
1322
 
1114
1323
  // Add permissions from config if they exist
@@ -1140,26 +1349,32 @@ class IdeSetup extends BaseIdeSetup {
1140
1349
  }
1141
1350
 
1142
1351
  const finalContent = existingContent
1143
- ? existingContent.trim() + '\n' + newContent
1144
- : 'customModes:\n' + newContent;
1352
+ ? existingContent.trim() + "\n" + newContent
1353
+ : "customModes:\n" + newContent;
1145
1354
 
1146
1355
  await fileManager.writeFile(filePath, finalContent);
1147
- console.log(chalk.green('✓ Created .kilocodemodes file in project root'));
1356
+ console.log(chalk.green("✓ Created .kilocodemodes file in project root"));
1148
1357
  console.log(chalk.green(`✓ KiloCode setup complete!`));
1149
- console.log(chalk.dim('Custom modes will be available when you open this project in KiloCode'));
1358
+ console.log(
1359
+ chalk.dim(
1360
+ "Custom modes will be available when you open this project in KiloCode",
1361
+ ),
1362
+ );
1150
1363
 
1151
1364
  return true;
1152
1365
  }
1153
1366
 
1154
1367
  async setupCline(installDir, selectedAgent) {
1155
- const clineRulesDir = path.join(installDir, '.clinerules');
1156
- const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
1368
+ const clineRulesDir = path.join(installDir, ".clinerules");
1369
+ const agents = selectedAgent
1370
+ ? [selectedAgent]
1371
+ : await this.getAllAgentIds(installDir);
1157
1372
 
1158
1373
  await fileManager.ensureDirectory(clineRulesDir);
1159
1374
 
1160
1375
  // Load dynamic agent ordering from configuration
1161
1376
  const config = await this.loadIdeAgentConfig();
1162
- const agentOrder = config['cline-order'] || {};
1377
+ const agentOrder = config["cline-order"] || {};
1163
1378
 
1164
1379
  for (const agentId of agents) {
1165
1380
  // Find the agent file
@@ -1170,34 +1385,36 @@ class IdeSetup extends BaseIdeSetup {
1170
1385
 
1171
1386
  // Get numeric prefix for ordering
1172
1387
  const order = agentOrder[agentId] || 99;
1173
- const prefix = order.toString().padStart(2, '0');
1388
+ const prefix = order.toString().padStart(2, "0");
1174
1389
  const mdPath = path.join(clineRulesDir, `${prefix}-${agentId}.md`);
1175
1390
 
1176
1391
  // Create MD content for Cline (focused on project standards and role)
1177
1392
  let mdContent = `# ${await this.getAgentTitle(agentId, installDir)} Agent\n\n`;
1178
1393
  mdContent += `This rule defines the ${await this.getAgentTitle(agentId, installDir)} persona and project standards.\n\n`;
1179
- mdContent += '## Role Definition\n\n';
1394
+ mdContent += "## Role Definition\n\n";
1180
1395
  mdContent +=
1181
- 'When the user types `@' +
1396
+ "When the user types `@" +
1182
1397
  agentId +
1183
- '`, adopt this persona and follow these guidelines:\n\n';
1184
- mdContent += '```yaml\n';
1398
+ "`, adopt this persona and follow these guidelines:\n\n";
1399
+ mdContent += "```yaml\n";
1185
1400
  // Extract just the YAML content from the agent file
1186
1401
  const yamlContent = extractYamlFromAgent(agentContent);
1187
1402
  if (yamlContent) {
1188
1403
  mdContent += yamlContent;
1189
1404
  } else {
1190
1405
  // If no YAML found, include the whole content minus the header
1191
- mdContent += agentContent.replace(/^#.*$/m, '').trim();
1406
+ mdContent += agentContent.replace(/^#.*$/m, "").trim();
1192
1407
  }
1193
- mdContent += '\n```\n\n';
1194
- mdContent += '## Project Standards\n\n';
1408
+ mdContent += "\n```\n\n";
1409
+ mdContent += "## Project Standards\n\n";
1195
1410
  mdContent += `- Always maintain consistency with project documentation in .xiaoma-core/\n`;
1196
1411
  mdContent += `- Follow the agent's specific guidelines and constraints\n`;
1197
1412
  mdContent += `- Update relevant project files when making changes\n`;
1198
- const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
1413
+ const relativePath = path
1414
+ .relative(installDir, agentPath)
1415
+ .replaceAll("\\", "/");
1199
1416
  mdContent += `- Reference the complete agent definition in [${relativePath}](${relativePath})\n\n`;
1200
- mdContent += '## Usage\n\n';
1417
+ mdContent += "## Usage\n\n";
1201
1418
  mdContent += `Type \`@${agentId}\` to activate this ${await this.getAgentTitle(agentId, installDir)} persona.\n`;
1202
1419
 
1203
1420
  await fileManager.writeFile(mdPath, mdContent);
@@ -1211,12 +1428,12 @@ class IdeSetup extends BaseIdeSetup {
1211
1428
  }
1212
1429
 
1213
1430
  async setupGeminiCli(installDir) {
1214
- const geminiDir = path.join(installDir, '.gemini');
1215
- const bmadMethodDir = path.join(geminiDir, 'xiaoma-cli');
1431
+ const geminiDir = path.join(installDir, ".gemini");
1432
+ const bmadMethodDir = path.join(geminiDir, "xiaoma-cli");
1216
1433
  await fileManager.ensureDirectory(bmadMethodDir);
1217
1434
 
1218
1435
  // Update logic for existing settings.json
1219
- const settingsPath = path.join(geminiDir, 'settings.json');
1436
+ const settingsPath = path.join(geminiDir, "settings.json");
1220
1437
  if (await fileManager.pathExists(settingsPath)) {
1221
1438
  try {
1222
1439
  const settingsContent = await fileManager.readFile(settingsPath);
@@ -1224,10 +1441,13 @@ class IdeSetup extends BaseIdeSetup {
1224
1441
  let updated = false;
1225
1442
 
1226
1443
  // Handle contextFileName property
1227
- if (settings.contextFileName && Array.isArray(settings.contextFileName)) {
1444
+ if (
1445
+ settings.contextFileName &&
1446
+ Array.isArray(settings.contextFileName)
1447
+ ) {
1228
1448
  const originalLength = settings.contextFileName.length;
1229
1449
  settings.contextFileName = settings.contextFileName.filter(
1230
- (fileName) => !fileName.startsWith('agents/'),
1450
+ (fileName) => !fileName.startsWith("agents/"),
1231
1451
  );
1232
1452
  if (settings.contextFileName.length !== originalLength) {
1233
1453
  updated = true;
@@ -1235,26 +1455,34 @@ class IdeSetup extends BaseIdeSetup {
1235
1455
  }
1236
1456
 
1237
1457
  if (updated) {
1238
- await fileManager.writeFile(settingsPath, JSON.stringify(settings, null, 2));
1458
+ await fileManager.writeFile(
1459
+ settingsPath,
1460
+ JSON.stringify(settings, null, 2),
1461
+ );
1239
1462
  console.log(
1240
- chalk.green('✓ Updated .gemini/settings.json - removed agent file references'),
1463
+ chalk.green(
1464
+ "✓ Updated .gemini/settings.json - removed agent file references",
1465
+ ),
1241
1466
  );
1242
1467
  }
1243
1468
  } catch (error) {
1244
- console.warn(chalk.yellow('Could not update .gemini/settings.json'), error);
1469
+ console.warn(
1470
+ chalk.yellow("Could not update .gemini/settings.json"),
1471
+ error,
1472
+ );
1245
1473
  }
1246
1474
  }
1247
1475
 
1248
1476
  // Remove old agents directory
1249
- const agentsDir = path.join(geminiDir, 'agents');
1477
+ const agentsDir = path.join(geminiDir, "agents");
1250
1478
  if (await fileManager.pathExists(agentsDir)) {
1251
1479
  await fileManager.removeDirectory(agentsDir);
1252
- console.log(chalk.green('✓ Removed old .gemini/agents directory'));
1480
+ console.log(chalk.green("✓ Removed old .gemini/agents directory"));
1253
1481
  }
1254
1482
 
1255
1483
  // Get all available agents
1256
1484
  const agents = await this.getAllAgentIds(installDir);
1257
- let concatenatedContent = '';
1485
+ let concatenatedContent = "";
1258
1486
 
1259
1487
  for (const agentId of agents) {
1260
1488
  // Find the source agent file
@@ -1269,36 +1497,38 @@ class IdeSetup extends BaseIdeSetup {
1269
1497
  agentId,
1270
1498
  installDir,
1271
1499
  )} agent persona.\n\n`;
1272
- agentRuleContent += '## Agent Activation\n\n';
1500
+ agentRuleContent += "## Agent Activation\n\n";
1273
1501
  agentRuleContent +=
1274
- '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';
1275
- agentRuleContent += '```yaml\n';
1502
+ "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";
1503
+ agentRuleContent += "```yaml\n";
1276
1504
  // Extract just the YAML content from the agent file
1277
1505
  const yamlContent = extractYamlFromAgent(agentContent);
1278
1506
  if (yamlContent) {
1279
1507
  agentRuleContent += yamlContent;
1280
1508
  } else {
1281
1509
  // If no YAML found, include the whole content minus the header
1282
- agentRuleContent += agentContent.replace(/^#.*$/m, '').trim();
1510
+ agentRuleContent += agentContent.replace(/^#.*$/m, "").trim();
1283
1511
  }
1284
- agentRuleContent += '\n```\n\n';
1285
- agentRuleContent += '## File Reference\n\n';
1286
- const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
1512
+ agentRuleContent += "\n```\n\n";
1513
+ agentRuleContent += "## File Reference\n\n";
1514
+ const relativePath = path
1515
+ .relative(installDir, agentPath)
1516
+ .replaceAll("\\", "/");
1287
1517
  agentRuleContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
1288
- agentRuleContent += '## Usage\n\n';
1518
+ agentRuleContent += "## Usage\n\n";
1289
1519
  agentRuleContent += `When the user types \`*${agentId}\`, activate this ${await this.getAgentTitle(
1290
1520
  agentId,
1291
1521
  installDir,
1292
1522
  )} persona and follow all instructions defined in the YAML configuration above.\n`;
1293
1523
 
1294
1524
  // Add to concatenated content with separator
1295
- concatenatedContent += agentRuleContent + '\n\n---\n\n';
1525
+ concatenatedContent += agentRuleContent + "\n\n---\n\n";
1296
1526
  console.log(chalk.green(`✓ Added context for @${agentId}`));
1297
1527
  }
1298
1528
  }
1299
1529
 
1300
1530
  // Write the concatenated content to GEMINI.md
1301
- const geminiMdPath = path.join(bmadMethodDir, 'GEMINI.md');
1531
+ const geminiMdPath = path.join(bmadMethodDir, "GEMINI.md");
1302
1532
  await fileManager.writeFile(geminiMdPath, concatenatedContent);
1303
1533
  console.log(chalk.green(`\n✓ Created GEMINI.md in ${bmadMethodDir}`));
1304
1534
 
@@ -1306,12 +1536,12 @@ class IdeSetup extends BaseIdeSetup {
1306
1536
  }
1307
1537
 
1308
1538
  async setupQwenCode(installDir, selectedAgent) {
1309
- const qwenDir = path.join(installDir, '.qwen');
1310
- const bmadMethodDir = path.join(qwenDir, 'xiaoma-cli');
1539
+ const qwenDir = path.join(installDir, ".qwen");
1540
+ const bmadMethodDir = path.join(qwenDir, "xiaoma-cli");
1311
1541
  await fileManager.ensureDirectory(bmadMethodDir);
1312
1542
 
1313
1543
  // Update logic for existing settings.json
1314
- const settingsPath = path.join(qwenDir, 'settings.json');
1544
+ const settingsPath = path.join(qwenDir, "settings.json");
1315
1545
  if (await fileManager.pathExists(settingsPath)) {
1316
1546
  try {
1317
1547
  const settingsContent = await fileManager.readFile(settingsPath);
@@ -1319,10 +1549,13 @@ class IdeSetup extends BaseIdeSetup {
1319
1549
  let updated = false;
1320
1550
 
1321
1551
  // Handle contextFileName property
1322
- if (settings.contextFileName && Array.isArray(settings.contextFileName)) {
1552
+ if (
1553
+ settings.contextFileName &&
1554
+ Array.isArray(settings.contextFileName)
1555
+ ) {
1323
1556
  const originalLength = settings.contextFileName.length;
1324
1557
  settings.contextFileName = settings.contextFileName.filter(
1325
- (fileName) => !fileName.startsWith('agents/'),
1558
+ (fileName) => !fileName.startsWith("agents/"),
1326
1559
  );
1327
1560
  if (settings.contextFileName.length !== originalLength) {
1328
1561
  updated = true;
@@ -1330,24 +1563,36 @@ class IdeSetup extends BaseIdeSetup {
1330
1563
  }
1331
1564
 
1332
1565
  if (updated) {
1333
- await fileManager.writeFile(settingsPath, JSON.stringify(settings, null, 2));
1334
- console.log(chalk.green('✓ Updated .qwen/settings.json - removed agent file references'));
1566
+ await fileManager.writeFile(
1567
+ settingsPath,
1568
+ JSON.stringify(settings, null, 2),
1569
+ );
1570
+ console.log(
1571
+ chalk.green(
1572
+ "✓ Updated .qwen/settings.json - removed agent file references",
1573
+ ),
1574
+ );
1335
1575
  }
1336
1576
  } catch (error) {
1337
- console.warn(chalk.yellow('Could not update .qwen/settings.json'), error);
1577
+ console.warn(
1578
+ chalk.yellow("Could not update .qwen/settings.json"),
1579
+ error,
1580
+ );
1338
1581
  }
1339
1582
  }
1340
1583
 
1341
1584
  // Remove old agents directory
1342
- const agentsDir = path.join(qwenDir, 'agents');
1585
+ const agentsDir = path.join(qwenDir, "agents");
1343
1586
  if (await fileManager.pathExists(agentsDir)) {
1344
1587
  await fileManager.removeDirectory(agentsDir);
1345
- console.log(chalk.green('✓ Removed old .qwen/agents directory'));
1588
+ console.log(chalk.green("✓ Removed old .qwen/agents directory"));
1346
1589
  }
1347
1590
 
1348
1591
  // Get all available agents
1349
- const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
1350
- let concatenatedContent = '';
1592
+ const agents = selectedAgent
1593
+ ? [selectedAgent]
1594
+ : await this.getAllAgentIds(installDir);
1595
+ let concatenatedContent = "";
1351
1596
 
1352
1597
  for (const agentId of agents) {
1353
1598
  // Find the source agent file
@@ -1362,36 +1607,38 @@ class IdeSetup extends BaseIdeSetup {
1362
1607
  agentId,
1363
1608
  installDir,
1364
1609
  )} agent persona.\n\n`;
1365
- agentRuleContent += '## Agent Activation\n\n';
1610
+ agentRuleContent += "## Agent Activation\n\n";
1366
1611
  agentRuleContent +=
1367
- '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';
1368
- agentRuleContent += '```yaml\n';
1612
+ "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";
1613
+ agentRuleContent += "```yaml\n";
1369
1614
  // Extract just the YAML content from the agent file
1370
1615
  const yamlContent = extractYamlFromAgent(agentContent);
1371
1616
  if (yamlContent) {
1372
1617
  agentRuleContent += yamlContent;
1373
1618
  } else {
1374
1619
  // If no YAML found, include the whole content minus the header
1375
- agentRuleContent += agentContent.replace(/^#.*$/m, '').trim();
1620
+ agentRuleContent += agentContent.replace(/^#.*$/m, "").trim();
1376
1621
  }
1377
- agentRuleContent += '\n```\n\n';
1378
- agentRuleContent += '## File Reference\n\n';
1379
- const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
1622
+ agentRuleContent += "\n```\n\n";
1623
+ agentRuleContent += "## File Reference\n\n";
1624
+ const relativePath = path
1625
+ .relative(installDir, agentPath)
1626
+ .replaceAll("\\", "/");
1380
1627
  agentRuleContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
1381
- agentRuleContent += '## Usage\n\n';
1628
+ agentRuleContent += "## Usage\n\n";
1382
1629
  agentRuleContent += `When the user types \`*${agentId}\`, activate this ${await this.getAgentTitle(
1383
1630
  agentId,
1384
1631
  installDir,
1385
1632
  )} persona and follow all instructions defined in the YAML configuration above.\n`;
1386
1633
 
1387
1634
  // Add to concatenated content with separator
1388
- concatenatedContent += agentRuleContent + '\n\n---\n\n';
1635
+ concatenatedContent += agentRuleContent + "\n\n---\n\n";
1389
1636
  console.log(chalk.green(`✓ Added context for *${agentId}`));
1390
1637
  }
1391
1638
  }
1392
1639
 
1393
1640
  // Write the concatenated content to QWEN.md
1394
- const qwenMdPath = path.join(bmadMethodDir, 'QWEN.md');
1641
+ const qwenMdPath = path.join(bmadMethodDir, "QWEN.md");
1395
1642
  await fileManager.writeFile(qwenMdPath, concatenatedContent);
1396
1643
  console.log(chalk.green(`\n✓ Created QWEN.md in ${bmadMethodDir}`));
1397
1644
 
@@ -1405,10 +1652,16 @@ class IdeSetup extends BaseIdeSetup {
1405
1652
  preConfiguredSettings = null,
1406
1653
  ) {
1407
1654
  // Configure VS Code workspace settings first to avoid UI conflicts with loading spinners
1408
- await this.configureVsCodeSettings(installDir, spinner, preConfiguredSettings);
1655
+ await this.configureVsCodeSettings(
1656
+ installDir,
1657
+ spinner,
1658
+ preConfiguredSettings,
1659
+ );
1409
1660
 
1410
- const chatmodesDir = path.join(installDir, '.github', 'chatmodes');
1411
- const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
1661
+ const chatmodesDir = path.join(installDir, ".github", "chatmodes");
1662
+ const agents = selectedAgent
1663
+ ? [selectedAgent]
1664
+ : await this.getAllAgentIds(installDir);
1412
1665
 
1413
1666
  await fileManager.ensureDirectory(chatmodesDir);
1414
1667
 
@@ -1446,14 +1699,22 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
1446
1699
  }
1447
1700
 
1448
1701
  console.log(chalk.green(`\n✓ Github Copilot setup complete!`));
1449
- console.log(chalk.dim(`You can now find the XiaoMa agents in the Chat view's mode selector.`));
1702
+ console.log(
1703
+ chalk.dim(
1704
+ `You can now find the XiaoMa agents in the Chat view's mode selector.`,
1705
+ ),
1706
+ );
1450
1707
 
1451
1708
  return true;
1452
1709
  }
1453
1710
 
1454
- async configureVsCodeSettings(installDir, spinner, preConfiguredSettings = null) {
1455
- const vscodeDir = path.join(installDir, '.vscode');
1456
- const settingsPath = path.join(vscodeDir, 'settings.json');
1711
+ async configureVsCodeSettings(
1712
+ installDir,
1713
+ spinner,
1714
+ preConfiguredSettings = null,
1715
+ ) {
1716
+ const vscodeDir = path.join(installDir, ".vscode");
1717
+ const settingsPath = path.join(vscodeDir, "settings.json");
1457
1718
 
1458
1719
  await fileManager.ensureDirectory(vscodeDir);
1459
1720
 
@@ -1464,10 +1725,16 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
1464
1725
  const existingContent = await fileManager.readFile(settingsPath);
1465
1726
  existingSettings = JSON.parse(existingContent);
1466
1727
  console.log(
1467
- chalk.yellow('Found existing .vscode/settings.json. Merging XiaoMa settings...'),
1728
+ chalk.yellow(
1729
+ "Found existing .vscode/settings.json. Merging XiaoMa settings...",
1730
+ ),
1468
1731
  );
1469
1732
  } catch {
1470
- console.warn(chalk.yellow('Could not parse existing settings.json. Creating new one.'));
1733
+ console.warn(
1734
+ chalk.yellow(
1735
+ "Could not parse existing settings.json. Creating new one.",
1736
+ ),
1737
+ );
1471
1738
  existingSettings = {};
1472
1739
  }
1473
1740
  }
@@ -1476,36 +1743,44 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
1476
1743
  let configChoice;
1477
1744
  if (preConfiguredSettings && preConfiguredSettings.configChoice) {
1478
1745
  configChoice = preConfiguredSettings.configChoice;
1479
- console.log(chalk.dim(`Using pre-configured GitHub Copilot settings: ${configChoice}`));
1746
+ console.log(
1747
+ chalk.dim(
1748
+ `Using pre-configured GitHub Copilot settings: ${configChoice}`,
1749
+ ),
1750
+ );
1480
1751
  } else {
1481
1752
  // Clear any previous output and add spacing to avoid conflicts with loaders
1482
- console.log('\n'.repeat(2));
1483
- console.log(chalk.blue('🔧 Github Copilot Agent Settings Configuration'));
1753
+ console.log("\n".repeat(2));
1754
+ console.log(chalk.blue("🔧 Github Copilot Agent Settings Configuration"));
1484
1755
  console.log(
1485
- chalk.dim('XiaoMa works best with specific VS Code settings for optimal agent experience.'),
1756
+ chalk.dim(
1757
+ "XiaoMa works best with specific VS Code settings for optimal agent experience.",
1758
+ ),
1486
1759
  );
1487
- console.log(''); // Add extra spacing
1760
+ console.log(""); // Add extra spacing
1488
1761
 
1489
1762
  const response = await inquirer.prompt([
1490
1763
  {
1491
- type: 'list',
1492
- name: 'configChoice',
1493
- message: chalk.yellow('How would you like to configure GitHub Copilot settings?'),
1764
+ type: "list",
1765
+ name: "configChoice",
1766
+ message: chalk.yellow(
1767
+ "How would you like to configure GitHub Copilot settings?",
1768
+ ),
1494
1769
  choices: [
1495
1770
  {
1496
- name: 'Use recommended defaults (fastest setup)',
1497
- value: 'defaults',
1771
+ name: "Use recommended defaults (fastest setup)",
1772
+ value: "defaults",
1498
1773
  },
1499
1774
  {
1500
- name: 'Configure each setting manually (customize to your preferences)',
1501
- value: 'manual',
1775
+ name: "Configure each setting manually (customize to your preferences)",
1776
+ value: "manual",
1502
1777
  },
1503
1778
  {
1504
1779
  name: "Skip settings configuration (I'll configure manually later)",
1505
- value: 'skip',
1780
+ value: "skip",
1506
1781
  },
1507
1782
  ],
1508
- default: 'defaults',
1783
+ default: "defaults",
1509
1784
  },
1510
1785
  ]);
1511
1786
  configChoice = response.configChoice;
@@ -1513,32 +1788,42 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
1513
1788
 
1514
1789
  let bmadSettings = {};
1515
1790
 
1516
- if (configChoice === 'skip') {
1517
- console.log(chalk.yellow('⚠️ Skipping VS Code settings configuration.'));
1518
- console.log(chalk.dim('You can manually configure these settings in .vscode/settings.json:'));
1519
- console.log(chalk.dim(' • chat.agent.enabled: true'));
1520
- console.log(chalk.dim(' • chat.agent.maxRequests: 15'));
1521
- console.log(chalk.dim(' • github.copilot.chat.agent.runTasks: true'));
1522
- console.log(chalk.dim(' • chat.mcp.discovery.enabled: true'));
1523
- console.log(chalk.dim('github.copilot.chat.agent.autoFix: true'));
1524
- console.log(chalk.dim(' • chat.tools.autoApprove: false'));
1791
+ if (configChoice === "skip") {
1792
+ console.log(chalk.yellow("⚠️ Skipping VS Code settings configuration."));
1793
+ console.log(
1794
+ chalk.dim(
1795
+ "You can manually configure these settings in .vscode/settings.json:",
1796
+ ),
1797
+ );
1798
+ console.log(chalk.dim(" • chat.agent.enabled: true"));
1799
+ console.log(chalk.dim(" • chat.agent.maxRequests: 15"));
1800
+ console.log(chalk.dim(" • github.copilot.chat.agent.runTasks: true"));
1801
+ console.log(chalk.dim(" • chat.mcp.discovery.enabled: true"));
1802
+ console.log(chalk.dim(" • github.copilot.chat.agent.autoFix: true"));
1803
+ console.log(chalk.dim(" • chat.tools.autoApprove: false"));
1525
1804
  return true;
1526
1805
  }
1527
1806
 
1528
- if (configChoice === 'defaults') {
1807
+ if (configChoice === "defaults") {
1529
1808
  // Use recommended defaults
1530
1809
  bmadSettings = {
1531
- 'chat.agent.enabled': true,
1532
- 'chat.agent.maxRequests': 15,
1533
- 'github.copilot.chat.agent.runTasks': true,
1534
- 'chat.mcp.discovery.enabled': true,
1535
- 'github.copilot.chat.agent.autoFix': true,
1536
- 'chat.tools.autoApprove': false,
1810
+ "chat.agent.enabled": true,
1811
+ "chat.agent.maxRequests": 15,
1812
+ "github.copilot.chat.agent.runTasks": true,
1813
+ "chat.mcp.discovery.enabled": true,
1814
+ "github.copilot.chat.agent.autoFix": true,
1815
+ "chat.tools.autoApprove": false,
1537
1816
  };
1538
- console.log(chalk.green('✓ Using recommended XiaoMa defaults for Github Copilot settings'));
1817
+ console.log(
1818
+ chalk.green(
1819
+ "✓ Using recommended XiaoMa defaults for Github Copilot settings",
1820
+ ),
1821
+ );
1539
1822
  } else {
1540
1823
  // Manual configuration
1541
- console.log(chalk.blue("\n📋 Let's configure each setting for your preferences:"));
1824
+ console.log(
1825
+ chalk.blue("\n📋 Let's configure each setting for your preferences:"),
1826
+ );
1542
1827
 
1543
1828
  // Pause spinner during manual configuration prompts
1544
1829
  let spinnerWasActive = false;
@@ -1549,40 +1834,43 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
1549
1834
 
1550
1835
  const manualSettings = await inquirer.prompt([
1551
1836
  {
1552
- type: 'input',
1553
- name: 'maxRequests',
1554
- message: 'Maximum requests per agent session (recommended: 15)?',
1555
- default: '15',
1837
+ type: "input",
1838
+ name: "maxRequests",
1839
+ message: "Maximum requests per agent session (recommended: 15)?",
1840
+ default: "15",
1556
1841
  validate: (input) => {
1557
1842
  const number_ = Number.parseInt(input);
1558
1843
  if (isNaN(number_) || number_ < 1 || number_ > 50) {
1559
- return 'Please enter a number between 1 and 50';
1844
+ return "Please enter a number between 1 and 50";
1560
1845
  }
1561
1846
  return true;
1562
1847
  },
1563
1848
  },
1564
1849
  {
1565
- type: 'confirm',
1566
- name: 'runTasks',
1567
- message: 'Allow agents to run workspace tasks (package.json scripts, etc.)?',
1850
+ type: "confirm",
1851
+ name: "runTasks",
1852
+ message:
1853
+ "Allow agents to run workspace tasks (package.json scripts, etc.)?",
1568
1854
  default: true,
1569
1855
  },
1570
1856
  {
1571
- type: 'confirm',
1572
- name: 'mcpDiscovery',
1573
- message: 'Enable MCP (Model Context Protocol) server discovery?',
1857
+ type: "confirm",
1858
+ name: "mcpDiscovery",
1859
+ message: "Enable MCP (Model Context Protocol) server discovery?",
1574
1860
  default: true,
1575
1861
  },
1576
1862
  {
1577
- type: 'confirm',
1578
- name: 'autoFix',
1579
- message: 'Enable automatic error detection and fixing in generated code?',
1863
+ type: "confirm",
1864
+ name: "autoFix",
1865
+ message:
1866
+ "Enable automatic error detection and fixing in generated code?",
1580
1867
  default: true,
1581
1868
  },
1582
1869
  {
1583
- type: 'confirm',
1584
- name: 'autoApprove',
1585
- message: 'Auto-approve ALL tools without confirmation? (⚠️ EXPERIMENTAL - less secure)',
1870
+ type: "confirm",
1871
+ name: "autoApprove",
1872
+ message:
1873
+ "Auto-approve ALL tools without confirmation? (⚠️ EXPERIMENTAL - less secure)",
1586
1874
  default: false,
1587
1875
  },
1588
1876
  ]);
@@ -1593,39 +1881,55 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
1593
1881
  }
1594
1882
 
1595
1883
  bmadSettings = {
1596
- 'chat.agent.enabled': true, // Always enabled - required for XiaoMa agents
1597
- 'chat.agent.maxRequests': Number.parseInt(manualSettings.maxRequests),
1598
- 'github.copilot.chat.agent.runTasks': manualSettings.runTasks,
1599
- 'chat.mcp.discovery.enabled': manualSettings.mcpDiscovery,
1600
- 'github.copilot.chat.agent.autoFix': manualSettings.autoFix,
1601
- 'chat.tools.autoApprove': manualSettings.autoApprove,
1884
+ "chat.agent.enabled": true, // Always enabled - required for XiaoMa agents
1885
+ "chat.agent.maxRequests": Number.parseInt(manualSettings.maxRequests),
1886
+ "github.copilot.chat.agent.runTasks": manualSettings.runTasks,
1887
+ "chat.mcp.discovery.enabled": manualSettings.mcpDiscovery,
1888
+ "github.copilot.chat.agent.autoFix": manualSettings.autoFix,
1889
+ "chat.tools.autoApprove": manualSettings.autoApprove,
1602
1890
  };
1603
1891
 
1604
- console.log(chalk.green('✓ Custom settings configured'));
1892
+ console.log(chalk.green("✓ Custom settings configured"));
1605
1893
  }
1606
1894
 
1607
1895
  // Merge settings (existing settings take precedence to avoid overriding user preferences)
1608
1896
  const mergedSettings = { ...bmadSettings, ...existingSettings };
1609
1897
 
1610
1898
  // Write the updated settings
1611
- await fileManager.writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2));
1899
+ await fileManager.writeFile(
1900
+ settingsPath,
1901
+ JSON.stringify(mergedSettings, null, 2),
1902
+ );
1612
1903
 
1613
- console.log(chalk.green('✓ VS Code workspace settings configured successfully'));
1614
- console.log(chalk.dim(' Settings written to .vscode/settings.json:'));
1904
+ console.log(
1905
+ chalk.green("✓ VS Code workspace settings configured successfully"),
1906
+ );
1907
+ console.log(chalk.dim(" Settings written to .vscode/settings.json:"));
1615
1908
  for (const [key, value] of Object.entries(bmadSettings)) {
1616
1909
  console.log(chalk.dim(` • ${key}: ${value}`));
1617
1910
  }
1618
- console.log(chalk.dim(''));
1619
- console.log(chalk.dim('You can modify these settings anytime in .vscode/settings.json'));
1911
+ console.log(chalk.dim(""));
1912
+ console.log(
1913
+ chalk.dim(
1914
+ "You can modify these settings anytime in .vscode/settings.json",
1915
+ ),
1916
+ );
1620
1917
  }
1621
1918
 
1622
- async setupAuggieCLI(installDir, selectedAgent, spinner = null, preConfiguredSettings = null) {
1623
- const os = require('node:os');
1624
- const inquirer = require('inquirer');
1625
- const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
1919
+ async setupAuggieCLI(
1920
+ installDir,
1921
+ selectedAgent,
1922
+ spinner = null,
1923
+ preConfiguredSettings = null,
1924
+ ) {
1925
+ const os = require("node:os");
1926
+ const inquirer = require("inquirer");
1927
+ const agents = selectedAgent
1928
+ ? [selectedAgent]
1929
+ : await this.getAllAgentIds(installDir);
1626
1930
 
1627
1931
  // Get the IDE configuration to access location options
1628
- const ideConfig = await configLoader.getIdeConfiguration('auggie-cli');
1932
+ const ideConfig = await configLoader.getIdeConfiguration("auggie-cli");
1629
1933
  const locations = ideConfig.locations;
1630
1934
 
1631
1935
  // Use pre-configured settings if provided, otherwise prompt
@@ -1634,7 +1938,7 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
1634
1938
  selectedLocations = preConfiguredSettings.selectedLocations;
1635
1939
  console.log(
1636
1940
  chalk.dim(
1637
- `Using pre-configured Auggie CLI (Augment Code) locations: ${selectedLocations.join(', ')}`,
1941
+ `Using pre-configured Auggie CLI (Augment Code) locations: ${selectedLocations.join(", ")}`,
1638
1942
  ),
1639
1943
  );
1640
1944
  } else {
@@ -1646,23 +1950,27 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
1646
1950
  }
1647
1951
 
1648
1952
  // Clear any previous output and add spacing to avoid conflicts with loaders
1649
- console.log('\n'.repeat(2));
1650
- console.log(chalk.blue('📍 Auggie CLI Location Configuration'));
1651
- console.log(chalk.dim('Choose where to install XiaoMa agents for Auggie CLI access.'));
1652
- console.log(''); // Add extra spacing
1953
+ console.log("\n".repeat(2));
1954
+ console.log(chalk.blue("📍 Auggie CLI Location Configuration"));
1955
+ console.log(
1956
+ chalk.dim(
1957
+ "Choose where to install XiaoMa agents for Auggie CLI access.",
1958
+ ),
1959
+ );
1960
+ console.log(""); // Add extra spacing
1653
1961
 
1654
1962
  const response = await inquirer.prompt([
1655
1963
  {
1656
- type: 'checkbox',
1657
- name: 'selectedLocations',
1658
- message: 'Select Auggie CLI command locations:',
1964
+ type: "checkbox",
1965
+ name: "selectedLocations",
1966
+ message: "Select Auggie CLI command locations:",
1659
1967
  choices: Object.entries(locations).map(([key, location]) => ({
1660
1968
  name: `${location.name}: ${location.description}`,
1661
1969
  value: key,
1662
1970
  })),
1663
1971
  validate: (selected) => {
1664
1972
  if (selected.length === 0) {
1665
- return 'Please select at least one location';
1973
+ return "Please select at least one location";
1666
1974
  }
1667
1975
  return true;
1668
1976
  },
@@ -1679,12 +1987,12 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
1679
1987
  // Install to each selected location
1680
1988
  for (const locationKey of selectedLocations) {
1681
1989
  const location = locations[locationKey];
1682
- let commandsDir = location['rule-dir'];
1990
+ let commandsDir = location["rule-dir"];
1683
1991
 
1684
1992
  // Handle tilde expansion for user directory
1685
- if (commandsDir.startsWith('~/')) {
1993
+ if (commandsDir.startsWith("~/")) {
1686
1994
  commandsDir = path.join(os.homedir(), commandsDir.slice(2));
1687
- } else if (commandsDir.startsWith('./')) {
1995
+ } else if (commandsDir.startsWith("./")) {
1688
1996
  commandsDir = path.join(installDir, commandsDir.slice(2));
1689
1997
  }
1690
1998
 
@@ -1698,12 +2006,18 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
1698
2006
  const agentContent = await fileManager.readFile(agentPath);
1699
2007
  const mdPath = path.join(commandsDir, `${agentId}.md`);
1700
2008
  await fileManager.writeFile(mdPath, agentContent);
1701
- console.log(chalk.green(`✓ Created command: ${agentId}.md in ${location.name}`));
2009
+ console.log(
2010
+ chalk.green(`✓ Created command: ${agentId}.md in ${location.name}`),
2011
+ );
1702
2012
  }
1703
2013
  }
1704
2014
 
1705
- console.log(chalk.green(`\n✓ Created Auggie CLI commands in ${commandsDir}`));
1706
- console.log(chalk.dim(` Location: ${location.name} - ${location.description}`));
2015
+ console.log(
2016
+ chalk.green(`\n✓ Created Auggie CLI commands in ${commandsDir}`),
2017
+ );
2018
+ console.log(
2019
+ chalk.dim(` Location: ${location.name} - ${location.description}`),
2020
+ );
1707
2021
  }
1708
2022
 
1709
2023
  return true;