bmad-method 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/.bmad-core/agent-teams/team-all.yml +16 -0
  2. package/.bmad-core/agent-teams/team-fullstack.yml +26 -0
  3. package/.bmad-core/agent-teams/team-no-ui.yml +15 -0
  4. package/.bmad-core/agents/analyst.md +65 -0
  5. package/.bmad-core/agents/architect.md +66 -0
  6. package/.bmad-core/agents/bmad-master.md +107 -0
  7. package/.bmad-core/agents/bmad-orchestrator.md +81 -0
  8. package/.bmad-core/agents/dev.md +69 -0
  9. package/.bmad-core/agents/pm.md +64 -0
  10. package/.bmad-core/agents/po.md +60 -0
  11. package/.bmad-core/agents/qa.md +52 -0
  12. package/.bmad-core/agents/sm.md +60 -0
  13. package/.bmad-core/agents/ux-expert.md +66 -0
  14. package/.bmad-core/checklists/architect-checklist.md +443 -0
  15. package/.bmad-core/checklists/change-checklist.md +182 -0
  16. package/.bmad-core/checklists/pm-checklist.md +375 -0
  17. package/.bmad-core/checklists/po-master-checklist.md +441 -0
  18. package/.bmad-core/checklists/story-dod-checklist.md +101 -0
  19. package/.bmad-core/checklists/story-draft-checklist.md +156 -0
  20. package/.bmad-core/data/bmad-kb.md +36 -0
  21. package/.bmad-core/data/technical-preferences.md +3 -0
  22. package/.bmad-core/schemas/agent-team-schema.yml +153 -0
  23. package/.bmad-core/tasks/advanced-elicitation.md +92 -0
  24. package/.bmad-core/tasks/brainstorming-techniques.md +238 -0
  25. package/.bmad-core/tasks/brownfield-create-epic.md +160 -0
  26. package/.bmad-core/tasks/brownfield-create-story.md +147 -0
  27. package/.bmad-core/tasks/core-dump.md +74 -0
  28. package/.bmad-core/tasks/correct-course.md +73 -0
  29. package/.bmad-core/tasks/create-agent.md +202 -0
  30. package/.bmad-core/tasks/create-deep-research-prompt.md +301 -0
  31. package/.bmad-core/tasks/create-doc.md +74 -0
  32. package/.bmad-core/tasks/create-expansion-pack.md +425 -0
  33. package/.bmad-core/tasks/create-next-story.md +206 -0
  34. package/.bmad-core/tasks/create-team.md +229 -0
  35. package/.bmad-core/tasks/doc-migration-task.md +198 -0
  36. package/.bmad-core/tasks/execute-checklist.md +97 -0
  37. package/.bmad-core/tasks/generate-ai-frontend-prompt.md +58 -0
  38. package/.bmad-core/tasks/index-docs.md +180 -0
  39. package/.bmad-core/tasks/shard-doc.md +173 -0
  40. package/.bmad-core/templates/agent-tmpl.md +58 -0
  41. package/.bmad-core/templates/architecture-tmpl.md +771 -0
  42. package/.bmad-core/templates/brownfield-architecture-tmpl.md +542 -0
  43. package/.bmad-core/templates/brownfield-prd-tmpl.md +240 -0
  44. package/.bmad-core/templates/competitor-analysis-tmpl.md +289 -0
  45. package/.bmad-core/templates/expansion-pack-plan-tmpl.md +91 -0
  46. package/.bmad-core/templates/front-end-architecture-tmpl.md +173 -0
  47. package/.bmad-core/templates/front-end-spec-tmpl.md +411 -0
  48. package/.bmad-core/templates/fullstack-architecture-tmpl.md +1034 -0
  49. package/.bmad-core/templates/market-research-tmpl.md +261 -0
  50. package/.bmad-core/templates/prd-tmpl.md +200 -0
  51. package/.bmad-core/templates/project-brief-tmpl.md +228 -0
  52. package/.bmad-core/templates/story-tmpl.md +61 -0
  53. package/.bmad-core/templates/web-agent-startup-instructions-template.md +39 -0
  54. package/.bmad-core/utils/agent-switcher.ide.md +112 -0
  55. package/.bmad-core/utils/template-format.md +26 -0
  56. package/.bmad-core/utils/workflow-management.md +224 -0
  57. package/.bmad-core/web-bundles/agents/analyst.txt +1679 -0
  58. package/.bmad-core/web-bundles/agents/architect.txt +3602 -0
  59. package/.bmad-core/web-bundles/agents/bmad-master.txt +9496 -0
  60. package/.bmad-core/web-bundles/agents/bmad-orchestrator.txt +1455 -0
  61. package/.bmad-core/web-bundles/agents/dev.txt +315 -0
  62. package/.bmad-core/web-bundles/agents/pm.txt +2196 -0
  63. package/.bmad-core/web-bundles/agents/po.txt +1489 -0
  64. package/.bmad-core/web-bundles/agents/qa.txt +129 -0
  65. package/.bmad-core/web-bundles/agents/sm.txt +663 -0
  66. package/.bmad-core/web-bundles/agents/ux-expert.txt +1099 -0
  67. package/.bmad-core/web-bundles/teams/team-all.txt +10315 -0
  68. package/.bmad-core/web-bundles/teams/team-fullstack.txt +9663 -0
  69. package/.bmad-core/web-bundles/teams/team-no-ui.txt +8504 -0
  70. package/.bmad-core/workflows/brownfield-fullstack.yml +116 -0
  71. package/.bmad-core/workflows/brownfield-service.yml +117 -0
  72. package/.bmad-core/workflows/brownfield-ui.yml +127 -0
  73. package/.bmad-core/workflows/greenfield-fullstack.yml +177 -0
  74. package/.bmad-core/workflows/greenfield-service.yml +143 -0
  75. package/.bmad-core/workflows/greenfield-ui.yml +172 -0
  76. package/.claude/commands/analyst.md +69 -0
  77. package/.claude/commands/architect.md +70 -0
  78. package/.claude/commands/bmad-master.md +111 -0
  79. package/.claude/commands/bmad-orchestrator.md +85 -0
  80. package/.claude/commands/dev.md +73 -0
  81. package/.claude/commands/pm.md +68 -0
  82. package/.claude/commands/po.md +64 -0
  83. package/.claude/commands/qa.md +56 -0
  84. package/.claude/commands/sm.md +64 -0
  85. package/.claude/commands/ux-expert.md +70 -0
  86. package/.cursor/rules/analyst.mdc +83 -0
  87. package/.cursor/rules/architect.mdc +84 -0
  88. package/.cursor/rules/bmad-master.mdc +125 -0
  89. package/.cursor/rules/bmad-orchestrator.mdc +99 -0
  90. package/.cursor/rules/dev.mdc +87 -0
  91. package/.cursor/rules/pm.mdc +82 -0
  92. package/.cursor/rules/po.mdc +78 -0
  93. package/.cursor/rules/qa.mdc +70 -0
  94. package/.cursor/rules/sm.mdc +78 -0
  95. package/.cursor/rules/ux-expert.mdc +84 -0
  96. package/.github/workflows/release.yml +59 -0
  97. package/.husky/pre-commit +2 -0
  98. package/.releaserc.json +17 -0
  99. package/.roo/.roomodes +95 -0
  100. package/.roo/README.md +38 -0
  101. package/.vscode/extensions.json +6 -0
  102. package/.vscode/settings.json +72 -0
  103. package/.windsurf/rules/analyst.md +77 -0
  104. package/.windsurf/rules/architect.md +78 -0
  105. package/.windsurf/rules/bmad-master.md +119 -0
  106. package/.windsurf/rules/bmad-orchestrator.md +93 -0
  107. package/.windsurf/rules/dev.md +81 -0
  108. package/.windsurf/rules/pm.md +76 -0
  109. package/.windsurf/rules/po.md +72 -0
  110. package/.windsurf/rules/qa.md +64 -0
  111. package/.windsurf/rules/sm.md +72 -0
  112. package/.windsurf/rules/ux-expert.md +78 -0
  113. package/CHANGELOG.md +22 -0
  114. package/CONTRIBUTING.md +46 -0
  115. package/LICENSE +21 -0
  116. package/README.md +283 -0
  117. package/docs/versioning-and-releases.md +85 -0
  118. package/docs/versions.md +49 -0
  119. package/expansion-packs/README.md +113 -0
  120. package/expansion-packs/infrastructure-devops/README.md +147 -0
  121. package/expansion-packs/infrastructure-devops/agents/infra-devops-platform.md +59 -0
  122. package/expansion-packs/infrastructure-devops/checklists/infrastructure-checklist.md +484 -0
  123. package/expansion-packs/infrastructure-devops/manifest.yml +38 -0
  124. package/expansion-packs/infrastructure-devops/tasks/review-infrastructure.md +160 -0
  125. package/expansion-packs/infrastructure-devops/tasks/validate-infrastructure.md +154 -0
  126. package/expansion-packs/infrastructure-devops/templates/infrastructure-architecture-tmpl.md +415 -0
  127. package/expansion-packs/infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.md +0 -0
  128. package/package.json +73 -0
  129. package/tools/bmad-npx-wrapper.js +41 -0
  130. package/tools/builders/web-builder.js +145 -0
  131. package/tools/cli.js +119 -0
  132. package/tools/installer/README.md +58 -0
  133. package/tools/installer/bin/bmad.js +179 -0
  134. package/tools/installer/config/install.config.yml +139 -0
  135. package/tools/installer/lib/config-loader.js +89 -0
  136. package/tools/installer/lib/file-manager.js +169 -0
  137. package/tools/installer/lib/ide-setup.js +419 -0
  138. package/tools/installer/lib/installer.js +534 -0
  139. package/tools/installer/package-lock.json +704 -0
  140. package/tools/installer/package.json +43 -0
  141. package/tools/installer/templates/claude-commands.md +7 -0
  142. package/tools/installer/templates/cursor-rules.md +22 -0
  143. package/tools/installer/templates/windsurf-rules.md +22 -0
  144. package/tools/lib/dependency-resolver.js +179 -0
  145. package/tools/upgraders/v3-to-v4-upgrader.js +766 -0
  146. package/tools/version-bump.js +72 -0
  147. package/tools/yaml-format.js +211 -0
@@ -0,0 +1,766 @@
1
+ const fs = require("fs").promises;
2
+ const path = require("path");
3
+ const chalk = require("chalk");
4
+ const ora = require("ora");
5
+ const glob = require("glob");
6
+ const inquirer = require("inquirer");
7
+ const { promisify } = require("util");
8
+ const globAsync = promisify(glob);
9
+
10
+ class V3ToV4Upgrader {
11
+ constructor() {
12
+ // Constructor remains empty
13
+ }
14
+
15
+ async upgrade(options = {}) {
16
+ try {
17
+ // Keep readline open throughout the process
18
+ process.stdin.resume();
19
+
20
+ // 1. Welcome message
21
+ console.log(
22
+ chalk.bold("\nWelcome to BMAD-METHOD V3 to V4 Upgrade Tool\n")
23
+ );
24
+ console.log(
25
+ "This tool will help you upgrade your BMAD-METHOD V3 project to V4.\n"
26
+ );
27
+ console.log(chalk.cyan("What this tool does:"));
28
+ console.log("- Creates a backup of your V3 files (.bmad-v3-backup/)");
29
+ console.log("- Installs the new V4 .bmad-core structure");
30
+ console.log(
31
+ "- Preserves your PRD, Architecture, and Stories in the new format\n"
32
+ );
33
+ console.log(chalk.yellow("What this tool does NOT do:"));
34
+ console.log(
35
+ "- Modify your document content (use doc-migration-task after upgrade)"
36
+ );
37
+ console.log("- Touch any files outside bmad-agent/ and docs/\n");
38
+
39
+ // 2. Get project path
40
+ const projectPath = await this.getProjectPath(options.projectPath);
41
+
42
+ // 3. Validate V3 structure
43
+ const validation = await this.validateV3Project(projectPath);
44
+ if (!validation.isValid) {
45
+ console.error(
46
+ chalk.red("\nError: This doesn't appear to be a V3 project.")
47
+ );
48
+ console.error("Expected to find:");
49
+ console.error("- bmad-agent/ directory");
50
+ console.error("- docs/ directory\n");
51
+ console.error(
52
+ "Please check you're in the correct directory and try again."
53
+ );
54
+ return;
55
+ }
56
+
57
+ // 4. Pre-flight check
58
+ const analysis = await this.analyzeProject(projectPath);
59
+ await this.showPreflightCheck(analysis, options);
60
+
61
+ if (!options.dryRun) {
62
+ const { confirm } = await inquirer.prompt([
63
+ {
64
+ type: "confirm",
65
+ name: "confirm",
66
+ message: "Continue with upgrade?",
67
+ default: true,
68
+ },
69
+ ]);
70
+
71
+ if (!confirm) {
72
+ console.log("Upgrade cancelled.");
73
+ return;
74
+ }
75
+ }
76
+
77
+ // 5. Create backup
78
+ if (options.backup !== false && !options.dryRun) {
79
+ await this.createBackup(projectPath);
80
+ }
81
+
82
+ // 6. Install V4 structure
83
+ if (!options.dryRun) {
84
+ await this.installV4Structure(projectPath);
85
+ }
86
+
87
+ // 7. Migrate documents
88
+ if (!options.dryRun) {
89
+ await this.migrateDocuments(projectPath, analysis);
90
+ }
91
+
92
+ // 8. Setup IDE
93
+ if (!options.dryRun) {
94
+ await this.setupIDE(projectPath);
95
+ }
96
+
97
+ // 9. Show completion report
98
+ this.showCompletionReport(projectPath, analysis);
99
+
100
+ process.exit(0);
101
+ } catch (error) {
102
+ console.error(chalk.red("\nUpgrade error:"), error.message);
103
+ process.exit(1);
104
+ }
105
+ }
106
+
107
+ async getProjectPath(providedPath) {
108
+ if (providedPath) {
109
+ return path.resolve(providedPath);
110
+ }
111
+
112
+ const { projectPath } = await inquirer.prompt([
113
+ {
114
+ type: "input",
115
+ name: "projectPath",
116
+ message: "Please enter the path to your V3 project:",
117
+ default: process.cwd(),
118
+ },
119
+ ]);
120
+
121
+ return path.resolve(projectPath);
122
+ }
123
+
124
+ async validateV3Project(projectPath) {
125
+ const spinner = ora("Validating project structure...").start();
126
+
127
+ try {
128
+ const bmadAgentPath = path.join(projectPath, "bmad-agent");
129
+ const docsPath = path.join(projectPath, "docs");
130
+
131
+ const hasBmadAgent = await this.pathExists(bmadAgentPath);
132
+ const hasDocs = await this.pathExists(docsPath);
133
+
134
+ if (hasBmadAgent) {
135
+ spinner.text = "✓ Found bmad-agent/ directory";
136
+ console.log(chalk.green("\n✓ Found bmad-agent/ directory"));
137
+ }
138
+
139
+ if (hasDocs) {
140
+ console.log(chalk.green("✓ Found docs/ directory"));
141
+ }
142
+
143
+ const isValid = hasBmadAgent && hasDocs;
144
+
145
+ if (isValid) {
146
+ spinner.succeed("This appears to be a valid V3 project");
147
+ } else {
148
+ spinner.fail("Invalid V3 project structure");
149
+ }
150
+
151
+ return { isValid, hasBmadAgent, hasDocs };
152
+ } catch (error) {
153
+ spinner.fail("Validation failed");
154
+ throw error;
155
+ }
156
+ }
157
+
158
+ async analyzeProject(projectPath) {
159
+ const docsPath = path.join(projectPath, "docs");
160
+ const bmadAgentPath = path.join(projectPath, "bmad-agent");
161
+
162
+ // Find PRD
163
+ const prdCandidates = ["prd.md", "PRD.md", "product-requirements.md"];
164
+ let prdFile = null;
165
+ for (const candidate of prdCandidates) {
166
+ const candidatePath = path.join(docsPath, candidate);
167
+ if (await this.pathExists(candidatePath)) {
168
+ prdFile = candidate;
169
+ break;
170
+ }
171
+ }
172
+
173
+ // Find Architecture
174
+ const archCandidates = [
175
+ "architecture.md",
176
+ "Architecture.md",
177
+ "technical-architecture.md",
178
+ ];
179
+ let archFile = null;
180
+ for (const candidate of archCandidates) {
181
+ const candidatePath = path.join(docsPath, candidate);
182
+ if (await this.pathExists(candidatePath)) {
183
+ archFile = candidate;
184
+ break;
185
+ }
186
+ }
187
+
188
+ // Find Front-end Architecture (V3 specific)
189
+ const frontEndCandidates = [
190
+ "front-end-architecture.md",
191
+ "frontend-architecture.md",
192
+ "ui-architecture.md",
193
+ ];
194
+ let frontEndArchFile = null;
195
+ for (const candidate of frontEndCandidates) {
196
+ const candidatePath = path.join(docsPath, candidate);
197
+ if (await this.pathExists(candidatePath)) {
198
+ frontEndArchFile = candidate;
199
+ break;
200
+ }
201
+ }
202
+
203
+ // Find UX/UI spec
204
+ const uxSpecCandidates = [
205
+ "ux-ui-spec.md",
206
+ "ux-ui-specification.md",
207
+ "ui-spec.md",
208
+ "ux-spec.md",
209
+ ];
210
+ let uxSpecFile = null;
211
+ for (const candidate of uxSpecCandidates) {
212
+ const candidatePath = path.join(docsPath, candidate);
213
+ if (await this.pathExists(candidatePath)) {
214
+ uxSpecFile = candidate;
215
+ break;
216
+ }
217
+ }
218
+
219
+ // Find v0 prompt or UX prompt
220
+ const uxPromptCandidates = [
221
+ "v0-prompt.md",
222
+ "ux-prompt.md",
223
+ "ui-prompt.md",
224
+ "design-prompt.md",
225
+ ];
226
+ let uxPromptFile = null;
227
+ for (const candidate of uxPromptCandidates) {
228
+ const candidatePath = path.join(docsPath, candidate);
229
+ if (await this.pathExists(candidatePath)) {
230
+ uxPromptFile = candidate;
231
+ break;
232
+ }
233
+ }
234
+
235
+ // Find epic files
236
+ const epicFiles = await globAsync("epic*.md", { cwd: docsPath });
237
+
238
+ // Find story files
239
+ const storiesPath = path.join(docsPath, "stories");
240
+ let storyFiles = [];
241
+ if (await this.pathExists(storiesPath)) {
242
+ storyFiles = await globAsync("*.md", { cwd: storiesPath });
243
+ }
244
+
245
+ // Count custom files in bmad-agent
246
+ const bmadAgentFiles = await globAsync("**/*.md", {
247
+ cwd: bmadAgentPath,
248
+ ignore: ["node_modules/**"],
249
+ });
250
+
251
+ return {
252
+ prdFile,
253
+ archFile,
254
+ frontEndArchFile,
255
+ uxSpecFile,
256
+ uxPromptFile,
257
+ epicFiles,
258
+ storyFiles,
259
+ customFileCount: bmadAgentFiles.length,
260
+ };
261
+ }
262
+
263
+ async showPreflightCheck(analysis, options) {
264
+ console.log(chalk.bold("\nProject Analysis:"));
265
+ console.log(
266
+ `- PRD found: ${
267
+ analysis.prdFile
268
+ ? `docs/${analysis.prdFile}`
269
+ : chalk.yellow("Not found")
270
+ }`
271
+ );
272
+ console.log(
273
+ `- Architecture found: ${
274
+ analysis.archFile
275
+ ? `docs/${analysis.archFile}`
276
+ : chalk.yellow("Not found")
277
+ }`
278
+ );
279
+ if (analysis.frontEndArchFile) {
280
+ console.log(
281
+ `- Front-end Architecture found: docs/${analysis.frontEndArchFile}`
282
+ );
283
+ }
284
+ console.log(
285
+ `- UX/UI Spec found: ${
286
+ analysis.uxSpecFile
287
+ ? `docs/${analysis.uxSpecFile}`
288
+ : chalk.yellow("Not found")
289
+ }`
290
+ );
291
+ console.log(
292
+ `- UX/Design Prompt found: ${
293
+ analysis.uxPromptFile
294
+ ? `docs/${analysis.uxPromptFile}`
295
+ : chalk.yellow("Not found")
296
+ }`
297
+ );
298
+ console.log(
299
+ `- Epic files found: ${analysis.epicFiles.length} files (epic*.md)`
300
+ );
301
+ console.log(
302
+ `- Stories found: ${analysis.storyFiles.length} files in docs/stories/`
303
+ );
304
+ console.log(`- Custom files in bmad-agent/: ${analysis.customFileCount}`);
305
+
306
+ if (!options.dryRun) {
307
+ console.log("\nThe following will be backed up to .bmad-v3-backup/:");
308
+ console.log("- bmad-agent/ (entire directory)");
309
+ console.log("- docs/ (entire directory)");
310
+
311
+ if (analysis.epicFiles.length > 0) {
312
+ console.log(
313
+ chalk.green(
314
+ "\nNote: Epic files found! They will be placed in docs/prd/ with an index.md file."
315
+ )
316
+ );
317
+ console.log(
318
+ chalk.green(
319
+ "Since epic files exist, you won't need to shard the PRD after upgrade."
320
+ )
321
+ );
322
+ }
323
+ }
324
+ }
325
+
326
+ async createBackup(projectPath) {
327
+ const spinner = ora("Creating backup...").start();
328
+
329
+ try {
330
+ const backupPath = path.join(projectPath, ".bmad-v3-backup");
331
+
332
+ // Check if backup already exists
333
+ if (await this.pathExists(backupPath)) {
334
+ spinner.fail("Backup directory already exists");
335
+ console.error(
336
+ chalk.red(
337
+ "\nError: Backup directory .bmad-v3-backup/ already exists."
338
+ )
339
+ );
340
+ console.error("\nThis might mean an upgrade was already attempted.");
341
+ console.error(
342
+ "Please remove or rename the existing backup and try again."
343
+ );
344
+ throw new Error("Backup already exists");
345
+ }
346
+
347
+ // Create backup directory
348
+ await fs.mkdir(backupPath, { recursive: true });
349
+ spinner.text = "✓ Created .bmad-v3-backup/";
350
+ console.log(chalk.green("\n✓ Created .bmad-v3-backup/"));
351
+
352
+ // Move bmad-agent
353
+ const bmadAgentSrc = path.join(projectPath, "bmad-agent");
354
+ const bmadAgentDest = path.join(backupPath, "bmad-agent");
355
+ await fs.rename(bmadAgentSrc, bmadAgentDest);
356
+ console.log(chalk.green("✓ Moved bmad-agent/ to backup"));
357
+
358
+ // Move docs
359
+ const docsSrc = path.join(projectPath, "docs");
360
+ const docsDest = path.join(backupPath, "docs");
361
+ await fs.rename(docsSrc, docsDest);
362
+ console.log(chalk.green("✓ Moved docs/ to backup"));
363
+
364
+ spinner.succeed("Backup created successfully");
365
+ } catch (error) {
366
+ spinner.fail("Backup failed");
367
+ throw error;
368
+ }
369
+ }
370
+
371
+ async installV4Structure(projectPath) {
372
+ const spinner = ora("Installing V4 structure...").start();
373
+
374
+ try {
375
+ // Get the source .bmad-core directory
376
+ const sourcePath = path.join(__dirname, "..", "..", ".bmad-core");
377
+ const destPath = path.join(projectPath, ".bmad-core");
378
+
379
+ // Copy .bmad-core
380
+ await this.copyDirectory(sourcePath, destPath);
381
+ spinner.text = "✓ Copied fresh .bmad-core/ directory from V4";
382
+ console.log(
383
+ chalk.green("\n✓ Copied fresh .bmad-core/ directory from V4")
384
+ );
385
+
386
+ // Create docs directory
387
+ const docsPath = path.join(projectPath, "docs");
388
+ await fs.mkdir(docsPath, { recursive: true });
389
+ console.log(chalk.green("✓ Created new docs/ directory"));
390
+
391
+ // Create install manifest for future updates
392
+ await this.createInstallManifest(projectPath);
393
+ console.log(chalk.green("✓ Created install manifest"));
394
+
395
+ console.log(
396
+ chalk.yellow(
397
+ "\nNote: Your V3 bmad-agent content has been backed up and NOT migrated."
398
+ )
399
+ );
400
+ console.log(
401
+ chalk.yellow(
402
+ "The new V4 agents are completely different and look for different file structures."
403
+ )
404
+ );
405
+
406
+ spinner.succeed("V4 structure installed successfully");
407
+ } catch (error) {
408
+ spinner.fail("V4 installation failed");
409
+ throw error;
410
+ }
411
+ }
412
+
413
+ async migrateDocuments(projectPath, analysis) {
414
+ const spinner = ora("Migrating your project documents...").start();
415
+
416
+ try {
417
+ const backupDocsPath = path.join(projectPath, ".bmad-v3-backup", "docs");
418
+ const newDocsPath = path.join(projectPath, "docs");
419
+ let copiedCount = 0;
420
+
421
+ // Copy PRD
422
+ if (analysis.prdFile) {
423
+ const src = path.join(backupDocsPath, analysis.prdFile);
424
+ const dest = path.join(newDocsPath, analysis.prdFile);
425
+ await fs.copyFile(src, dest);
426
+ console.log(chalk.green(`\n✓ Copied PRD to docs/${analysis.prdFile}`));
427
+ copiedCount++;
428
+ }
429
+
430
+ // Copy Architecture
431
+ if (analysis.archFile) {
432
+ const src = path.join(backupDocsPath, analysis.archFile);
433
+ const dest = path.join(newDocsPath, analysis.archFile);
434
+ await fs.copyFile(src, dest);
435
+ console.log(
436
+ chalk.green(`✓ Copied Architecture to docs/${analysis.archFile}`)
437
+ );
438
+ copiedCount++;
439
+ }
440
+
441
+ // Copy Front-end Architecture if exists
442
+ if (analysis.frontEndArchFile) {
443
+ const src = path.join(backupDocsPath, analysis.frontEndArchFile);
444
+ const dest = path.join(newDocsPath, analysis.frontEndArchFile);
445
+ await fs.copyFile(src, dest);
446
+ console.log(
447
+ chalk.green(
448
+ `✓ Copied Front-end Architecture to docs/${analysis.frontEndArchFile}`
449
+ )
450
+ );
451
+ console.log(
452
+ chalk.yellow(
453
+ "Note: V4 uses a single full-stack-architecture.md - use doc-migration-task to merge"
454
+ )
455
+ );
456
+ copiedCount++;
457
+ }
458
+
459
+ // Copy UX/UI Spec if exists
460
+ if (analysis.uxSpecFile) {
461
+ const src = path.join(backupDocsPath, analysis.uxSpecFile);
462
+ const dest = path.join(newDocsPath, analysis.uxSpecFile);
463
+ await fs.copyFile(src, dest);
464
+ console.log(
465
+ chalk.green(`✓ Copied UX/UI Spec to docs/${analysis.uxSpecFile}`)
466
+ );
467
+ copiedCount++;
468
+ }
469
+
470
+ // Copy UX/Design Prompt if exists
471
+ if (analysis.uxPromptFile) {
472
+ const src = path.join(backupDocsPath, analysis.uxPromptFile);
473
+ const dest = path.join(newDocsPath, analysis.uxPromptFile);
474
+ await fs.copyFile(src, dest);
475
+ console.log(
476
+ chalk.green(
477
+ `✓ Copied UX/Design Prompt to docs/${analysis.uxPromptFile}`
478
+ )
479
+ );
480
+ copiedCount++;
481
+ }
482
+
483
+ // Copy stories
484
+ if (analysis.storyFiles.length > 0) {
485
+ const storiesDir = path.join(newDocsPath, "stories");
486
+ await fs.mkdir(storiesDir, { recursive: true });
487
+
488
+ for (const storyFile of analysis.storyFiles) {
489
+ const src = path.join(backupDocsPath, "stories", storyFile);
490
+ const dest = path.join(storiesDir, storyFile);
491
+ await fs.copyFile(src, dest);
492
+ }
493
+ console.log(
494
+ chalk.green(
495
+ `✓ Copied ${analysis.storyFiles.length} story files to docs/stories/`
496
+ )
497
+ );
498
+ copiedCount += analysis.storyFiles.length;
499
+ }
500
+
501
+ // Copy epic files to prd subfolder
502
+ if (analysis.epicFiles.length > 0) {
503
+ const prdDir = path.join(newDocsPath, "prd");
504
+ await fs.mkdir(prdDir, { recursive: true });
505
+
506
+ for (const epicFile of analysis.epicFiles) {
507
+ const src = path.join(backupDocsPath, epicFile);
508
+ const dest = path.join(prdDir, epicFile);
509
+ await fs.copyFile(src, dest);
510
+ }
511
+ console.log(
512
+ chalk.green(
513
+ `✓ Found and copied ${analysis.epicFiles.length} epic files to docs/prd/`
514
+ )
515
+ );
516
+
517
+ // Create index.md for the prd folder
518
+ await this.createPrdIndex(projectPath, analysis);
519
+ console.log(chalk.green("✓ Created index.md in docs/prd/"));
520
+
521
+ console.log(
522
+ chalk.green(
523
+ "\nNote: Epic files detected! These are compatible with V4 and have been copied."
524
+ )
525
+ );
526
+ console.log(
527
+ chalk.green(
528
+ "You won't need to shard the PRD since epics already exist."
529
+ )
530
+ );
531
+ copiedCount += analysis.epicFiles.length;
532
+ }
533
+
534
+ spinner.succeed(`Migrated ${copiedCount} documents successfully`);
535
+ } catch (error) {
536
+ spinner.fail("Document migration failed");
537
+ throw error;
538
+ }
539
+ }
540
+
541
+ async setupIDE(projectPath) {
542
+ const { ide } = await inquirer.prompt([
543
+ {
544
+ type: "list",
545
+ name: "ide",
546
+ message: "Which IDE are you using?",
547
+ choices: [
548
+ { name: "Cursor", value: "cursor" },
549
+ { name: "Claude Code", value: "claude-code" },
550
+ { name: "Windsurf", value: "windsurf" },
551
+ { name: "Roo Code", value: "roo" },
552
+ { name: "VS Code", value: "skip" },
553
+ { name: "Other/Skip", value: "skip" },
554
+ ],
555
+ },
556
+ ]);
557
+
558
+ const selectedIde = ide === "skip" ? null : ide;
559
+
560
+ if (selectedIde) {
561
+ const ideSetup = require("../installer/lib/ide-setup");
562
+ const spinner = ora("Setting up IDE rules for all agents...").start();
563
+
564
+ try {
565
+ await ideSetup.setup(selectedIde, projectPath);
566
+ spinner.succeed("IDE setup complete!");
567
+
568
+ const ideMessages = {
569
+ cursor: "Rules created in .cursor/rules/",
570
+ "claude-code": "Commands created in .claude/commands/",
571
+ windsurf: "Rules created in .windsurf/rules/",
572
+ roo: "Custom modes created in .roomodes",
573
+ };
574
+
575
+ console.log(chalk.green(`- ${ideMessages[selectedIde]}`));
576
+ } catch (error) {
577
+ spinner.fail("IDE setup failed");
578
+ console.error(
579
+ chalk.yellow("IDE setup failed, but upgrade is complete.")
580
+ );
581
+ }
582
+ }
583
+ }
584
+
585
+ showCompletionReport(projectPath, analysis) {
586
+ console.log(chalk.bold.green("\n✓ Upgrade Complete!\n"));
587
+ console.log(chalk.bold("Summary:"));
588
+ console.log(`- V3 files backed up to: .bmad-v3-backup/`);
589
+ console.log(`- V4 structure installed: .bmad-core/ (fresh from V4)`);
590
+
591
+ const totalDocs =
592
+ (analysis.prdFile ? 1 : 0) +
593
+ (analysis.archFile ? 1 : 0) +
594
+ (analysis.frontEndArchFile ? 1 : 0) +
595
+ (analysis.uxSpecFile ? 1 : 0) +
596
+ (analysis.uxPromptFile ? 1 : 0) +
597
+ analysis.storyFiles.length;
598
+ console.log(
599
+ `- Documents migrated: ${totalDocs} files${
600
+ analysis.epicFiles.length > 0
601
+ ? ` + ${analysis.epicFiles.length} epics`
602
+ : ""
603
+ }`
604
+ );
605
+
606
+ console.log(chalk.bold("\nImportant Changes:"));
607
+ console.log(
608
+ "- The V4 agents (sm, dev, etc.) expect different file structures than V3"
609
+ );
610
+ console.log(
611
+ "- Your V3 bmad-agent content was NOT migrated (it's incompatible)"
612
+ );
613
+ if (analysis.epicFiles.length > 0) {
614
+ console.log(
615
+ "- Epic files were found and copied - no PRD sharding needed!"
616
+ );
617
+ }
618
+ if (analysis.frontEndArchFile) {
619
+ console.log(
620
+ "- Front-end architecture found - V4 uses full-stack-architecture.md, migration needed"
621
+ );
622
+ }
623
+ if (analysis.uxSpecFile || analysis.uxPromptFile) {
624
+ console.log(
625
+ "- UX/UI design files found and copied - ready for use with V4"
626
+ );
627
+ }
628
+
629
+ console.log(chalk.bold("\nNext Steps:"));
630
+ console.log("1. Review your documents in the new docs/ folder");
631
+ console.log(
632
+ "2. Use @bmad-master agent to run the doc-migration-task to align your documents with V4 templates"
633
+ );
634
+ if (analysis.epicFiles.length === 0) {
635
+ console.log(
636
+ "3. Use @bmad-master agent to shard the PRD to create epic files"
637
+ );
638
+ }
639
+
640
+ console.log(
641
+ chalk.dim(
642
+ "\nYour V3 backup is preserved in .bmad-v3-backup/ and can be restored if needed."
643
+ )
644
+ );
645
+ }
646
+
647
+ async pathExists(filePath) {
648
+ try {
649
+ await fs.access(filePath);
650
+ return true;
651
+ } catch {
652
+ return false;
653
+ }
654
+ }
655
+
656
+ async copyDirectory(src, dest) {
657
+ await fs.mkdir(dest, { recursive: true });
658
+ const entries = await fs.readdir(src, { withFileTypes: true });
659
+
660
+ for (const entry of entries) {
661
+ const srcPath = path.join(src, entry.name);
662
+ const destPath = path.join(dest, entry.name);
663
+
664
+ if (entry.isDirectory()) {
665
+ await this.copyDirectory(srcPath, destPath);
666
+ } else {
667
+ await fs.copyFile(srcPath, destPath);
668
+ }
669
+ }
670
+ }
671
+
672
+ async createPrdIndex(projectPath, analysis) {
673
+ const prdIndexPath = path.join(projectPath, "docs", "prd", "index.md");
674
+ const prdPath = path.join(
675
+ projectPath,
676
+ "docs",
677
+ analysis.prdFile || "prd.md"
678
+ );
679
+
680
+ let indexContent = "# Product Requirements Document\n\n";
681
+
682
+ // Try to read the PRD to get the title and intro content
683
+ if (analysis.prdFile && (await this.pathExists(prdPath))) {
684
+ try {
685
+ const prdContent = await fs.readFile(prdPath, "utf8");
686
+ const lines = prdContent.split("\n");
687
+
688
+ // Find the first heading
689
+ const titleMatch = lines.find((line) => line.startsWith("# "));
690
+ if (titleMatch) {
691
+ indexContent = titleMatch + "\n\n";
692
+ }
693
+
694
+ // Get any content before the first ## section
695
+ let introContent = "";
696
+ let foundFirstSection = false;
697
+ for (const line of lines) {
698
+ if (line.startsWith("## ")) {
699
+ foundFirstSection = true;
700
+ break;
701
+ }
702
+ if (!line.startsWith("# ")) {
703
+ introContent += line + "\n";
704
+ }
705
+ }
706
+
707
+ if (introContent.trim()) {
708
+ indexContent += introContent.trim() + "\n\n";
709
+ }
710
+ } catch (error) {
711
+ // If we can't read the PRD, just use default content
712
+ }
713
+ }
714
+
715
+ // Add sections list
716
+ indexContent += "## Sections\n\n";
717
+
718
+ // Sort epic files for consistent ordering
719
+ const sortedEpics = [...analysis.epicFiles].sort();
720
+
721
+ for (const epicFile of sortedEpics) {
722
+ // Extract epic name from filename
723
+ const epicName = epicFile
724
+ .replace(/\.md$/, "")
725
+ .replace(/^epic-?/i, "")
726
+ .replace(/-/g, " ")
727
+ .replace(/^\d+\s*/, "") // Remove leading numbers
728
+ .trim();
729
+
730
+ const displayName = epicName.charAt(0).toUpperCase() + epicName.slice(1);
731
+ indexContent += `- [${
732
+ displayName || epicFile.replace(".md", "")
733
+ }](./${epicFile})\n`;
734
+ }
735
+
736
+ await fs.writeFile(prdIndexPath, indexContent);
737
+ }
738
+
739
+ async createInstallManifest(projectPath) {
740
+ const fileManager = require("../installer/lib/file-manager");
741
+ const glob = require("glob");
742
+ const { promisify } = require("util");
743
+ const globAsync = promisify(glob);
744
+
745
+ // Get all files in .bmad-core for the manifest
746
+ const bmadCorePath = path.join(projectPath, ".bmad-core");
747
+ const files = await globAsync("**/*", {
748
+ cwd: bmadCorePath,
749
+ nodir: true,
750
+ ignore: ["**/.git/**", "**/node_modules/**"],
751
+ });
752
+
753
+ // Prepend .bmad-core/ to file paths for manifest
754
+ const manifestFiles = files.map((file) => path.join(".bmad-core", file));
755
+
756
+ const config = {
757
+ installType: "full",
758
+ agent: null,
759
+ ide: null, // Will be set if IDE setup is done later
760
+ };
761
+
762
+ await fileManager.createManifest(projectPath, config, manifestFiles);
763
+ }
764
+ }
765
+
766
+ module.exports = V3ToV4Upgrader;