@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,15 +1,15 @@
1
- const fs = require('node:fs').promises;
2
- const path = require('node:path');
3
- const { glob } = require('glob');
1
+ const fs = require("node:fs").promises;
2
+ const path = require("node:path");
3
+ const { glob } = require("glob");
4
4
 
5
5
  // Dynamic imports for ES modules
6
6
  let chalk, ora, inquirer;
7
7
 
8
8
  // Initialize ES modules
9
9
  async function initializeModules() {
10
- chalk = (await import('chalk')).default;
11
- ora = (await import('ora')).default;
12
- inquirer = (await import('inquirer')).default;
10
+ chalk = (await import("chalk")).default;
11
+ ora = (await import("ora")).default;
12
+ inquirer = (await import("inquirer")).default;
13
13
  }
14
14
 
15
15
  class V3ToV4Upgrader {
@@ -25,15 +25,23 @@ class V3ToV4Upgrader {
25
25
  process.stdin.resume();
26
26
 
27
27
  // 1. Welcome message
28
- console.log(chalk.bold('\nWelcome to XiaoMa-Cli V3 to V4 Upgrade Tool\n'));
29
- console.log('This tool will help you upgrade your XiaoMa-Cli V3 project to V4.\n');
30
- console.log(chalk.cyan('What this tool does:'));
31
- console.log('- Creates a backup of your V3 files (.bmad-v3-backup/)');
32
- console.log('- Installs the new V4 .xiaoma-core structure');
33
- console.log('- Preserves your PRD, Architecture, and Stories in the new format\n');
34
- console.log(chalk.yellow('What this tool does NOT do:'));
35
- console.log('- Modify your document content (use doc-migration-task after upgrade)');
36
- console.log('- Touch any files outside bmad-agent/ and docs/\n');
28
+ console.log(
29
+ chalk.bold("\nWelcome to XiaoMa-Cli V3 to V4 Upgrade Tool\n"),
30
+ );
31
+ console.log(
32
+ "This tool will help you upgrade your XiaoMa-Cli V3 project to V4.\n",
33
+ );
34
+ console.log(chalk.cyan("What this tool does:"));
35
+ console.log("- Creates a backup of your V3 files (.bmad-v3-backup/)");
36
+ console.log("- Installs the new V4 .xiaoma-core structure");
37
+ console.log(
38
+ "- Preserves your PRD, Architecture, and Stories in the new format\n",
39
+ );
40
+ console.log(chalk.yellow("What this tool does NOT do:"));
41
+ console.log(
42
+ "- Modify your document content (use doc-migration-task after upgrade)",
43
+ );
44
+ console.log("- Touch any files outside bmad-agent/ and docs/\n");
37
45
 
38
46
  // 2. Get project path
39
47
  const projectPath = await this.getProjectPath(options.projectPath);
@@ -41,11 +49,15 @@ class V3ToV4Upgrader {
41
49
  // 3. Validate V3 structure
42
50
  const validation = await this.validateV3Project(projectPath);
43
51
  if (!validation.isValid) {
44
- console.error(chalk.red("\nError: This doesn't appear to be a V3 project."));
45
- console.error('Expected to find:');
46
- console.error('- bmad-agent/ directory');
47
- console.error('- docs/ directory\n');
48
- console.error("Please check you're in the correct directory and try again.");
52
+ console.error(
53
+ chalk.red("\nError: This doesn't appear to be a V3 project."),
54
+ );
55
+ console.error("Expected to find:");
56
+ console.error("- bmad-agent/ directory");
57
+ console.error("- docs/ directory\n");
58
+ console.error(
59
+ "Please check you're in the correct directory and try again.",
60
+ );
49
61
  return;
50
62
  }
51
63
 
@@ -56,15 +68,15 @@ class V3ToV4Upgrader {
56
68
  if (!options.dryRun) {
57
69
  const { confirm } = await inquirer.prompt([
58
70
  {
59
- type: 'confirm',
60
- name: 'confirm',
61
- message: 'Continue with upgrade?',
71
+ type: "confirm",
72
+ name: "confirm",
73
+ message: "Continue with upgrade?",
62
74
  default: true,
63
75
  },
64
76
  ]);
65
77
 
66
78
  if (!confirm) {
67
- console.log('Upgrade cancelled.');
79
+ console.log("Upgrade cancelled.");
68
80
  return;
69
81
  }
70
82
  }
@@ -94,7 +106,7 @@ class V3ToV4Upgrader {
94
106
 
95
107
  process.exit(0);
96
108
  } catch (error) {
97
- console.error(chalk.red('\nUpgrade error:'), error.message);
109
+ console.error(chalk.red("\nUpgrade error:"), error.message);
98
110
  process.exit(1);
99
111
  }
100
112
  }
@@ -106,9 +118,9 @@ class V3ToV4Upgrader {
106
118
 
107
119
  const { projectPath } = await inquirer.prompt([
108
120
  {
109
- type: 'input',
110
- name: 'projectPath',
111
- message: 'Please enter the path to your V3 project:',
121
+ type: "input",
122
+ name: "projectPath",
123
+ message: "Please enter the path to your V3 project:",
112
124
  default: process.cwd(),
113
125
  },
114
126
  ]);
@@ -117,45 +129,45 @@ class V3ToV4Upgrader {
117
129
  }
118
130
 
119
131
  async validateV3Project(projectPath) {
120
- const spinner = ora('Validating project structure...').start();
132
+ const spinner = ora("Validating project structure...").start();
121
133
 
122
134
  try {
123
- const bmadAgentPath = path.join(projectPath, 'bmad-agent');
124
- const docsPath = path.join(projectPath, 'docs');
135
+ const bmadAgentPath = path.join(projectPath, "bmad-agent");
136
+ const docsPath = path.join(projectPath, "docs");
125
137
 
126
138
  const hasBmadAgent = await this.pathExists(bmadAgentPath);
127
139
  const hasDocs = await this.pathExists(docsPath);
128
140
 
129
141
  if (hasBmadAgent) {
130
- spinner.text = '✓ Found bmad-agent/ directory';
131
- console.log(chalk.green('\n✓ Found bmad-agent/ directory'));
142
+ spinner.text = "✓ Found bmad-agent/ directory";
143
+ console.log(chalk.green("\n✓ Found bmad-agent/ directory"));
132
144
  }
133
145
 
134
146
  if (hasDocs) {
135
- console.log(chalk.green('✓ Found docs/ directory'));
147
+ console.log(chalk.green("✓ Found docs/ directory"));
136
148
  }
137
149
 
138
150
  const isValid = hasBmadAgent && hasDocs;
139
151
 
140
152
  if (isValid) {
141
- spinner.succeed('This appears to be a valid V3 project');
153
+ spinner.succeed("This appears to be a valid V3 project");
142
154
  } else {
143
- spinner.fail('Invalid V3 project structure');
155
+ spinner.fail("Invalid V3 project structure");
144
156
  }
145
157
 
146
158
  return { isValid, hasBmadAgent, hasDocs };
147
159
  } catch (error) {
148
- spinner.fail('Validation failed');
160
+ spinner.fail("Validation failed");
149
161
  throw error;
150
162
  }
151
163
  }
152
164
 
153
165
  async analyzeProject(projectPath) {
154
- const docsPath = path.join(projectPath, 'docs');
155
- const bmadAgentPath = path.join(projectPath, 'bmad-agent');
166
+ const docsPath = path.join(projectPath, "docs");
167
+ const bmadAgentPath = path.join(projectPath, "bmad-agent");
156
168
 
157
169
  // Find PRD
158
- const prdCandidates = ['prd.md', 'PRD.md', 'product-requirements.md'];
170
+ const prdCandidates = ["prd.md", "PRD.md", "product-requirements.md"];
159
171
  let prdFile = null;
160
172
  for (const candidate of prdCandidates) {
161
173
  const candidatePath = path.join(docsPath, candidate);
@@ -166,7 +178,11 @@ class V3ToV4Upgrader {
166
178
  }
167
179
 
168
180
  // Find Architecture
169
- const archCandidates = ['architecture.md', 'Architecture.md', 'technical-architecture.md'];
181
+ const archCandidates = [
182
+ "architecture.md",
183
+ "Architecture.md",
184
+ "technical-architecture.md",
185
+ ];
170
186
  let archFile = null;
171
187
  for (const candidate of archCandidates) {
172
188
  const candidatePath = path.join(docsPath, candidate);
@@ -178,9 +194,9 @@ class V3ToV4Upgrader {
178
194
 
179
195
  // Find Front-end Architecture (V3 specific)
180
196
  const frontEndCandidates = [
181
- 'front-end-architecture.md',
182
- 'frontend-architecture.md',
183
- 'ui-architecture.md',
197
+ "front-end-architecture.md",
198
+ "frontend-architecture.md",
199
+ "ui-architecture.md",
184
200
  ];
185
201
  let frontEndArchFile = null;
186
202
  for (const candidate of frontEndCandidates) {
@@ -193,10 +209,10 @@ class V3ToV4Upgrader {
193
209
 
194
210
  // Find UX/UI spec
195
211
  const uxSpecCandidates = [
196
- 'ux-ui-spec.md',
197
- 'ux-ui-specification.md',
198
- 'ui-spec.md',
199
- 'ux-spec.md',
212
+ "ux-ui-spec.md",
213
+ "ux-ui-specification.md",
214
+ "ui-spec.md",
215
+ "ux-spec.md",
200
216
  ];
201
217
  let uxSpecFile = null;
202
218
  for (const candidate of uxSpecCandidates) {
@@ -208,7 +224,12 @@ class V3ToV4Upgrader {
208
224
  }
209
225
 
210
226
  // Find v0 prompt or UX prompt
211
- const uxPromptCandidates = ['v0-prompt.md', 'ux-prompt.md', 'ui-prompt.md', 'design-prompt.md'];
227
+ const uxPromptCandidates = [
228
+ "v0-prompt.md",
229
+ "ux-prompt.md",
230
+ "ui-prompt.md",
231
+ "design-prompt.md",
232
+ ];
212
233
  let uxPromptFile = null;
213
234
  for (const candidate of uxPromptCandidates) {
214
235
  const candidatePath = path.join(docsPath, candidate);
@@ -219,19 +240,19 @@ class V3ToV4Upgrader {
219
240
  }
220
241
 
221
242
  // Find epic files
222
- const epicFiles = await glob('epic*.md', { cwd: docsPath });
243
+ const epicFiles = await glob("epic*.md", { cwd: docsPath });
223
244
 
224
245
  // Find story files
225
- const storiesPath = path.join(docsPath, 'stories');
246
+ const storiesPath = path.join(docsPath, "stories");
226
247
  let storyFiles = [];
227
248
  if (await this.pathExists(storiesPath)) {
228
- storyFiles = await glob('*.md', { cwd: storiesPath });
249
+ storyFiles = await glob("*.md", { cwd: storiesPath });
229
250
  }
230
251
 
231
252
  // Count custom files in bmad-agent
232
- const bmadAgentFiles = await glob('**/*.md', {
253
+ const bmadAgentFiles = await glob("**/*.md", {
233
254
  cwd: bmadAgentPath,
234
- ignore: ['node_modules/**'],
255
+ ignore: ["node_modules/**"],
235
256
  });
236
257
 
237
258
  return {
@@ -247,133 +268,157 @@ class V3ToV4Upgrader {
247
268
  }
248
269
 
249
270
  async showPreflightCheck(analysis, options) {
250
- console.log(chalk.bold('\nProject Analysis:'));
271
+ console.log(chalk.bold("\nProject Analysis:"));
251
272
  console.log(
252
- `- PRD found: ${analysis.prdFile ? `docs/${analysis.prdFile}` : chalk.yellow('Not found')}`,
273
+ `- PRD found: ${analysis.prdFile ? `docs/${analysis.prdFile}` : chalk.yellow("Not found")}`,
253
274
  );
254
275
  console.log(
255
276
  `- Architecture found: ${
256
- analysis.archFile ? `docs/${analysis.archFile}` : chalk.yellow('Not found')
277
+ analysis.archFile
278
+ ? `docs/${analysis.archFile}`
279
+ : chalk.yellow("Not found")
257
280
  }`,
258
281
  );
259
282
  if (analysis.frontEndArchFile) {
260
- console.log(`- Front-end Architecture found: docs/${analysis.frontEndArchFile}`);
283
+ console.log(
284
+ `- Front-end Architecture found: docs/${analysis.frontEndArchFile}`,
285
+ );
261
286
  }
262
287
  console.log(
263
288
  `- UX/UI Spec found: ${
264
- analysis.uxSpecFile ? `docs/${analysis.uxSpecFile}` : chalk.yellow('Not found')
289
+ analysis.uxSpecFile
290
+ ? `docs/${analysis.uxSpecFile}`
291
+ : chalk.yellow("Not found")
265
292
  }`,
266
293
  );
267
294
  console.log(
268
295
  `- UX/Design Prompt found: ${
269
- analysis.uxPromptFile ? `docs/${analysis.uxPromptFile}` : chalk.yellow('Not found')
296
+ analysis.uxPromptFile
297
+ ? `docs/${analysis.uxPromptFile}`
298
+ : chalk.yellow("Not found")
270
299
  }`,
271
300
  );
272
- console.log(`- Epic files found: ${analysis.epicFiles.length} files (epic*.md)`);
273
- console.log(`- Stories found: ${analysis.storyFiles.length} files in docs/stories/`);
301
+ console.log(
302
+ `- Epic files found: ${analysis.epicFiles.length} files (epic*.md)`,
303
+ );
304
+ console.log(
305
+ `- Stories found: ${analysis.storyFiles.length} files in docs/stories/`,
306
+ );
274
307
  console.log(`- Custom files in bmad-agent/: ${analysis.customFileCount}`);
275
308
 
276
309
  if (!options.dryRun) {
277
- console.log('\nThe following will be backed up to .bmad-v3-backup/:');
278
- console.log('- bmad-agent/ (entire directory)');
279
- console.log('- docs/ (entire directory)');
310
+ console.log("\nThe following will be backed up to .bmad-v3-backup/:");
311
+ console.log("- bmad-agent/ (entire directory)");
312
+ console.log("- docs/ (entire directory)");
280
313
 
281
314
  if (analysis.epicFiles.length > 0) {
282
315
  console.log(
283
316
  chalk.green(
284
- '\nNote: Epic files found! They will be placed in docs/prd/ with an index.md file.',
317
+ "\nNote: Epic files found! They will be placed in docs/prd/ with an index.md file.",
285
318
  ),
286
319
  );
287
320
  console.log(
288
- chalk.green("Since epic files exist, you won't need to shard the PRD after upgrade."),
321
+ chalk.green(
322
+ "Since epic files exist, you won't need to shard the PRD after upgrade.",
323
+ ),
289
324
  );
290
325
  }
291
326
  }
292
327
  }
293
328
 
294
329
  async createBackup(projectPath) {
295
- const spinner = ora('Creating backup...').start();
330
+ const spinner = ora("Creating backup...").start();
296
331
 
297
332
  try {
298
- const backupPath = path.join(projectPath, '.bmad-v3-backup');
333
+ const backupPath = path.join(projectPath, ".bmad-v3-backup");
299
334
 
300
335
  // Check if backup already exists
301
336
  if (await this.pathExists(backupPath)) {
302
- spinner.fail('Backup directory already exists');
303
- console.error(chalk.red('\nError: Backup directory .bmad-v3-backup/ already exists.'));
304
- console.error('\nThis might mean an upgrade was already attempted.');
305
- console.error('Please remove or rename the existing backup and try again.');
306
- throw new Error('Backup already exists');
337
+ spinner.fail("Backup directory already exists");
338
+ console.error(
339
+ chalk.red(
340
+ "\nError: Backup directory .bmad-v3-backup/ already exists.",
341
+ ),
342
+ );
343
+ console.error("\nThis might mean an upgrade was already attempted.");
344
+ console.error(
345
+ "Please remove or rename the existing backup and try again.",
346
+ );
347
+ throw new Error("Backup already exists");
307
348
  }
308
349
 
309
350
  // Create backup directory
310
351
  await fs.mkdir(backupPath, { recursive: true });
311
- spinner.text = '✓ Created .bmad-v3-backup/';
312
- console.log(chalk.green('\n✓ Created .bmad-v3-backup/'));
352
+ spinner.text = "✓ Created .bmad-v3-backup/";
353
+ console.log(chalk.green("\n✓ Created .bmad-v3-backup/"));
313
354
 
314
355
  // Move bmad-agent
315
- const bmadAgentSource = path.join(projectPath, 'bmad-agent');
316
- const bmadAgentDestination = path.join(backupPath, 'bmad-agent');
356
+ const bmadAgentSource = path.join(projectPath, "bmad-agent");
357
+ const bmadAgentDestination = path.join(backupPath, "bmad-agent");
317
358
  await fs.rename(bmadAgentSource, bmadAgentDestination);
318
- console.log(chalk.green('✓ Moved bmad-agent/ to backup'));
359
+ console.log(chalk.green("✓ Moved bmad-agent/ to backup"));
319
360
 
320
361
  // Move docs
321
- const docsSrc = path.join(projectPath, 'docs');
322
- const docsDest = path.join(backupPath, 'docs');
362
+ const docsSrc = path.join(projectPath, "docs");
363
+ const docsDest = path.join(backupPath, "docs");
323
364
  await fs.rename(docsSrc, docsDest);
324
- console.log(chalk.green('✓ Moved docs/ to backup'));
365
+ console.log(chalk.green("✓ Moved docs/ to backup"));
325
366
 
326
- spinner.succeed('Backup created successfully');
367
+ spinner.succeed("Backup created successfully");
327
368
  } catch (error) {
328
- spinner.fail('Backup failed');
369
+ spinner.fail("Backup failed");
329
370
  throw error;
330
371
  }
331
372
  }
332
373
 
333
374
  async installV4Structure(projectPath) {
334
- const spinner = ora('Installing V4 structure...').start();
375
+ const spinner = ora("Installing V4 structure...").start();
335
376
 
336
377
  try {
337
378
  // Get the source xiaoma-core directory (without dot prefix)
338
- const sourcePath = path.join(__dirname, '..', '..', 'xiaoma-core');
339
- const destinationPath = path.join(projectPath, '.xiaoma-core');
379
+ const sourcePath = path.join(__dirname, "..", "..", "xiaoma-core");
380
+ const destinationPath = path.join(projectPath, ".xiaoma-core");
340
381
 
341
382
  // Copy .xiaoma-core
342
383
  await this.copyDirectory(sourcePath, destinationPath);
343
- spinner.text = '✓ Copied fresh .xiaoma-core/ directory from V4';
344
- console.log(chalk.green('\n✓ Copied fresh .xiaoma-core/ directory from V4'));
384
+ spinner.text = "✓ Copied fresh .xiaoma-core/ directory from V4";
385
+ console.log(
386
+ chalk.green("\n✓ Copied fresh .xiaoma-core/ directory from V4"),
387
+ );
345
388
 
346
389
  // Create docs directory
347
- const docsPath = path.join(projectPath, 'docs');
390
+ const docsPath = path.join(projectPath, "docs");
348
391
  await fs.mkdir(docsPath, { recursive: true });
349
- console.log(chalk.green('✓ Created new docs/ directory'));
392
+ console.log(chalk.green("✓ Created new docs/ directory"));
350
393
 
351
394
  // Create install manifest for future updates
352
395
  await this.createInstallManifest(projectPath);
353
- console.log(chalk.green('✓ Created install manifest'));
396
+ console.log(chalk.green("✓ Created install manifest"));
354
397
 
355
398
  console.log(
356
- chalk.yellow('\nNote: Your V3 bmad-agent content has been backed up and NOT migrated.'),
399
+ chalk.yellow(
400
+ "\nNote: Your V3 bmad-agent content has been backed up and NOT migrated.",
401
+ ),
357
402
  );
358
403
  console.log(
359
404
  chalk.yellow(
360
- 'The new V4 agents are completely different and look for different file structures.',
405
+ "The new V4 agents are completely different and look for different file structures.",
361
406
  ),
362
407
  );
363
408
 
364
- spinner.succeed('V4 structure installed successfully');
409
+ spinner.succeed("V4 structure installed successfully");
365
410
  } catch (error) {
366
- spinner.fail('V4 installation failed');
411
+ spinner.fail("V4 installation failed");
367
412
  throw error;
368
413
  }
369
414
  }
370
415
 
371
416
  async migrateDocuments(projectPath, analysis) {
372
- const spinner = ora('Migrating your project documents...').start();
417
+ const spinner = ora("Migrating your project documents...").start();
373
418
 
374
419
  try {
375
- const backupDocsPath = path.join(projectPath, '.bmad-v3-backup', 'docs');
376
- const newDocsPath = path.join(projectPath, 'docs');
420
+ const backupDocsPath = path.join(projectPath, ".bmad-v3-backup", "docs");
421
+ const newDocsPath = path.join(projectPath, "docs");
377
422
  let copiedCount = 0;
378
423
 
379
424
  // Copy PRD
@@ -390,7 +435,9 @@ class V3ToV4Upgrader {
390
435
  const source = path.join(backupDocsPath, analysis.archFile);
391
436
  const destination = path.join(newDocsPath, analysis.archFile);
392
437
  await fs.copyFile(source, destination);
393
- console.log(chalk.green(`✓ Copied Architecture to docs/${analysis.archFile}`));
438
+ console.log(
439
+ chalk.green(`✓ Copied Architecture to docs/${analysis.archFile}`),
440
+ );
394
441
  copiedCount++;
395
442
  }
396
443
 
@@ -400,11 +447,13 @@ class V3ToV4Upgrader {
400
447
  const destination = path.join(newDocsPath, analysis.frontEndArchFile);
401
448
  await fs.copyFile(source, destination);
402
449
  console.log(
403
- chalk.green(`✓ Copied Front-end Architecture to docs/${analysis.frontEndArchFile}`),
450
+ chalk.green(
451
+ `✓ Copied Front-end Architecture to docs/${analysis.frontEndArchFile}`,
452
+ ),
404
453
  );
405
454
  console.log(
406
455
  chalk.yellow(
407
- 'Note: V4 uses a single full-stack-architecture.md - use doc-migration-task to merge',
456
+ "Note: V4 uses a single full-stack-architecture.md - use doc-migration-task to merge",
408
457
  ),
409
458
  );
410
459
  copiedCount++;
@@ -415,7 +464,9 @@ class V3ToV4Upgrader {
415
464
  const source = path.join(backupDocsPath, analysis.uxSpecFile);
416
465
  const destination = path.join(newDocsPath, analysis.uxSpecFile);
417
466
  await fs.copyFile(source, destination);
418
- console.log(chalk.green(`✓ Copied UX/UI Spec to docs/${analysis.uxSpecFile}`));
467
+ console.log(
468
+ chalk.green(`✓ Copied UX/UI Spec to docs/${analysis.uxSpecFile}`),
469
+ );
419
470
  copiedCount++;
420
471
  }
421
472
 
@@ -424,29 +475,35 @@ class V3ToV4Upgrader {
424
475
  const source = path.join(backupDocsPath, analysis.uxPromptFile);
425
476
  const destination = path.join(newDocsPath, analysis.uxPromptFile);
426
477
  await fs.copyFile(source, destination);
427
- console.log(chalk.green(`✓ Copied UX/Design Prompt to docs/${analysis.uxPromptFile}`));
478
+ console.log(
479
+ chalk.green(
480
+ `✓ Copied UX/Design Prompt to docs/${analysis.uxPromptFile}`,
481
+ ),
482
+ );
428
483
  copiedCount++;
429
484
  }
430
485
 
431
486
  // Copy stories
432
487
  if (analysis.storyFiles.length > 0) {
433
- const storiesDir = path.join(newDocsPath, 'stories');
488
+ const storiesDir = path.join(newDocsPath, "stories");
434
489
  await fs.mkdir(storiesDir, { recursive: true });
435
490
 
436
491
  for (const storyFile of analysis.storyFiles) {
437
- const source = path.join(backupDocsPath, 'stories', storyFile);
492
+ const source = path.join(backupDocsPath, "stories", storyFile);
438
493
  const destination = path.join(storiesDir, storyFile);
439
494
  await fs.copyFile(source, destination);
440
495
  }
441
496
  console.log(
442
- chalk.green(`✓ Copied ${analysis.storyFiles.length} story files to docs/stories/`),
497
+ chalk.green(
498
+ `✓ Copied ${analysis.storyFiles.length} story files to docs/stories/`,
499
+ ),
443
500
  );
444
501
  copiedCount += analysis.storyFiles.length;
445
502
  }
446
503
 
447
504
  // Copy epic files to prd subfolder
448
505
  if (analysis.epicFiles.length > 0) {
449
- const prdDir = path.join(newDocsPath, 'prd');
506
+ const prdDir = path.join(newDocsPath, "prd");
450
507
  await fs.mkdir(prdDir, { recursive: true });
451
508
 
452
509
  for (const epicFile of analysis.epicFiles) {
@@ -455,25 +512,31 @@ class V3ToV4Upgrader {
455
512
  await fs.copyFile(source, destination);
456
513
  }
457
514
  console.log(
458
- chalk.green(`✓ Found and copied ${analysis.epicFiles.length} epic files to docs/prd/`),
515
+ chalk.green(
516
+ `✓ Found and copied ${analysis.epicFiles.length} epic files to docs/prd/`,
517
+ ),
459
518
  );
460
519
 
461
520
  // Create index.md for the prd folder
462
521
  await this.createPrdIndex(projectPath, analysis);
463
- console.log(chalk.green('✓ Created index.md in docs/prd/'));
522
+ console.log(chalk.green("✓ Created index.md in docs/prd/"));
464
523
 
465
524
  console.log(
466
525
  chalk.green(
467
- '\nNote: Epic files detected! These are compatible with V4 and have been copied.',
526
+ "\nNote: Epic files detected! These are compatible with V4 and have been copied.",
527
+ ),
528
+ );
529
+ console.log(
530
+ chalk.green(
531
+ "You won't need to shard the PRD since epics already exist.",
468
532
  ),
469
533
  );
470
- console.log(chalk.green("You won't need to shard the PRD since epics already exist."));
471
534
  copiedCount += analysis.epicFiles.length;
472
535
  }
473
536
 
474
537
  spinner.succeed(`Migrated ${copiedCount} documents successfully`);
475
538
  } catch (error) {
476
- spinner.fail('Document migration failed');
539
+ spinner.fail("Document migration failed");
477
540
  throw error;
478
541
  }
479
542
  }
@@ -481,21 +544,21 @@ class V3ToV4Upgrader {
481
544
  async setupIDE(projectPath, selectedIdes) {
482
545
  // Use the IDE selections passed from the installer
483
546
  if (!selectedIdes || selectedIdes.length === 0) {
484
- console.log(chalk.dim('No IDE setup requested - skipping'));
547
+ console.log(chalk.dim("No IDE setup requested - skipping"));
485
548
  return;
486
549
  }
487
550
 
488
- const ideSetup = require('../installer/lib/ide-setup');
489
- const spinner = ora('Setting up IDE rules for all agents...').start();
551
+ const ideSetup = require("../installer/lib/ide-setup");
552
+ const spinner = ora("Setting up IDE rules for all agents...").start();
490
553
 
491
554
  try {
492
555
  const ideMessages = {
493
- cursor: 'Rules created in .cursor/rules/bmad/',
494
- 'claude-code': 'Commands created in .claude/commands/BMad/',
495
- windsurf: 'Rules created in .windsurf/workflows/',
496
- trae: 'Rules created in.trae/rules/',
497
- roo: 'Custom modes created in .roomodes',
498
- cline: 'Rules created in .clinerules/',
556
+ cursor: "Rules created in .cursor/rules/bmad/",
557
+ "claude-code": "Commands created in .claude/commands/BMad/",
558
+ windsurf: "Rules created in .windsurf/workflows/",
559
+ trae: "Rules created in.trae/rules/",
560
+ roo: "Custom modes created in .roomodes",
561
+ cline: "Rules created in .clinerules/",
499
562
  };
500
563
 
501
564
  // Setup each selected IDE
@@ -507,14 +570,14 @@ class V3ToV4Upgrader {
507
570
 
508
571
  spinner.succeed(`IDE setup complete for ${selectedIdes.length} IDE(s)!`);
509
572
  } catch {
510
- spinner.fail('IDE setup failed');
511
- console.error(chalk.yellow('IDE setup failed, but upgrade is complete.'));
573
+ spinner.fail("IDE setup failed");
574
+ console.error(chalk.yellow("IDE setup failed, but upgrade is complete."));
512
575
  }
513
576
  }
514
577
 
515
578
  showCompletionReport(projectPath, analysis) {
516
- console.log(chalk.bold.green('\n✓ Upgrade Complete!\n'));
517
- console.log(chalk.bold('Summary:'));
579
+ console.log(chalk.bold.green("\n✓ Upgrade Complete!\n"));
580
+ console.log(chalk.bold("Summary:"));
518
581
  console.log(`- V3 files backed up to: .bmad-v3-backup/`);
519
582
  console.log(`- V4 structure installed: .xiaoma-core/ (fresh from V4)`);
520
583
 
@@ -527,36 +590,50 @@ class V3ToV4Upgrader {
527
590
  analysis.storyFiles.length;
528
591
  console.log(
529
592
  `- Documents migrated: ${totalDocs} files${
530
- analysis.epicFiles.length > 0 ? ` + ${analysis.epicFiles.length} epics` : ''
593
+ analysis.epicFiles.length > 0
594
+ ? ` + ${analysis.epicFiles.length} epics`
595
+ : ""
531
596
  }`,
532
597
  );
533
598
 
534
- console.log(chalk.bold('\nImportant Changes:'));
535
- console.log('- The V4 agents (sm, dev, etc.) expect different file structures than V3');
536
- console.log("- Your V3 bmad-agent content was NOT migrated (it's incompatible)");
599
+ console.log(chalk.bold("\nImportant Changes:"));
600
+ console.log(
601
+ "- The V4 agents (sm, dev, etc.) expect different file structures than V3",
602
+ );
603
+ console.log(
604
+ "- Your V3 bmad-agent content was NOT migrated (it's incompatible)",
605
+ );
537
606
  if (analysis.epicFiles.length > 0) {
538
- console.log('- Epic files were found and copied - no PRD sharding needed!');
607
+ console.log(
608
+ "- Epic files were found and copied - no PRD sharding needed!",
609
+ );
539
610
  }
540
611
  if (analysis.frontEndArchFile) {
541
612
  console.log(
542
- '- Front-end architecture found - V4 uses full-stack-architecture.md, migration needed',
613
+ "- Front-end architecture found - V4 uses full-stack-architecture.md, migration needed",
543
614
  );
544
615
  }
545
616
  if (analysis.uxSpecFile || analysis.uxPromptFile) {
546
- console.log('- UX/UI design files found and copied - ready for use with V4');
617
+ console.log(
618
+ "- UX/UI design files found and copied - ready for use with V4",
619
+ );
547
620
  }
548
621
 
549
- console.log(chalk.bold('\nNext Steps:'));
550
- console.log('1. Review your documents in the new docs/ folder');
622
+ console.log(chalk.bold("\nNext Steps:"));
623
+ console.log("1. Review your documents in the new docs/ folder");
551
624
  console.log(
552
- '2. Use @bmad-master agent to run the doc-migration-task to align your documents with V4 templates',
625
+ "2. Use @bmad-master agent to run the doc-migration-task to align your documents with V4 templates",
553
626
  );
554
627
  if (analysis.epicFiles.length === 0) {
555
- console.log('3. Use @bmad-master agent to shard the PRD to create epic files');
628
+ console.log(
629
+ "3. Use @bmad-master agent to shard the PRD to create epic files",
630
+ );
556
631
  }
557
632
 
558
633
  console.log(
559
- chalk.dim('\nYour V3 backup is preserved in .bmad-v3-backup/ and can be restored if needed.'),
634
+ chalk.dim(
635
+ "\nYour V3 backup is preserved in .bmad-v3-backup/ and can be restored if needed.",
636
+ ),
560
637
  );
561
638
  }
562
639
 
@@ -584,38 +661,42 @@ class V3ToV4Upgrader {
584
661
  }
585
662
 
586
663
  async createPrdIndex(projectPath, analysis) {
587
- const prdIndexPath = path.join(projectPath, 'docs', 'prd', 'index.md');
588
- const prdPath = path.join(projectPath, 'docs', analysis.prdFile || 'prd.md');
664
+ const prdIndexPath = path.join(projectPath, "docs", "prd", "index.md");
665
+ const prdPath = path.join(
666
+ projectPath,
667
+ "docs",
668
+ analysis.prdFile || "prd.md",
669
+ );
589
670
 
590
- let indexContent = '# Product Requirements Document\n\n';
671
+ let indexContent = "# Product Requirements Document\n\n";
591
672
 
592
673
  // Try to read the PRD to get the title and intro content
593
674
  if (analysis.prdFile && (await this.pathExists(prdPath))) {
594
675
  try {
595
- const prdContent = await fs.readFile(prdPath, 'utf8');
596
- const lines = prdContent.split('\n');
676
+ const prdContent = await fs.readFile(prdPath, "utf8");
677
+ const lines = prdContent.split("\n");
597
678
 
598
679
  // Find the first heading
599
- const titleMatch = lines.find((line) => line.startsWith('# '));
680
+ const titleMatch = lines.find((line) => line.startsWith("# "));
600
681
  if (titleMatch) {
601
- indexContent = titleMatch + '\n\n';
682
+ indexContent = titleMatch + "\n\n";
602
683
  }
603
684
 
604
685
  // Get any content before the first ## section
605
- let introContent = '';
686
+ let introContent = "";
606
687
  let foundFirstSection = false;
607
688
  for (const line of lines) {
608
- if (line.startsWith('## ')) {
689
+ if (line.startsWith("## ")) {
609
690
  foundFirstSection = true;
610
691
  break;
611
692
  }
612
- if (!line.startsWith('# ')) {
613
- introContent += line + '\n';
693
+ if (!line.startsWith("# ")) {
694
+ introContent += line + "\n";
614
695
  }
615
696
  }
616
697
 
617
698
  if (introContent.trim()) {
618
- indexContent += introContent.trim() + '\n\n';
699
+ indexContent += introContent.trim() + "\n\n";
619
700
  }
620
701
  } catch {
621
702
  // If we can't read the PRD, just use default content
@@ -623,7 +704,7 @@ class V3ToV4Upgrader {
623
704
  }
624
705
 
625
706
  // Add sections list
626
- indexContent += '## Sections\n\n';
707
+ indexContent += "## Sections\n\n";
627
708
 
628
709
  // Sort epic files for consistent ordering
629
710
  const sortedEpics = [...analysis.epicFiles].sort();
@@ -631,36 +712,36 @@ class V3ToV4Upgrader {
631
712
  for (const epicFile of sortedEpics) {
632
713
  // Extract epic name from filename
633
714
  const epicName = epicFile
634
- .replace(/\.md$/, '')
635
- .replace(/^epic-?/i, '')
636
- .replaceAll('-', ' ')
637
- .replace(/^\d+\s*/, '') // Remove leading numbers
715
+ .replace(/\.md$/, "")
716
+ .replace(/^epic-?/i, "")
717
+ .replaceAll("-", " ")
718
+ .replace(/^\d+\s*/, "") // Remove leading numbers
638
719
  .trim();
639
720
 
640
721
  const displayName = epicName.charAt(0).toUpperCase() + epicName.slice(1);
641
- indexContent += `- [${displayName || epicFile.replace('.md', '')}](./${epicFile})\n`;
722
+ indexContent += `- [${displayName || epicFile.replace(".md", "")}](./${epicFile})\n`;
642
723
  }
643
724
 
644
725
  await fs.writeFile(prdIndexPath, indexContent);
645
726
  }
646
727
 
647
728
  async createInstallManifest(projectPath) {
648
- const fileManager = require('../installer/lib/file-manager');
649
- const { glob } = require('glob');
729
+ const fileManager = require("../installer/lib/file-manager");
730
+ const { glob } = require("glob");
650
731
 
651
732
  // Get all files in .xiaoma-core for the manifest
652
- const bmadCorePath = path.join(projectPath, '.xiaoma-core');
653
- const files = await glob('**/*', {
733
+ const bmadCorePath = path.join(projectPath, ".xiaoma-core");
734
+ const files = await glob("**/*", {
654
735
  cwd: bmadCorePath,
655
736
  nodir: true,
656
- ignore: ['**/.git/**', '**/node_modules/**'],
737
+ ignore: ["**/.git/**", "**/node_modules/**"],
657
738
  });
658
739
 
659
740
  // Prepend .xiaoma-core/ to file paths for manifest
660
- const manifestFiles = files.map((file) => path.join('.xiaoma-core', file));
741
+ const manifestFiles = files.map((file) => path.join(".xiaoma-core", file));
661
742
 
662
743
  const config = {
663
- installType: 'full',
744
+ installType: "full",
664
745
  agent: null,
665
746
  ide: null, // Will be set if IDE setup is done later
666
747
  };