bmad-method 4.27.6 → 5.0.0

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 (274) 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 → .bmad-core}/agents/analyst.md +23 -29
  5. package/.bmad-core/agents/architect.md +66 -0
  6. package/.bmad-core/agents/bmad-master.md +104 -0
  7. package/.bmad-core/agents/bmad-orchestrator.md +81 -0
  8. package/.bmad-core/agents/dev.md +70 -0
  9. package/{bmad-core → .bmad-core}/agents/pm.md +24 -24
  10. package/{bmad-core → .bmad-core}/agents/po.md +24 -27
  11. package/.bmad-core/agents/qa.md +52 -0
  12. package/.bmad-core/agents/sm.md +55 -0
  13. package/.bmad-core/agents/ux-expert.md +66 -0
  14. package/{bmad-core → .bmad-core}/checklists/change-checklist.md +2 -2
  15. package/{bmad-core → .bmad-core}/checklists/story-draft-checklist.md +1 -1
  16. package/.bmad-core/data/bmad-kb.md +47 -0
  17. package/.bmad-core/schemas/agent-team-schema.yml +153 -0
  18. package/.bmad-core/tasks/advanced-elicitation.md +92 -0
  19. package/.bmad-core/tasks/brainstorming-techniques.md +238 -0
  20. package/.bmad-core/tasks/core-dump.md +74 -0
  21. package/{expansion-packs/bmad-creator-tools → .bmad-core}/tasks/create-agent.md +11 -9
  22. package/.bmad-core/tasks/create-doc.md +74 -0
  23. package/.bmad-core/tasks/create-expansion-pack.md +425 -0
  24. package/.bmad-core/tasks/create-next-story.md +206 -0
  25. package/.bmad-core/tasks/create-team.md +229 -0
  26. package/{bmad-core → .bmad-core}/tasks/doc-migration-task.md +9 -9
  27. package/{common → .bmad-core}/tasks/execute-checklist.md +6 -2
  28. package/.bmad-core/tasks/generate-ai-frontend-prompt.md +58 -0
  29. package/{bmad-core → .bmad-core}/tasks/index-docs.md +7 -3
  30. package/{bmad-core → .bmad-core}/tasks/shard-doc.md +7 -25
  31. package/.bmad-core/templates/agent-tmpl.md +58 -0
  32. package/.bmad-core/templates/architecture-tmpl.md +771 -0
  33. package/.bmad-core/templates/brownfield-architecture-tmpl.md +542 -0
  34. package/.bmad-core/templates/brownfield-prd-tmpl.md +240 -0
  35. package/.bmad-core/templates/competitor-analysis-tmpl.md +289 -0
  36. package/.bmad-core/templates/expansion-pack-plan-tmpl.md +91 -0
  37. package/.bmad-core/templates/front-end-architecture-tmpl.md +173 -0
  38. package/.bmad-core/templates/front-end-spec-tmpl.md +411 -0
  39. package/.bmad-core/templates/fullstack-architecture-tmpl.md +1016 -0
  40. package/.bmad-core/templates/market-research-tmpl.md +261 -0
  41. package/.bmad-core/templates/prd-tmpl.md +200 -0
  42. package/.bmad-core/templates/project-brief-tmpl.md +228 -0
  43. package/.bmad-core/templates/simple-project-prd-tmpl.md +461 -0
  44. package/.bmad-core/templates/story-tmpl.md +61 -0
  45. package/.bmad-core/templates/web-agent-startup-instructions-template.md +39 -0
  46. package/.bmad-core/utils/agent-switcher.ide.md +112 -0
  47. package/.bmad-core/utils/template-format.md +26 -0
  48. package/.bmad-core/utils/workflow-management.md +224 -0
  49. package/.bmad-core/web-bundles/agents/analyst.txt +1684 -0
  50. package/.bmad-core/web-bundles/agents/architect.txt +3584 -0
  51. package/.bmad-core/web-bundles/agents/bmad-master.txt +9491 -0
  52. package/.bmad-core/web-bundles/agents/bmad-orchestrator.txt +1466 -0
  53. package/{dist → .bmad-core/web-bundles}/agents/dev.txt +71 -179
  54. package/{dist → .bmad-core/web-bundles}/agents/pm.txt +1058 -624
  55. package/{dist → .bmad-core/web-bundles}/agents/po.txt +138 -337
  56. package/.bmad-core/web-bundles/agents/qa.txt +129 -0
  57. package/.bmad-core/web-bundles/agents/sm.txt +658 -0
  58. package/.bmad-core/web-bundles/agents/ux-expert.txt +1099 -0
  59. package/.bmad-core/web-bundles/teams/team-all.txt +10757 -0
  60. package/.bmad-core/web-bundles/teams/team-fullstack.txt +10109 -0
  61. package/.bmad-core/web-bundles/teams/team-no-ui.txt +8950 -0
  62. package/.bmad-core/workflows/brownfield-fullstack.yml +116 -0
  63. package/.bmad-core/workflows/brownfield-service.yml +117 -0
  64. package/.bmad-core/workflows/brownfield-ui.yml +127 -0
  65. package/.bmad-core/workflows/greenfield-fullstack.yml +177 -0
  66. package/.bmad-core/workflows/greenfield-service.yml +143 -0
  67. package/.bmad-core/workflows/greenfield-ui.yml +172 -0
  68. package/.claude/commands/analyst.md +63 -0
  69. package/.claude/commands/architect.md +70 -0
  70. package/.claude/commands/bmad-master.md +108 -0
  71. package/.claude/commands/bmad-orchestrator.md +85 -0
  72. package/.claude/commands/dev.md +74 -0
  73. package/.claude/commands/pm.md +63 -0
  74. package/.claude/commands/po.md +64 -0
  75. package/.claude/commands/qa.md +56 -0
  76. package/.claude/commands/sm.md +59 -0
  77. package/.claude/commands/ux-expert.md +70 -0
  78. package/.cursor/rules/analyst.mdc +77 -0
  79. package/.cursor/rules/architect.mdc +84 -0
  80. package/.cursor/rules/bmad-master.mdc +122 -0
  81. package/.cursor/rules/bmad-orchestrator.mdc +99 -0
  82. package/.cursor/rules/dev.mdc +88 -0
  83. package/.cursor/rules/pm.mdc +77 -0
  84. package/.cursor/rules/po.mdc +78 -0
  85. package/.cursor/rules/qa.mdc +70 -0
  86. package/.cursor/rules/sm.mdc +73 -0
  87. package/.cursor/rules/ux-expert.mdc +84 -0
  88. package/.roo/.roomodes +95 -0
  89. package/.roo/README.md +38 -0
  90. package/.vscode/extensions.json +6 -0
  91. package/.vscode/settings.json +75 -49
  92. package/.windsurf/rules/analyst.md +71 -0
  93. package/.windsurf/rules/architect.md +78 -0
  94. package/.windsurf/rules/bmad-master.md +116 -0
  95. package/.windsurf/rules/bmad-orchestrator.md +93 -0
  96. package/.windsurf/rules/dev.md +82 -0
  97. package/.windsurf/rules/pm.md +71 -0
  98. package/.windsurf/rules/po.md +72 -0
  99. package/.windsurf/rules/qa.md +64 -0
  100. package/.windsurf/rules/sm.md +67 -0
  101. package/.windsurf/rules/ux-expert.md +78 -0
  102. package/CHANGELOG.md +16 -459
  103. package/CONTRIBUTING.md +5 -168
  104. package/LICENSE +1 -1
  105. package/README.md +230 -77
  106. package/docs/bmad-workflow-guide.md +15 -19
  107. package/docs/claude-code-guide.md +119 -0
  108. package/docs/cursor-guide.md +127 -0
  109. package/docs/roo-code-guide.md +140 -0
  110. package/docs/sample-output/simple-fullstack-greenfield/prd.md +42 -0
  111. package/docs/versioning-and-releases.md +16 -8
  112. package/docs/versions.md +5 -4
  113. package/docs/windsurf-guide.md +127 -0
  114. package/expansion-packs/README.md +112 -2
  115. package/expansion-packs/{bmad-infrastructure-devops → infrastructure-devops}/README.md +9 -9
  116. package/expansion-packs/{bmad-infrastructure-devops → infrastructure-devops}/agents/infra-devops-platform.md +15 -14
  117. package/expansion-packs/{bmad-infrastructure-devops → infrastructure-devops}/checklists/infrastructure-checklist.md +1 -1
  118. package/expansion-packs/infrastructure-devops/manifest.yml +38 -0
  119. package/expansion-packs/{bmad-infrastructure-devops → infrastructure-devops}/tasks/review-infrastructure.md +4 -4
  120. package/expansion-packs/{bmad-infrastructure-devops → infrastructure-devops}/tasks/validate-infrastructure.md +4 -4
  121. package/expansion-packs/infrastructure-devops/templates/infrastructure-architecture-tmpl.md +415 -0
  122. package/expansion-packs/infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.md +0 -0
  123. package/package.json +11 -19
  124. package/tools/bmad-npx-wrapper.js +1 -1
  125. package/tools/builders/web-builder.js +28 -563
  126. package/tools/cli.js +22 -55
  127. package/tools/installer/README.md +53 -3
  128. package/tools/installer/bin/bmad.js +56 -294
  129. package/tools/installer/config/install.config.yml +139 -0
  130. package/tools/installer/lib/config-loader.js +34 -198
  131. package/tools/installer/lib/file-manager.js +7 -200
  132. package/tools/installer/lib/ide-setup.js +189 -545
  133. package/tools/installer/lib/installer.js +61 -1171
  134. package/tools/installer/package-lock.json +3 -3
  135. package/tools/installer/package.json +4 -4
  136. package/tools/installer/templates/claude-commands.md +7 -0
  137. package/tools/installer/templates/cursor-rules.md +22 -0
  138. package/tools/installer/templates/windsurf-rules.md +22 -0
  139. package/tools/lib/dependency-resolver.js +22 -22
  140. package/tools/upgraders/v3-to-v4-upgrader.js +43 -35
  141. package/tools/version-bump.js +1 -1
  142. package/tools/yaml-format.js +2 -2
  143. package/.github/FUNDING.yaml +0 -15
  144. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
  145. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -22
  146. package/.prettierignore +0 -21
  147. package/.prettierrc +0 -23
  148. package/bmad-core/agent-teams/team-all.yaml +0 -14
  149. package/bmad-core/agent-teams/team-fullstack.yaml +0 -18
  150. package/bmad-core/agent-teams/team-ide-minimal.yaml +0 -10
  151. package/bmad-core/agent-teams/team-no-ui.yaml +0 -13
  152. package/bmad-core/agents/architect.md +0 -62
  153. package/bmad-core/agents/bmad-master.md +0 -88
  154. package/bmad-core/agents/bmad-orchestrator.md +0 -135
  155. package/bmad-core/agents/dev.md +0 -56
  156. package/bmad-core/agents/qa.md +0 -54
  157. package/bmad-core/agents/sm.md +0 -45
  158. package/bmad-core/agents/ux-expert.md +0 -53
  159. package/bmad-core/core-config.yaml +0 -25
  160. package/bmad-core/data/bmad-kb.md +0 -803
  161. package/bmad-core/data/brainstorming-techniques.md +0 -36
  162. package/bmad-core/data/elicitation-methods.md +0 -134
  163. package/bmad-core/tasks/advanced-elicitation.md +0 -117
  164. package/bmad-core/tasks/create-brownfield-story.md +0 -355
  165. package/bmad-core/tasks/create-next-story.md +0 -113
  166. package/bmad-core/tasks/create-workflow-plan.md +0 -289
  167. package/bmad-core/tasks/document-project.md +0 -317
  168. package/bmad-core/tasks/facilitate-brainstorming-session.md +0 -136
  169. package/bmad-core/tasks/generate-ai-frontend-prompt.md +0 -51
  170. package/bmad-core/tasks/kb-mode-interaction.md +0 -70
  171. package/bmad-core/tasks/review-story.md +0 -145
  172. package/bmad-core/tasks/update-workflow-plan.md +0 -248
  173. package/bmad-core/tasks/validate-next-story.md +0 -134
  174. package/bmad-core/templates/architecture-tmpl.yaml +0 -650
  175. package/bmad-core/templates/brainstorming-output-tmpl.yaml +0 -156
  176. package/bmad-core/templates/brownfield-architecture-tmpl.yaml +0 -476
  177. package/bmad-core/templates/brownfield-prd-tmpl.yaml +0 -280
  178. package/bmad-core/templates/competitor-analysis-tmpl.yaml +0 -293
  179. package/bmad-core/templates/front-end-architecture-tmpl.yaml +0 -206
  180. package/bmad-core/templates/front-end-spec-tmpl.yaml +0 -349
  181. package/bmad-core/templates/fullstack-architecture-tmpl.yaml +0 -805
  182. package/bmad-core/templates/market-research-tmpl.yaml +0 -252
  183. package/bmad-core/templates/prd-tmpl.yaml +0 -202
  184. package/bmad-core/templates/project-brief-tmpl.yaml +0 -221
  185. package/bmad-core/templates/story-tmpl.yaml +0 -137
  186. package/bmad-core/workflows/brownfield-fullstack.yaml +0 -297
  187. package/bmad-core/workflows/brownfield-service.yaml +0 -187
  188. package/bmad-core/workflows/brownfield-ui.yaml +0 -197
  189. package/bmad-core/workflows/greenfield-fullstack.yaml +0 -240
  190. package/bmad-core/workflows/greenfield-service.yaml +0 -206
  191. package/bmad-core/workflows/greenfield-ui.yaml +0 -235
  192. package/common/tasks/create-doc.md +0 -79
  193. package/common/utils/bmad-doc-template.md +0 -325
  194. package/common/utils/workflow-management.md +0 -69
  195. package/dist/agents/analyst.txt +0 -2849
  196. package/dist/agents/architect.txt +0 -3505
  197. package/dist/agents/bmad-master.txt +0 -9271
  198. package/dist/agents/bmad-orchestrator.txt +0 -2006
  199. package/dist/agents/qa.txt +0 -388
  200. package/dist/agents/sm.txt +0 -672
  201. package/dist/agents/ux-expert.txt +0 -987
  202. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +0 -2401
  203. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.txt +0 -1635
  204. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.txt +0 -825
  205. package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +0 -11504
  206. package/dist/expansion-packs/bmad-creator-tools/agents/bmad-the-creator.txt +0 -2023
  207. package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +0 -2052
  208. package/dist/teams/team-all.txt +0 -11572
  209. package/dist/teams/team-fullstack.txt +0 -10903
  210. package/dist/teams/team-ide-minimal.txt +0 -4346
  211. package/dist/teams/team-no-ui.txt +0 -9458
  212. package/docs/GUIDING-PRINCIPLES.md +0 -91
  213. package/docs/agentic-tools/claude-code-guide.md +0 -19
  214. package/docs/agentic-tools/cline-guide.md +0 -16
  215. package/docs/agentic-tools/cursor-guide.md +0 -14
  216. package/docs/agentic-tools/gemini-cli-guide.md +0 -32
  217. package/docs/agentic-tools/github-copilot-guide.md +0 -42
  218. package/docs/agentic-tools/roo-code-guide.md +0 -15
  219. package/docs/agentic-tools/trae-guide.md +0 -14
  220. package/docs/agentic-tools/windsurf-guide.md +0 -14
  221. package/docs/core-architecture.md +0 -219
  222. package/docs/expansion-packs.md +0 -280
  223. package/docs/how-to-contribute-with-pull-requests.md +0 -158
  224. package/docs/template-markup-references.md +0 -86
  225. package/docs/user-guide.md +0 -1142
  226. package/docs/working-in-the-brownfield.md +0 -361
  227. package/expansion-packs/bmad-2d-phaser-game-dev/agent-teams/phaser-2d-nodejs-game-team.yaml +0 -13
  228. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.md +0 -59
  229. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.md +0 -67
  230. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.md +0 -52
  231. package/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-design-checklist.md +0 -201
  232. package/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-story-dod-checklist.md +0 -160
  233. package/expansion-packs/bmad-2d-phaser-game-dev/config.yaml +0 -7
  234. package/expansion-packs/bmad-2d-phaser-game-dev/data/bmad-kb.md +0 -254
  235. package/expansion-packs/bmad-2d-phaser-game-dev/data/development-guidelines.md +0 -651
  236. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/advanced-elicitation.md +0 -111
  237. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/create-game-story.md +0 -216
  238. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/game-design-brainstorming.md +0 -308
  239. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-architecture-tmpl.yaml +0 -613
  240. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-brief-tmpl.yaml +0 -356
  241. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-design-doc-tmpl.yaml +0 -343
  242. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-story-tmpl.yaml +0 -253
  243. package/expansion-packs/bmad-2d-phaser-game-dev/templates/level-design-doc-tmpl.yaml +0 -484
  244. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-dev-greenfield.yaml +0 -183
  245. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-prototype.yaml +0 -175
  246. package/expansion-packs/bmad-creator-tools/README.md +0 -8
  247. package/expansion-packs/bmad-creator-tools/agents/bmad-the-creator.md +0 -54
  248. package/expansion-packs/bmad-creator-tools/config.yaml +0 -5
  249. package/expansion-packs/bmad-creator-tools/tasks/generate-expansion-pack.md +0 -1020
  250. package/expansion-packs/bmad-creator-tools/templates/agent-teams-tmpl.yaml +0 -178
  251. package/expansion-packs/bmad-creator-tools/templates/agent-tmpl.yaml +0 -154
  252. package/expansion-packs/bmad-creator-tools/templates/expansion-pack-plan-tmpl.yaml +0 -120
  253. package/expansion-packs/bmad-infrastructure-devops/config.yaml +0 -8
  254. package/expansion-packs/bmad-infrastructure-devops/data/bmad-kb.md +0 -308
  255. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-architecture-tmpl.yaml +0 -424
  256. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.yaml +0 -629
  257. package/tools/bump-all-versions.js +0 -107
  258. package/tools/bump-core-version.js +0 -57
  259. package/tools/bump-expansion-version.js +0 -78
  260. package/tools/installer/config/ide-agent-config.yaml +0 -58
  261. package/tools/installer/config/install.config.yaml +0 -91
  262. package/tools/lib/yaml-utils.js +0 -29
  263. package/tools/md-assets/web-agent-startup-instructions.md +0 -39
  264. package/tools/update-expansion-version.js +0 -54
  265. /package/{bmad-core → .bmad-core}/checklists/architect-checklist.md +0 -0
  266. /package/{bmad-core → .bmad-core}/checklists/pm-checklist.md +0 -0
  267. /package/{bmad-core → .bmad-core}/checklists/po-master-checklist.md +0 -0
  268. /package/{bmad-core → .bmad-core}/checklists/story-dod-checklist.md +0 -0
  269. /package/{bmad-core → .bmad-core}/data/technical-preferences.md +0 -0
  270. /package/{bmad-core → .bmad-core}/tasks/brownfield-create-epic.md +0 -0
  271. /package/{bmad-core → .bmad-core}/tasks/brownfield-create-story.md +0 -0
  272. /package/{bmad-core → .bmad-core}/tasks/correct-course.md +0 -0
  273. /package/{bmad-core → .bmad-core}/tasks/create-deep-research-prompt.md +0 -0
  274. /package/.github/workflows/{release.yaml → release.yml} +0 -0
@@ -2,7 +2,6 @@ const path = require("node:path");
2
2
  const fileManager = require("./file-manager");
3
3
  const configLoader = require("./config-loader");
4
4
  const ideSetup = require("./ide-setup");
5
- const { extractYamlFromAgent } = require("../../lib/yaml-utils");
6
5
 
7
6
  // Dynamic imports for ES modules
8
7
  let chalk, ora, inquirer;
@@ -17,20 +16,6 @@ async function initializeModules() {
17
16
  }
18
17
 
19
18
  class Installer {
20
- async getCoreVersion() {
21
- const yaml = require("js-yaml");
22
- const fs = require("fs-extra");
23
- const coreConfigPath = path.join(__dirname, "../../../bmad-core/core-config.yaml");
24
- try {
25
- const coreConfigContent = await fs.readFile(coreConfigPath, "utf8");
26
- const coreConfig = yaml.load(coreConfigContent);
27
- return coreConfig.version || "unknown";
28
- } catch (error) {
29
- console.warn("Could not read version from core-config.yaml, using 'unknown'");
30
- return "unknown";
31
- }
32
- }
33
-
34
19
  async install(config) {
35
20
  // Initialize ES modules
36
21
  await initializeModules();
@@ -38,23 +23,12 @@ class Installer {
38
23
  const spinner = ora("Analyzing installation directory...").start();
39
24
 
40
25
  try {
41
- // Store the original CWD where npx was executed
42
- const originalCwd = process.env.INIT_CWD || process.env.PWD || process.cwd();
43
-
44
- // Resolve installation directory relative to where the user ran the command
45
- let installDir = path.isAbsolute(config.directory)
46
- ? config.directory
47
- : path.resolve(originalCwd, config.directory);
48
-
26
+ // Resolve installation directory
27
+ let installDir = path.resolve(config.directory);
49
28
  if (path.basename(installDir) === '.bmad-core') {
50
29
  // If user points directly to .bmad-core, treat its parent as the project root
51
30
  installDir = path.dirname(installDir);
52
31
  }
53
-
54
- // Log resolved path for clarity
55
- if (!path.isAbsolute(config.directory)) {
56
- spinner.text = `Resolving "${config.directory}" to: ${installDir}`;
57
- }
58
32
 
59
33
  // Check if directory exists and handle non-existent directories
60
34
  if (!(await fileManager.pathExists(installDir))) {
@@ -100,7 +74,6 @@ class Installer {
100
74
  }
101
75
  }
102
76
  ]);
103
- // Preserve the original CWD for the recursive call
104
77
  config.directory = newDirectory;
105
78
  return await this.install(config); // Recursive call with new directory
106
79
  } else if (action === 'create') {
@@ -117,17 +90,6 @@ class Installer {
117
90
  spinner.start("Analyzing installation directory...");
118
91
  }
119
92
 
120
- // If this is an update request from early detection, handle it directly
121
- if (config.installType === 'update') {
122
- const state = await this.detectInstallationState(installDir);
123
- if (state.type === 'v4_existing') {
124
- return await this.performUpdate(config, installDir, state.manifest, spinner);
125
- } else {
126
- spinner.fail('No existing v4 installation found to update');
127
- throw new Error('No existing v4 installation found');
128
- }
129
- }
130
-
131
93
  // Detect current state
132
94
  const state = await this.detectInstallationState(installDir);
133
95
 
@@ -176,7 +138,6 @@ class Installer {
176
138
  hasBmadCore: false,
177
139
  hasOtherFiles: false,
178
140
  manifest: null,
179
- expansionPacks: {},
180
141
  };
181
142
 
182
143
  // Check if directory exists
@@ -186,7 +147,7 @@ class Installer {
186
147
 
187
148
  // Check for V4 installation (has .bmad-core with manifest)
188
149
  const bmadCorePath = path.join(installDir, ".bmad-core");
189
- const manifestPath = path.join(bmadCorePath, "install-manifest.yaml");
150
+ const manifestPath = path.join(bmadCorePath, "install-manifest.yml");
190
151
 
191
152
  if (await fileManager.pathExists(manifestPath)) {
192
153
  state.type = "v4_existing";
@@ -220,22 +181,18 @@ class Installer {
220
181
  });
221
182
 
222
183
  if (files.length > 0) {
223
- // Directory has other files, but no BMad installation.
184
+ // Directory has other files, but no BMAD installation.
224
185
  // Treat as clean install but record that it isn't empty.
225
186
  state.hasOtherFiles = true;
226
187
  }
227
188
 
228
- // Check for expansion packs (folders starting with .)
229
- const expansionPacks = await this.detectExpansionPacks(installDir);
230
- state.expansionPacks = expansionPacks;
231
-
232
189
  return state; // clean install
233
190
  }
234
191
 
235
- async performFreshInstall(config, installDir, spinner, options = {}) {
192
+ async performFreshInstall(config, installDir, spinner) {
236
193
  // Ensure modules are initialized
237
194
  await initializeModules();
238
- spinner.text = "Installing BMad Method...";
195
+ spinner.text = "Installing BMAD Method...";
239
196
 
240
197
  let files = [];
241
198
 
@@ -244,11 +201,7 @@ class Installer {
244
201
  spinner.text = "Copying complete .bmad-core folder...";
245
202
  const sourceDir = configLoader.getBmadCorePath();
246
203
  const bmadCoreDestDir = path.join(installDir, ".bmad-core");
247
- await fileManager.copyDirectoryWithRootReplacement(sourceDir, bmadCoreDestDir, ".bmad-core");
248
-
249
- // Copy common/ items to .bmad-core
250
- spinner.text = "Copying common utilities...";
251
- await this.copyCommonItems(installDir, ".bmad-core", spinner);
204
+ await fileManager.copyDirectory(sourceDir, bmadCoreDestDir);
252
205
 
253
206
  // Get list of all files for manifest
254
207
  const glob = require("glob");
@@ -263,16 +216,15 @@ class Installer {
263
216
  // Single agent installation
264
217
  spinner.text = `Installing ${config.agent} agent...`;
265
218
 
266
- // Copy agent file with {root} replacement
219
+ // Copy agent file
267
220
  const agentPath = configLoader.getAgentPath(config.agent);
268
221
  const destAgentPath = path.join(
269
222
  installDir,
270
- ".bmad-core",
271
223
  "agents",
272
224
  `${config.agent}.md`
273
225
  );
274
- await fileManager.copyFileWithRootReplacement(agentPath, destAgentPath, ".bmad-core");
275
- files.push(`.bmad-core/agents/${config.agent}.md`);
226
+ await fileManager.copyFile(agentPath, destAgentPath);
227
+ files.push(`agents/${config.agent}.md`);
276
228
 
277
229
  // Copy dependencies
278
230
  const dependencies = await configLoader.getAgentDependencies(
@@ -284,108 +236,29 @@ class Installer {
284
236
  spinner.text = `Copying dependency: ${dep}`;
285
237
 
286
238
  if (dep.includes("*")) {
287
- // Handle glob patterns with {root} replacement
239
+ // Handle glob patterns
288
240
  const copiedFiles = await fileManager.copyGlobPattern(
289
241
  dep.replace(".bmad-core/", ""),
290
242
  sourceBase,
291
- path.join(installDir, ".bmad-core"),
292
- ".bmad-core"
243
+ installDir
293
244
  );
294
- files.push(...copiedFiles.map(f => `.bmad-core/${f}`));
245
+ files.push(...copiedFiles);
295
246
  } else {
296
- // Handle single files with {root} replacement if needed
247
+ // Handle single files
297
248
  const sourcePath = path.join(
298
249
  sourceBase,
299
250
  dep.replace(".bmad-core/", "")
300
251
  );
301
252
  const destPath = path.join(
302
253
  installDir,
303
- dep
304
- );
305
-
306
- const needsRootReplacement = dep.endsWith('.md') || dep.endsWith('.yaml') || dep.endsWith('.yml');
307
- let success = false;
308
-
309
- if (needsRootReplacement) {
310
- success = await fileManager.copyFileWithRootReplacement(sourcePath, destPath, ".bmad-core");
311
- } else {
312
- success = await fileManager.copyFile(sourcePath, destPath);
313
- }
314
-
315
- if (success) {
316
- files.push(dep);
317
- }
318
- }
319
- }
320
-
321
- // Copy common/ items to .bmad-core
322
- spinner.text = "Copying common utilities...";
323
- const commonFiles = await this.copyCommonItems(installDir, ".bmad-core", spinner);
324
- files.push(...commonFiles);
325
- } else if (config.installType === "team") {
326
- // Team installation
327
- spinner.text = `Installing ${config.team} team...`;
328
-
329
- // Get team dependencies
330
- const teamDependencies = await configLoader.getTeamDependencies(config.team);
331
- const sourceBase = configLoader.getBmadCorePath();
332
-
333
- // Install all team dependencies
334
- for (const dep of teamDependencies) {
335
- spinner.text = `Copying team dependency: ${dep}`;
336
-
337
- if (dep.includes("*")) {
338
- // Handle glob patterns with {root} replacement
339
- const copiedFiles = await fileManager.copyGlobPattern(
340
- dep.replace(".bmad-core/", ""),
341
- sourceBase,
342
- path.join(installDir, ".bmad-core"),
343
- ".bmad-core"
254
+ dep.replace(".bmad-core/", "")
344
255
  );
345
- files.push(...copiedFiles.map(f => `.bmad-core/${f}`));
346
- } else {
347
- // Handle single files with {root} replacement if needed
348
- const sourcePath = path.join(sourceBase, dep.replace(".bmad-core/", ""));
349
- const destPath = path.join(installDir, dep);
350
-
351
- const needsRootReplacement = dep.endsWith('.md') || dep.endsWith('.yaml') || dep.endsWith('.yml');
352
- let success = false;
353
-
354
- if (needsRootReplacement) {
355
- success = await fileManager.copyFileWithRootReplacement(sourcePath, destPath, ".bmad-core");
356
- } else {
357
- success = await fileManager.copyFile(sourcePath, destPath);
358
- }
359
256
 
360
- if (success) {
361
- files.push(dep);
257
+ if (await fileManager.copyFile(sourcePath, destPath)) {
258
+ files.push(dep.replace(".bmad-core/", ""));
362
259
  }
363
260
  }
364
261
  }
365
-
366
- // Copy common/ items to .bmad-core
367
- spinner.text = "Copying common utilities...";
368
- const commonFiles = await this.copyCommonItems(installDir, ".bmad-core", spinner);
369
- files.push(...commonFiles);
370
- } else if (config.installType === "expansion-only") {
371
- // Expansion-only installation - DO NOT create .bmad-core
372
- // Only install expansion packs
373
- spinner.text = "Installing expansion packs only...";
374
- }
375
-
376
- // Install expansion packs if requested
377
- const expansionFiles = await this.installExpansionPacks(installDir, config.expansionPacks, spinner, config);
378
- files.push(...expansionFiles);
379
-
380
- // Install web bundles if requested
381
- if (config.includeWebBundles && config.webBundlesDirectory) {
382
- spinner.text = "Installing web bundles...";
383
- // Resolve web bundles directory using the same logic as the main installation directory
384
- const originalCwd = process.env.INIT_CWD || process.env.PWD || process.cwd();
385
- let resolvedWebBundlesDir = path.isAbsolute(config.webBundlesDirectory)
386
- ? config.webBundlesDirectory
387
- : path.resolve(originalCwd, config.webBundlesDirectory);
388
- await this.installWebBundles(resolvedWebBundlesDir, config, spinner);
389
262
  }
390
263
 
391
264
  // Set up IDE integration if requested
@@ -393,25 +266,16 @@ class Installer {
393
266
  if (ides.length > 0) {
394
267
  for (const ide of ides) {
395
268
  spinner.text = `Setting up ${ide} integration...`;
396
- const preConfiguredSettings = ide === 'github-copilot' ? config.githubCopilotConfig : null;
397
- await ideSetup.setup(ide, installDir, config.agent, spinner, preConfiguredSettings);
269
+ await ideSetup.setup(ide, installDir, config.agent);
398
270
  }
399
271
  }
400
272
 
401
- // Modify core-config.yaml if sharding preferences were provided
402
- if (config.installType !== "expansion-only" && (config.prdSharded !== undefined || config.architectureSharded !== undefined)) {
403
- spinner.text = "Configuring document sharding settings...";
404
- await fileManager.modifyCoreConfig(installDir, config);
405
- }
406
-
407
- // Create manifest (skip for expansion-only installations)
408
- if (config.installType !== "expansion-only") {
409
- spinner.text = "Creating installation manifest...";
410
- await fileManager.createManifest(installDir, config, files);
411
- }
273
+ // Create manifest
274
+ spinner.text = "Creating installation manifest...";
275
+ await fileManager.createManifest(installDir, config, files);
412
276
 
413
277
  spinner.succeed("Installation complete!");
414
- this.showSuccessMessage(config, installDir, options);
278
+ this.showSuccessMessage(config, installDir);
415
279
  }
416
280
 
417
281
  async handleExistingV4Installation(config, installDir, state, spinner) {
@@ -419,137 +283,33 @@ class Installer {
419
283
  await initializeModules();
420
284
  spinner.stop();
421
285
 
422
- const currentVersion = state.manifest.version;
423
- const newVersion = await this.getCoreVersion();
424
- const versionCompare = this.compareVersions(currentVersion, newVersion);
425
-
426
- console.log(chalk.yellow("\n🔍 Found existing BMad v4 installation"));
286
+ console.log(chalk.yellow("\n🔍 Found existing BMAD v4 installation"));
427
287
  console.log(` Directory: ${installDir}`);
428
- console.log(` Current version: ${currentVersion}`);
429
- console.log(` Available version: ${newVersion}`);
288
+ console.log(` Version: ${state.manifest.version}`);
430
289
  console.log(
431
290
  ` Installed: ${new Date(
432
291
  state.manifest.installed_at
433
292
  ).toLocaleDateString()}`
434
293
  );
435
294
 
436
- // Check file integrity
437
- spinner.start("Checking installation integrity...");
438
- const integrity = await fileManager.checkFileIntegrity(installDir, state.manifest);
439
- spinner.stop();
440
-
441
- const hasMissingFiles = integrity.missing.length > 0;
442
- const hasModifiedFiles = integrity.modified.length > 0;
443
- const hasIntegrityIssues = hasMissingFiles || hasModifiedFiles;
444
-
445
- if (hasIntegrityIssues) {
446
- console.log(chalk.red("\n⚠️ Installation issues detected:"));
447
- if (hasMissingFiles) {
448
- console.log(chalk.red(` Missing files: ${integrity.missing.length}`));
449
- if (integrity.missing.length <= 5) {
450
- integrity.missing.forEach(file => console.log(chalk.dim(` - ${file}`)));
451
- }
452
- }
453
- if (hasModifiedFiles) {
454
- console.log(chalk.yellow(` Modified files: ${integrity.modified.length}`));
455
- if (integrity.modified.length <= 5) {
456
- integrity.modified.forEach(file => console.log(chalk.dim(` - ${file}`)));
457
- }
458
- }
459
- }
460
-
461
- // Show existing expansion packs
462
- if (Object.keys(state.expansionPacks).length > 0) {
463
- console.log(chalk.cyan("\n📦 Installed expansion packs:"));
464
- for (const [packId, packInfo] of Object.entries(state.expansionPacks)) {
465
- if (packInfo.hasManifest && packInfo.manifest) {
466
- console.log(` - ${packId} (v${packInfo.manifest.version || 'unknown'})`);
467
- } else {
468
- console.log(` - ${packId} (no manifest)`);
469
- }
470
- }
471
- }
472
-
473
- let choices = [];
474
-
475
- if (versionCompare < 0) {
476
- console.log(chalk.cyan("\n⬆️ Upgrade available for BMad core"));
477
- choices.push({ name: `Upgrade BMad core (v${currentVersion} → v${newVersion})`, value: "upgrade" });
478
- } else if (versionCompare === 0) {
479
- if (hasIntegrityIssues) {
480
- // Offer repair option when files are missing or modified
481
- choices.push({
482
- name: "Repair installation (restore missing/modified files)",
483
- value: "repair"
484
- });
485
- }
486
- console.log(chalk.yellow("\n⚠️ Same version already installed"));
487
- choices.push({ name: `Force reinstall BMad core (v${currentVersion} - reinstall)`, value: "reinstall" });
488
- } else {
489
- console.log(chalk.yellow("\n⬇️ Installed version is newer than available"));
490
- choices.push({ name: `Downgrade BMad core (v${currentVersion} → v${newVersion})`, value: "reinstall" });
491
- }
492
-
493
- choices.push(
494
- { name: "Add/update expansion packs only", value: "expansions" },
495
- { name: "Cancel", value: "cancel" }
496
- );
497
-
498
295
  const { action } = await inquirer.prompt([
499
296
  {
500
297
  type: "list",
501
298
  name: "action",
502
299
  message: "What would you like to do?",
503
- choices: choices,
300
+ choices: [
301
+ { name: "Update existing installation", value: "update" },
302
+ { name: "Reinstall (overwrite)", value: "reinstall" },
303
+ { name: "Cancel", value: "cancel" },
304
+ ],
504
305
  },
505
306
  ]);
506
307
 
507
308
  switch (action) {
508
- case "upgrade":
309
+ case "update":
509
310
  return await this.performUpdate(config, installDir, state.manifest, spinner);
510
- case "repair":
511
- // For repair, restore missing/modified files while backing up modified ones
512
- return await this.performRepair(config, installDir, state.manifest, integrity, spinner);
513
311
  case "reinstall":
514
- // For reinstall, don't check for modifications - just overwrite
515
312
  return await this.performReinstall(config, installDir, spinner);
516
- case "expansions":
517
- // Ask which expansion packs to install
518
- const availableExpansionPacks = await this.getAvailableExpansionPacks();
519
-
520
- if (availableExpansionPacks.length === 0) {
521
- console.log(chalk.yellow("No expansion packs available."));
522
- return;
523
- }
524
-
525
- const { selectedPacks } = await inquirer.prompt([
526
- {
527
- type: 'checkbox',
528
- name: 'selectedPacks',
529
- message: 'Select expansion packs to install/update:',
530
- choices: availableExpansionPacks.map(pack => ({
531
- name: `${pack.name} v${pack.version} - ${pack.description}`,
532
- value: pack.id,
533
- checked: state.expansionPacks[pack.id] !== undefined
534
- }))
535
- }
536
- ]);
537
-
538
- if (selectedPacks.length === 0) {
539
- console.log(chalk.yellow("No expansion packs selected."));
540
- return;
541
- }
542
-
543
- spinner.start("Installing expansion packs...");
544
- const expansionFiles = await this.installExpansionPacks(installDir, selectedPacks, spinner, { ides: config.ides || [] });
545
- spinner.succeed("Expansion packs installed successfully!");
546
-
547
- console.log(chalk.green("\n✓ Installation complete!"));
548
- console.log(chalk.green(`✓ Expansion packs installed/updated:`));
549
- for (const packId of selectedPacks) {
550
- console.log(chalk.green(` - ${packId} → .${packId}/`));
551
- }
552
- return;
553
313
  case "cancel":
554
314
  console.log("Installation cancelled.");
555
315
  return;
@@ -562,7 +322,7 @@ class Installer {
562
322
  spinner.stop();
563
323
 
564
324
  console.log(
565
- chalk.yellow("\n🔍 Found BMad v3 installation (bmad-agent/ directory)")
325
+ chalk.yellow("\n🔍 Found BMAD v3 installation (bmad-agent/ directory)")
566
326
  );
567
327
  console.log(` Directory: ${installDir}`);
568
328
 
@@ -584,10 +344,7 @@ class Installer {
584
344
  console.log(chalk.cyan("\n📦 Starting v3 to v4 upgrade process..."));
585
345
  const V3ToV4Upgrader = require("../../upgraders/v3-to-v4-upgrader");
586
346
  const upgrader = new V3ToV4Upgrader();
587
- return await upgrader.upgrade({
588
- projectPath: installDir,
589
- ides: config.ides || [] // Pass IDE selections from initial config
590
- });
347
+ return await upgrader.upgrade({ projectPath: installDir });
591
348
  }
592
349
  case "alongside":
593
350
  return await this.performFreshInstall(config, installDir, spinner);
@@ -650,20 +407,12 @@ class Installer {
650
407
  spinner.start("Checking for updates...");
651
408
 
652
409
  try {
653
- // Get current and new versions
654
- const currentVersion = manifest.version;
655
- const newVersion = await this.getCoreVersion();
656
- const versionCompare = this.compareVersions(currentVersion, newVersion);
657
-
658
- // Only check for modified files if it's an actual version upgrade
659
- let modifiedFiles = [];
660
- if (versionCompare !== 0) {
661
- spinner.text = "Checking for modified files...";
662
- modifiedFiles = await fileManager.checkModifiedFiles(
663
- installDir,
664
- manifest
665
- );
666
- }
410
+ // Check for modified files
411
+ spinner.text = "Checking for modified files...";
412
+ const modifiedFiles = await fileManager.checkModifiedFiles(
413
+ installDir,
414
+ manifest
415
+ );
667
416
 
668
417
  if (modifiedFiles.length > 0) {
669
418
  spinner.warn("Found modified files");
@@ -703,138 +452,35 @@ class Installer {
703
452
  }
704
453
 
705
454
  // Perform update by re-running installation
706
- spinner.text = versionCompare === 0 ? "Reinstalling files..." : "Updating files...";
455
+ spinner.text = "Updating files...";
707
456
  const config = {
708
457
  installType: manifest.install_type,
709
458
  agent: manifest.agent,
710
459
  directory: installDir,
711
- ides: newConfig?.ides || manifest.ides_setup || [],
460
+ ide: newConfig.ide || manifest.ide_setup, // Use new IDE choice if provided
712
461
  };
713
462
 
714
- await this.performFreshInstall(config, installDir, spinner, { isUpdate: true });
715
-
716
- // Clean up .yml files that now have .yaml counterparts
717
- spinner.text = "Cleaning up legacy .yml files...";
718
- await this.cleanupLegacyYmlFiles(installDir, spinner);
463
+ await this.performFreshInstall(config, installDir, spinner);
719
464
  } catch (error) {
720
465
  spinner.fail("Update failed");
721
466
  throw error;
722
467
  }
723
468
  }
724
469
 
725
- async performRepair(config, installDir, manifest, integrity, spinner) {
726
- spinner.start("Preparing to repair installation...");
727
-
728
- try {
729
- // Back up modified files
730
- if (integrity.modified.length > 0) {
731
- spinner.text = "Backing up modified files...";
732
- for (const file of integrity.modified) {
733
- const filePath = path.join(installDir, file);
734
- if (await fileManager.pathExists(filePath)) {
735
- const backupPath = await fileManager.backupFile(filePath);
736
- console.log(chalk.dim(` Backed up: ${file} → ${path.basename(backupPath)}`));
737
- }
738
- }
739
- }
740
-
741
- // Restore missing and modified files
742
- spinner.text = "Restoring files...";
743
- const sourceBase = configLoader.getBmadCorePath();
744
- const filesToRestore = [...integrity.missing, ...integrity.modified];
745
-
746
- for (const file of filesToRestore) {
747
- // Skip the manifest file itself
748
- if (file.endsWith('install-manifest.yaml')) continue;
749
-
750
- const relativePath = file.replace('.bmad-core/', '');
751
- const destPath = path.join(installDir, file);
752
-
753
- // Check if this is a common/ file that needs special processing
754
- const commonBase = path.dirname(path.dirname(path.dirname(path.dirname(__filename))));
755
- const commonSourcePath = path.join(commonBase, 'common', relativePath);
756
-
757
- if (await fileManager.pathExists(commonSourcePath)) {
758
- // This is a common/ file - needs template processing
759
- const fs = require('fs').promises;
760
- const content = await fs.readFile(commonSourcePath, 'utf8');
761
- const updatedContent = content.replace(/\{root\}/g, '.bmad-core');
762
- await fileManager.ensureDirectory(path.dirname(destPath));
763
- await fs.writeFile(destPath, updatedContent, 'utf8');
764
- spinner.text = `Restored: ${file}`;
765
- } else {
766
- // Regular file from bmad-core
767
- const sourcePath = path.join(sourceBase, relativePath);
768
- if (await fileManager.pathExists(sourcePath)) {
769
- await fileManager.copyFile(sourcePath, destPath);
770
- spinner.text = `Restored: ${file}`;
771
-
772
- // If this is a .yaml file, check for and remove corresponding .yml file
773
- if (file.endsWith('.yaml')) {
774
- const ymlFile = file.replace(/\.yaml$/, '.yml');
775
- const ymlPath = path.join(installDir, ymlFile);
776
- if (await fileManager.pathExists(ymlPath)) {
777
- const fs = require('fs').promises;
778
- await fs.unlink(ymlPath);
779
- console.log(chalk.dim(` Removed legacy: ${ymlFile} (replaced by ${file})`));
780
- }
781
- }
782
- } else {
783
- console.warn(chalk.yellow(` Warning: Source file not found: ${file}`));
784
- }
785
- }
786
- }
787
-
788
- // Clean up .yml files that now have .yaml counterparts
789
- spinner.text = "Cleaning up legacy .yml files...";
790
- await this.cleanupLegacyYmlFiles(installDir, spinner);
791
-
792
- spinner.succeed("Repair completed successfully!");
793
-
794
- // Show summary
795
- console.log(chalk.green("\n✓ Installation repaired!"));
796
- if (integrity.missing.length > 0) {
797
- console.log(chalk.green(` Restored ${integrity.missing.length} missing files`));
798
- }
799
- if (integrity.modified.length > 0) {
800
- console.log(chalk.green(` Restored ${integrity.modified.length} modified files (backups created)`));
801
- }
802
-
803
- // Warning for Cursor custom modes if agents were repaired
804
- const ides = manifest.ides_setup || [];
805
- if (ides.includes('cursor')) {
806
- console.log(chalk.yellow.bold("\n⚠️ IMPORTANT: Cursor Custom Modes Update Required"));
807
- console.log(chalk.yellow("Since agent files have been repaired, you need to update any custom agent modes configured in the Cursor custom agent GUI per the Cursor docs."));
808
- }
809
-
810
- } catch (error) {
811
- spinner.fail("Repair failed");
812
- throw error;
813
- }
814
- }
815
-
816
470
  async performReinstall(config, installDir, spinner) {
817
- spinner.start("Preparing to reinstall BMad Method...");
471
+ spinner.start("Reinstalling BMAD Method...");
818
472
 
819
473
  // Remove existing .bmad-core
820
474
  const bmadCorePath = path.join(installDir, ".bmad-core");
821
475
  if (await fileManager.pathExists(bmadCorePath)) {
822
- spinner.text = "Removing existing installation...";
823
476
  await fileManager.removeDirectory(bmadCorePath);
824
477
  }
825
-
826
- spinner.text = "Installing fresh copy...";
827
- const result = await this.performFreshInstall(config, installDir, spinner, { isUpdate: true });
828
-
829
- // Clean up .yml files that now have .yaml counterparts
830
- spinner.text = "Cleaning up legacy .yml files...";
831
- await this.cleanupLegacyYmlFiles(installDir, spinner);
832
-
833
- return result;
478
+
479
+ return await this.performFreshInstall(config, installDir, spinner);
834
480
  }
835
481
 
836
- showSuccessMessage(config, installDir, options = {}) {
837
- console.log(chalk.green("\n✓ BMad Method installed successfully!\n"));
482
+ showSuccessMessage(config, installDir) {
483
+ console.log(chalk.green("\n✓ BMAD Method installed successfully!\n"));
838
484
 
839
485
  const ides = config.ides || (config.ide ? [config.ide] : []);
840
486
  if (ides.length > 0) {
@@ -842,7 +488,7 @@ class Installer {
842
488
  const ideConfig = configLoader.getIdeConfiguration(ide);
843
489
  if (ideConfig?.instructions) {
844
490
  console.log(
845
- chalk.bold(`To use BMad agents in ${ideConfig.name}:`)
491
+ chalk.bold(`To use BMAD agents in ${ideConfig.name}:`)
846
492
  );
847
493
  console.log(ideConfig.instructions);
848
494
  }
@@ -857,26 +503,7 @@ class Installer {
857
503
 
858
504
  // Information about installation components
859
505
  console.log(chalk.bold("\n🎯 Installation Summary:"));
860
- if (config.installType !== "expansion-only") {
861
- console.log(chalk.green("✓ .bmad-core framework installed with all agents and workflows"));
862
- }
863
-
864
- if (config.expansionPacks && config.expansionPacks.length > 0) {
865
- console.log(chalk.green(`✓ Expansion packs installed:`));
866
- for (const packId of config.expansionPacks) {
867
- console.log(chalk.green(` - ${packId} → .${packId}/`));
868
- }
869
- }
870
-
871
- if (config.includeWebBundles && config.webBundlesDirectory) {
872
- const bundleInfo = this.getWebBundleInfo(config);
873
- // Resolve the web bundles directory for display
874
- const originalCwd = process.env.INIT_CWD || process.env.PWD || process.cwd();
875
- const resolvedWebBundlesDir = path.isAbsolute(config.webBundlesDirectory)
876
- ? config.webBundlesDirectory
877
- : path.resolve(originalCwd, config.webBundlesDirectory);
878
- console.log(chalk.green(`✓ Web bundles (${bundleInfo}) installed to: ${resolvedWebBundlesDir}`));
879
- }
506
+ console.log(chalk.green("✓ .bmad-core framework installed with all agents and workflows"));
880
507
 
881
508
  if (ides.length > 0) {
882
509
  const ideNames = ides.map(ide => {
@@ -887,13 +514,11 @@ class Installer {
887
514
  }
888
515
 
889
516
  // Information about web bundles
890
- if (!config.includeWebBundles) {
891
- console.log(chalk.bold("\n📦 Web Bundles Available:"));
892
- console.log("Pre-built web bundles are available and can be added later:");
893
- console.log(chalk.cyan(" Run the installer again to add them to your project"));
894
- console.log("These bundles work independently and can be shared, moved, or used");
895
- console.log("in other projects as standalone files.");
896
- }
517
+ console.log(chalk.bold("\n📦 Web Bundles Available:"));
518
+ console.log("Self-contained web bundles have been included in your installation:");
519
+ console.log(chalk.cyan(` ${installDir}/.bmad-core/web-bundles/`));
520
+ console.log("These bundles work independently without this installation and can be");
521
+ console.log("shared, moved, or used in other projects as standalone files.");
897
522
 
898
523
  if (config.installType === "single-agent") {
899
524
  console.log(
@@ -905,12 +530,6 @@ class Installer {
905
530
  chalk.dim("Need everything? Run: npx bmad-method install --full")
906
531
  );
907
532
  }
908
-
909
- // Warning for Cursor custom modes if agents were updated
910
- if (options.isUpdate && ides.includes('cursor')) {
911
- console.log(chalk.yellow.bold("\n⚠️ IMPORTANT: Cursor Custom Modes Update Required"));
912
- console.log(chalk.yellow("Since agents have been updated, you need to update any custom agent modes configured in the Cursor custom agent GUI per the Cursor docs."));
913
- }
914
533
  }
915
534
 
916
535
  // Legacy method for backward compatibility
@@ -931,7 +550,7 @@ class Installer {
931
550
  };
932
551
  return await this.install(config);
933
552
  }
934
- console.log(chalk.red("No BMad installation found."));
553
+ console.log(chalk.red("No BMAD installation found."));
935
554
  }
936
555
 
937
556
  async listAgents() {
@@ -939,7 +558,7 @@ class Installer {
939
558
  await initializeModules();
940
559
  const agents = await configLoader.getAvailableAgents();
941
560
 
942
- console.log(chalk.bold("\nAvailable BMad Agents:\n"));
561
+ console.log(chalk.bold("\nAvailable BMAD Agents:\n"));
943
562
 
944
563
  for (const agent of agents) {
945
564
  console.log(chalk.cyan(` ${agent.id.padEnd(20)}`), agent.description);
@@ -950,33 +569,6 @@ class Installer {
950
569
  );
951
570
  }
952
571
 
953
- async listExpansionPacks() {
954
- // Initialize ES modules
955
- await initializeModules();
956
- const expansionPacks = await this.getAvailableExpansionPacks();
957
-
958
- console.log(chalk.bold("\nAvailable BMad Expansion Packs:\n"));
959
-
960
- if (expansionPacks.length === 0) {
961
- console.log(chalk.yellow("No expansion packs found."));
962
- return;
963
- }
964
-
965
- for (const pack of expansionPacks) {
966
- console.log(chalk.cyan(` ${pack.id.padEnd(20)}`),
967
- `${pack.name} v${pack.version}`);
968
- console.log(chalk.dim(` ${' '.repeat(22)}${pack.description}`));
969
- if (pack.author && pack.author !== 'Unknown') {
970
- console.log(chalk.dim(` ${' '.repeat(22)}by ${pack.author}`));
971
- }
972
- console.log();
973
- }
974
-
975
- console.log(
976
- chalk.dim("Install with: npx bmad-method install --full --expansion-packs <id>\n")
977
- );
978
- }
979
-
980
572
  async showStatus() {
981
573
  // Initialize ES modules
982
574
  await initializeModules();
@@ -984,7 +576,7 @@ class Installer {
984
576
 
985
577
  if (!installDir) {
986
578
  console.log(
987
- chalk.yellow("No BMad installation found in current directory tree")
579
+ chalk.yellow("No BMAD installation found in current directory tree")
988
580
  );
989
581
  return;
990
582
  }
@@ -996,7 +588,7 @@ class Installer {
996
588
  return;
997
589
  }
998
590
 
999
- console.log(chalk.bold("\nBMad Installation Status:\n"));
591
+ console.log(chalk.bold("\nBMAD Installation Status:\n"));
1000
592
  console.log(` Directory: ${installDir}`);
1001
593
  console.log(` Version: ${manifest.version}`);
1002
594
  console.log(
@@ -1010,8 +602,8 @@ class Installer {
1010
602
  console.log(` Agent: ${manifest.agent}`);
1011
603
  }
1012
604
 
1013
- if (manifest.ides_setup && manifest.ides_setup.length > 0) {
1014
- console.log(` IDE Setup: ${manifest.ides_setup.join(', ')}`);
605
+ if (manifest.ide_setup) {
606
+ console.log(` IDE Setup: ${manifest.ide_setup}`);
1015
607
  }
1016
608
 
1017
609
  console.log(` Total Files: ${manifest.files.length}`);
@@ -1032,715 +624,13 @@ class Installer {
1032
624
  return configLoader.getAvailableAgents();
1033
625
  }
1034
626
 
1035
- async getAvailableExpansionPacks() {
1036
- return configLoader.getAvailableExpansionPacks();
1037
- }
1038
-
1039
- async getAvailableTeams() {
1040
- return configLoader.getAvailableTeams();
1041
- }
1042
-
1043
- async installExpansionPacks(installDir, selectedPacks, spinner, config = {}) {
1044
- if (!selectedPacks || selectedPacks.length === 0) {
1045
- return [];
1046
- }
1047
-
1048
- const installedFiles = [];
1049
- const glob = require('glob');
1050
-
1051
- for (const packId of selectedPacks) {
1052
- spinner.text = `Installing expansion pack: ${packId}...`;
1053
-
1054
- try {
1055
- const expansionPacks = await this.getAvailableExpansionPacks();
1056
- const pack = expansionPacks.find(p => p.id === packId);
1057
-
1058
- if (!pack) {
1059
- console.warn(`Expansion pack ${packId} not found, skipping...`);
1060
- continue;
1061
- }
1062
-
1063
- // Check if expansion pack already exists
1064
- let expansionDotFolder = path.join(installDir, `.${packId}`);
1065
- const existingManifestPath = path.join(expansionDotFolder, 'install-manifest.yaml');
1066
-
1067
- if (await fileManager.pathExists(existingManifestPath)) {
1068
- spinner.stop();
1069
- const existingManifest = await fileManager.readExpansionPackManifest(installDir, packId);
1070
-
1071
- console.log(chalk.yellow(`\n🔍 Found existing ${pack.name} installation`));
1072
- console.log(` Current version: ${existingManifest.version || 'unknown'}`);
1073
- console.log(` New version: ${pack.version}`);
1074
-
1075
- // Check integrity of existing expansion pack
1076
- const packIntegrity = await fileManager.checkFileIntegrity(installDir, existingManifest);
1077
- const hasPackIntegrityIssues = packIntegrity.missing.length > 0 || packIntegrity.modified.length > 0;
1078
-
1079
- if (hasPackIntegrityIssues) {
1080
- console.log(chalk.red(" ⚠️ Installation issues detected:"));
1081
- if (packIntegrity.missing.length > 0) {
1082
- console.log(chalk.red(` Missing files: ${packIntegrity.missing.length}`));
1083
- }
1084
- if (packIntegrity.modified.length > 0) {
1085
- console.log(chalk.yellow(` Modified files: ${packIntegrity.modified.length}`));
1086
- }
1087
- }
1088
-
1089
- const versionCompare = this.compareVersions(existingManifest.version || '0.0.0', pack.version);
1090
-
1091
- if (versionCompare === 0) {
1092
- console.log(chalk.yellow(' ⚠️ Same version already installed'));
1093
-
1094
- const choices = [];
1095
- if (hasPackIntegrityIssues) {
1096
- choices.push({ name: 'Repair (restore missing/modified files)', value: 'repair' });
1097
- }
1098
- choices.push(
1099
- { name: 'Force reinstall (overwrite)', value: 'overwrite' },
1100
- { name: 'Skip this expansion pack', value: 'skip' },
1101
- { name: 'Cancel installation', value: 'cancel' }
1102
- );
1103
-
1104
- const { action } = await inquirer.prompt([{
1105
- type: 'list',
1106
- name: 'action',
1107
- message: `${pack.name} v${pack.version} is already installed. What would you like to do?`,
1108
- choices: choices
1109
- }]);
1110
-
1111
- if (action === 'skip') {
1112
- spinner.start();
1113
- continue;
1114
- } else if (action === 'cancel') {
1115
- console.log(chalk.red('Installation cancelled.'));
1116
- process.exit(0);
1117
- } else if (action === 'repair') {
1118
- // Repair the expansion pack
1119
- await this.repairExpansionPack(installDir, packId, pack, packIntegrity, spinner);
1120
- continue;
1121
- }
1122
- } else if (versionCompare < 0) {
1123
- console.log(chalk.cyan(' ⬆️ Upgrade available'));
1124
-
1125
- const { proceed } = await inquirer.prompt([{
1126
- type: 'confirm',
1127
- name: 'proceed',
1128
- message: `Upgrade ${pack.name} from v${existingManifest.version} to v${pack.version}?`,
1129
- default: true
1130
- }]);
1131
-
1132
- if (!proceed) {
1133
- spinner.start();
1134
- continue;
1135
- }
1136
- } else {
1137
- console.log(chalk.yellow(' ⬇️ Installed version is newer than available version'));
1138
-
1139
- const { action } = await inquirer.prompt([{
1140
- type: 'list',
1141
- name: 'action',
1142
- message: 'What would you like to do?',
1143
- choices: [
1144
- { name: 'Keep current version', value: 'skip' },
1145
- { name: 'Downgrade to available version', value: 'downgrade' },
1146
- { name: 'Cancel installation', value: 'cancel' }
1147
- ]
1148
- }]);
1149
-
1150
- if (action === 'skip') {
1151
- spinner.start();
1152
- continue;
1153
- } else if (action === 'cancel') {
1154
- console.log(chalk.red('Installation cancelled.'));
1155
- process.exit(0);
1156
- }
1157
- }
1158
-
1159
- // If we get here, we're proceeding with installation
1160
- spinner.start(`Removing old ${pack.name} installation...`);
1161
- await fileManager.removeDirectory(expansionDotFolder);
1162
- }
1163
-
1164
- const expansionPackDir = pack.packPath;
1165
-
1166
- // Ensure dedicated dot folder exists for this expansion pack
1167
- expansionDotFolder = path.join(installDir, `.${packId}`);
1168
- await fileManager.ensureDirectory(expansionDotFolder);
1169
-
1170
- // Define the folders to copy from expansion packs
1171
- const foldersToSync = [
1172
- 'agents',
1173
- 'agent-teams',
1174
- 'templates',
1175
- 'tasks',
1176
- 'checklists',
1177
- 'workflows',
1178
- 'data',
1179
- 'utils',
1180
- 'schemas'
1181
- ];
1182
-
1183
- // Copy each folder if it exists
1184
- for (const folder of foldersToSync) {
1185
- const sourceFolder = path.join(expansionPackDir, folder);
1186
-
1187
- // Check if folder exists in expansion pack
1188
- if (await fileManager.pathExists(sourceFolder)) {
1189
- // Get all files in this folder
1190
- const files = glob.sync('**/*', {
1191
- cwd: sourceFolder,
1192
- nodir: true
1193
- });
1194
-
1195
- // Copy each file to the expansion pack's dot folder with {root} replacement
1196
- for (const file of files) {
1197
- const sourcePath = path.join(sourceFolder, file);
1198
- const destPath = path.join(expansionDotFolder, folder, file);
1199
-
1200
- const needsRootReplacement = file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml');
1201
- let success = false;
1202
-
1203
- if (needsRootReplacement) {
1204
- success = await fileManager.copyFileWithRootReplacement(sourcePath, destPath, `.${packId}`);
1205
- } else {
1206
- success = await fileManager.copyFile(sourcePath, destPath);
1207
- }
1208
-
1209
- if (success) {
1210
- installedFiles.push(path.join(`.${packId}`, folder, file));
1211
- }
1212
- }
1213
- }
1214
- }
1215
-
1216
- // Copy config.yaml with {root} replacement
1217
- const configPath = path.join(expansionPackDir, 'config.yaml');
1218
- if (await fileManager.pathExists(configPath)) {
1219
- const configDestPath = path.join(expansionDotFolder, 'config.yaml');
1220
- if (await fileManager.copyFileWithRootReplacement(configPath, configDestPath, `.${packId}`)) {
1221
- installedFiles.push(path.join(`.${packId}`, 'config.yaml'));
1222
- }
1223
- }
1224
-
1225
- // Copy README if it exists with {root} replacement
1226
- const readmePath = path.join(expansionPackDir, 'README.md');
1227
- if (await fileManager.pathExists(readmePath)) {
1228
- const readmeDestPath = path.join(expansionDotFolder, 'README.md');
1229
- if (await fileManager.copyFileWithRootReplacement(readmePath, readmeDestPath, `.${packId}`)) {
1230
- installedFiles.push(path.join(`.${packId}`, 'README.md'));
1231
- }
1232
- }
1233
-
1234
- // Copy common/ items to expansion pack folder
1235
- spinner.text = `Copying common utilities to ${packId}...`;
1236
- await this.copyCommonItems(installDir, `.${packId}`, spinner);
1237
-
1238
- // Check and resolve core dependencies
1239
- await this.resolveExpansionPackCoreDependencies(installDir, expansionDotFolder, packId, spinner);
1240
-
1241
- // Check and resolve core agents referenced by teams
1242
- await this.resolveExpansionPackCoreAgents(installDir, expansionDotFolder, packId, spinner);
1243
-
1244
- // Create manifest for this expansion pack
1245
- spinner.text = `Creating manifest for ${packId}...`;
1246
- const expansionConfig = {
1247
- installType: 'expansion-pack',
1248
- expansionPackId: packId,
1249
- expansionPackName: pack.name,
1250
- expansionPackVersion: pack.version,
1251
- ides: config.ides || [] // Use ides_setup instead of ide_setup
1252
- };
1253
-
1254
- // Get all files installed in this expansion pack
1255
- const expansionPackFiles = glob.sync('**/*', {
1256
- cwd: expansionDotFolder,
1257
- nodir: true
1258
- }).map(f => path.join(`.${packId}`, f));
1259
-
1260
- await fileManager.createExpansionPackManifest(installDir, packId, expansionConfig, expansionPackFiles);
1261
-
1262
- console.log(chalk.green(`✓ Installed expansion pack: ${pack.name} to ${`.${packId}`}`));
1263
- } catch (error) {
1264
- console.error(chalk.red(`Failed to install expansion pack ${packId}: ${error.message}`));
1265
- console.error(chalk.red(`Stack trace: ${error.stack}`));
1266
- }
1267
- }
1268
-
1269
- return installedFiles;
1270
- }
1271
-
1272
- async resolveExpansionPackCoreDependencies(installDir, expansionDotFolder, packId, spinner) {
1273
- const glob = require('glob');
1274
- const yaml = require('js-yaml');
1275
- const fs = require('fs').promises;
1276
-
1277
- // Find all agent files in the expansion pack
1278
- const agentFiles = glob.sync('agents/*.md', {
1279
- cwd: expansionDotFolder
1280
- });
1281
-
1282
- for (const agentFile of agentFiles) {
1283
- const agentPath = path.join(expansionDotFolder, agentFile);
1284
- const agentContent = await fs.readFile(agentPath, 'utf8');
1285
-
1286
- // Extract YAML frontmatter to check dependencies
1287
- const yamlContent = extractYamlFromAgent(agentContent);
1288
- if (yamlContent) {
1289
- try {
1290
- const agentConfig = yaml.load(yamlContent);
1291
- const dependencies = agentConfig.dependencies || {};
1292
-
1293
- // Check for core dependencies (those that don't exist in the expansion pack)
1294
- for (const depType of ['tasks', 'templates', 'checklists', 'workflows', 'utils', 'data']) {
1295
- const deps = dependencies[depType] || [];
1296
-
1297
- for (const dep of deps) {
1298
- const depFileName = dep.endsWith('.md') ? dep : `${dep}.md`;
1299
- const expansionDepPath = path.join(expansionDotFolder, depType, depFileName);
1300
-
1301
- // Check if dependency exists in expansion pack
1302
- if (!(await fileManager.pathExists(expansionDepPath))) {
1303
- // Try to find it in core
1304
- const coreDepPath = path.join(configLoader.getBmadCorePath(), depType, depFileName);
1305
-
1306
- if (await fileManager.pathExists(coreDepPath)) {
1307
- spinner.text = `Copying core dependency ${dep} for ${packId}...`;
1308
-
1309
- // Copy from core to expansion pack dot folder with {root} replacement
1310
- const destPath = path.join(expansionDotFolder, depType, depFileName);
1311
- await fileManager.copyFileWithRootReplacement(coreDepPath, destPath, `.${packId}`);
1312
-
1313
- console.log(chalk.dim(` Added core dependency: ${depType}/${depFileName}`));
1314
- } else {
1315
- console.warn(chalk.yellow(` Warning: Dependency ${depType}/${dep} not found in core or expansion pack`));
1316
- }
1317
- }
1318
- }
1319
- }
1320
- } catch (error) {
1321
- console.warn(chalk.yellow(` Warning: Could not parse agent dependencies: ${error.message}`));
1322
- }
1323
- }
1324
- }
1325
- }
1326
-
1327
- async resolveExpansionPackCoreAgents(installDir, expansionDotFolder, packId, spinner) {
1328
- const glob = require('glob');
1329
- const yaml = require('js-yaml');
1330
- const fs = require('fs').promises;
1331
-
1332
- // Find all team files in the expansion pack
1333
- const teamFiles = glob.sync('agent-teams/*.yaml', {
1334
- cwd: expansionDotFolder
1335
- });
1336
-
1337
- // Also get existing agents in the expansion pack
1338
- const existingAgents = new Set();
1339
- const agentFiles = glob.sync('agents/*.md', {
1340
- cwd: expansionDotFolder
1341
- });
1342
- for (const agentFile of agentFiles) {
1343
- const agentName = path.basename(agentFile, '.md');
1344
- existingAgents.add(agentName);
1345
- }
1346
-
1347
- // Process each team file
1348
- for (const teamFile of teamFiles) {
1349
- const teamPath = path.join(expansionDotFolder, teamFile);
1350
- const teamContent = await fs.readFile(teamPath, 'utf8');
1351
-
1352
- try {
1353
- const teamConfig = yaml.load(teamContent);
1354
- const agents = teamConfig.agents || [];
1355
-
1356
- // Add bmad-orchestrator if not present (required for all teams)
1357
- if (!agents.includes('bmad-orchestrator')) {
1358
- agents.unshift('bmad-orchestrator');
1359
- }
1360
-
1361
- // Check each agent in the team
1362
- for (const agentId of agents) {
1363
- if (!existingAgents.has(agentId)) {
1364
- // Agent not in expansion pack, try to get from core
1365
- const coreAgentPath = path.join(configLoader.getBmadCorePath(), 'agents', `${agentId}.md`);
1366
-
1367
- if (await fileManager.pathExists(coreAgentPath)) {
1368
- spinner.text = `Copying core agent ${agentId} for ${packId}...`;
1369
-
1370
- // Copy agent file with {root} replacement
1371
- const destPath = path.join(expansionDotFolder, 'agents', `${agentId}.md`);
1372
- await fileManager.copyFileWithRootReplacement(coreAgentPath, destPath, `.${packId}`);
1373
- existingAgents.add(agentId);
1374
-
1375
- console.log(chalk.dim(` Added core agent: ${agentId}`));
1376
-
1377
- // Now resolve this agent's dependencies too
1378
- const agentContent = await fs.readFile(coreAgentPath, 'utf8');
1379
- const yamlContent = extractYamlFromAgent(agentContent, true);
1380
-
1381
- if (yamlContent) {
1382
- try {
1383
-
1384
- const agentConfig = yaml.load(yamlContent);
1385
- const dependencies = agentConfig.dependencies || {};
1386
-
1387
- // Copy all dependencies for this agent
1388
- for (const depType of ['tasks', 'templates', 'checklists', 'workflows', 'utils', 'data']) {
1389
- const deps = dependencies[depType] || [];
1390
-
1391
- for (const dep of deps) {
1392
- const depFileName = dep.endsWith('.md') || dep.endsWith('.yaml') ? dep : `${dep}.md`;
1393
- const expansionDepPath = path.join(expansionDotFolder, depType, depFileName);
1394
-
1395
- // Check if dependency exists in expansion pack
1396
- if (!(await fileManager.pathExists(expansionDepPath))) {
1397
- // Try to find it in core
1398
- const coreDepPath = path.join(configLoader.getBmadCorePath(), depType, depFileName);
1399
-
1400
- if (await fileManager.pathExists(coreDepPath)) {
1401
- const destDepPath = path.join(expansionDotFolder, depType, depFileName);
1402
- await fileManager.copyFileWithRootReplacement(coreDepPath, destDepPath, `.${packId}`);
1403
- console.log(chalk.dim(` Added agent dependency: ${depType}/${depFileName}`));
1404
- } else {
1405
- // Try common folder
1406
- const sourceBase = path.dirname(path.dirname(path.dirname(path.dirname(__filename)))); // Go up to project root
1407
- const commonDepPath = path.join(sourceBase, 'common', depType, depFileName);
1408
- if (await fileManager.pathExists(commonDepPath)) {
1409
- const destDepPath = path.join(expansionDotFolder, depType, depFileName);
1410
- await fileManager.copyFile(commonDepPath, destDepPath);
1411
- console.log(chalk.dim(` Added agent dependency from common: ${depType}/${depFileName}`));
1412
- }
1413
- }
1414
- }
1415
- }
1416
- }
1417
- } catch (error) {
1418
- console.warn(chalk.yellow(` Warning: Could not parse agent ${agentId} dependencies: ${error.message}`));
1419
- }
1420
- }
1421
- } else {
1422
- console.warn(chalk.yellow(` Warning: Core agent ${agentId} not found for team ${path.basename(teamFile, '.yaml')}`));
1423
- }
1424
- }
1425
- }
1426
- } catch (error) {
1427
- console.warn(chalk.yellow(` Warning: Could not parse team file ${teamFile}: ${error.message}`));
1428
- }
1429
- }
1430
- }
1431
-
1432
- getWebBundleInfo(config) {
1433
- const webBundleType = config.webBundleType || 'all';
1434
-
1435
- switch (webBundleType) {
1436
- case 'all':
1437
- return 'all bundles';
1438
- case 'agents':
1439
- return 'individual agents only';
1440
- case 'teams':
1441
- return config.selectedWebBundleTeams ?
1442
- `teams: ${config.selectedWebBundleTeams.join(', ')}` :
1443
- 'selected teams';
1444
- case 'custom':
1445
- const parts = [];
1446
- if (config.selectedWebBundleTeams && config.selectedWebBundleTeams.length > 0) {
1447
- parts.push(`teams: ${config.selectedWebBundleTeams.join(', ')}`);
1448
- }
1449
- if (config.includeIndividualAgents) {
1450
- parts.push('individual agents');
1451
- }
1452
- return parts.length > 0 ? parts.join(' + ') : 'custom selection';
1453
- default:
1454
- return 'selected bundles';
1455
- }
1456
- }
1457
-
1458
- async installWebBundles(webBundlesDirectory, config, spinner) {
1459
- // Ensure modules are initialized
1460
- await initializeModules();
1461
-
1462
- try {
1463
- // Find the dist directory in the BMad installation
1464
- const distDir = configLoader.getDistPath();
1465
-
1466
- if (!(await fileManager.pathExists(distDir))) {
1467
- console.warn(chalk.yellow('Web bundles not found. Run "npm run build" to generate them.'));
1468
- return;
1469
- }
1470
-
1471
- // Ensure web bundles directory exists
1472
- await fileManager.ensureDirectory(webBundlesDirectory);
1473
-
1474
- const webBundleType = config.webBundleType || 'all';
1475
-
1476
- if (webBundleType === 'all') {
1477
- // Copy the entire dist directory structure
1478
- await fileManager.copyDirectory(distDir, webBundlesDirectory);
1479
- console.log(chalk.green(`✓ Installed all web bundles to: ${webBundlesDirectory}`));
1480
- } else {
1481
- let copiedCount = 0;
1482
-
1483
- // Copy specific selections based on type
1484
- if (webBundleType === 'agents' || (webBundleType === 'custom' && config.includeIndividualAgents)) {
1485
- const agentsSource = path.join(distDir, 'agents');
1486
- const agentsTarget = path.join(webBundlesDirectory, 'agents');
1487
- if (await fileManager.pathExists(agentsSource)) {
1488
- await fileManager.copyDirectory(agentsSource, agentsTarget);
1489
- console.log(chalk.green(`✓ Copied individual agent bundles`));
1490
- copiedCount += 10; // Approximate count for agents
1491
- }
1492
- }
1493
-
1494
- if (webBundleType === 'teams' || webBundleType === 'custom') {
1495
- if (config.selectedWebBundleTeams && config.selectedWebBundleTeams.length > 0) {
1496
- const teamsSource = path.join(distDir, 'teams');
1497
- const teamsTarget = path.join(webBundlesDirectory, 'teams');
1498
- await fileManager.ensureDirectory(teamsTarget);
1499
-
1500
- for (const teamId of config.selectedWebBundleTeams) {
1501
- const teamFile = `${teamId}.txt`;
1502
- const sourcePath = path.join(teamsSource, teamFile);
1503
- const targetPath = path.join(teamsTarget, teamFile);
1504
-
1505
- if (await fileManager.pathExists(sourcePath)) {
1506
- await fileManager.copyFile(sourcePath, targetPath);
1507
- copiedCount++;
1508
- console.log(chalk.green(`✓ Copied team bundle: ${teamId}`));
1509
- }
1510
- }
1511
- }
1512
- }
1513
-
1514
- // Always copy expansion packs if they exist
1515
- const expansionSource = path.join(distDir, 'expansion-packs');
1516
- const expansionTarget = path.join(webBundlesDirectory, 'expansion-packs');
1517
- if (await fileManager.pathExists(expansionSource)) {
1518
- await fileManager.copyDirectory(expansionSource, expansionTarget);
1519
- console.log(chalk.green(`✓ Copied expansion pack bundles`));
1520
- }
1521
-
1522
- console.log(chalk.green(`✓ Installed ${copiedCount} selected web bundles to: ${webBundlesDirectory}`));
1523
- }
1524
- } catch (error) {
1525
- console.error(chalk.red(`Failed to install web bundles: ${error.message}`));
1526
- }
1527
- }
1528
-
1529
- async copyCommonItems(installDir, targetSubdir, spinner) {
1530
- // Ensure modules are initialized
1531
- await initializeModules();
1532
-
1533
- const glob = require('glob');
1534
- const fs = require('fs').promises;
1535
- const sourceBase = path.dirname(path.dirname(path.dirname(path.dirname(__filename)))); // Go up to project root
1536
- const commonPath = path.join(sourceBase, 'common');
1537
- const targetPath = path.join(installDir, targetSubdir);
1538
- const copiedFiles = [];
1539
-
1540
- // Check if common/ exists
1541
- if (!(await fileManager.pathExists(commonPath))) {
1542
- console.warn(chalk.yellow('Warning: common/ folder not found'));
1543
- return copiedFiles;
1544
- }
1545
-
1546
- // Copy all items from common/ to target
1547
- const commonItems = glob.sync('**/*', {
1548
- cwd: commonPath,
1549
- nodir: true
1550
- });
1551
-
1552
- for (const item of commonItems) {
1553
- const sourcePath = path.join(commonPath, item);
1554
- const destPath = path.join(targetPath, item);
1555
-
1556
- // Read the file content
1557
- const content = await fs.readFile(sourcePath, 'utf8');
1558
-
1559
- // Replace {root} with the target subdirectory
1560
- const updatedContent = content.replace(/\{root\}/g, targetSubdir);
1561
-
1562
- // Ensure directory exists
1563
- await fileManager.ensureDirectory(path.dirname(destPath));
1564
-
1565
- // Write the updated content
1566
- await fs.writeFile(destPath, updatedContent, 'utf8');
1567
- copiedFiles.push(path.join(targetSubdir, item));
1568
- }
1569
-
1570
- console.log(chalk.dim(` Added ${commonItems.length} common utilities`));
1571
- return copiedFiles;
1572
- }
1573
-
1574
- async detectExpansionPacks(installDir) {
1575
- const expansionPacks = {};
1576
- const glob = require("glob");
1577
-
1578
- // Find all dot folders that might be expansion packs
1579
- const dotFolders = glob.sync(".*", {
1580
- cwd: installDir,
1581
- ignore: [".git", ".git/**", ".bmad-core", ".bmad-core/**"],
1582
- });
1583
-
1584
- for (const folder of dotFolders) {
1585
- const folderPath = path.join(installDir, folder);
1586
- const stats = await fileManager.pathExists(folderPath);
1587
-
1588
- if (stats) {
1589
- // Check if it has a manifest
1590
- const manifestPath = path.join(folderPath, "install-manifest.yaml");
1591
- if (await fileManager.pathExists(manifestPath)) {
1592
- const manifest = await fileManager.readExpansionPackManifest(installDir, folder.substring(1));
1593
- if (manifest) {
1594
- expansionPacks[folder.substring(1)] = {
1595
- path: folderPath,
1596
- manifest: manifest,
1597
- hasManifest: true
1598
- };
1599
- }
1600
- } else {
1601
- // Check if it has a config.yaml (expansion pack without manifest)
1602
- const configPath = path.join(folderPath, "config.yaml");
1603
- if (await fileManager.pathExists(configPath)) {
1604
- expansionPacks[folder.substring(1)] = {
1605
- path: folderPath,
1606
- manifest: null,
1607
- hasManifest: false
1608
- };
1609
- }
1610
- }
1611
- }
1612
- }
1613
-
1614
- return expansionPacks;
1615
- }
1616
-
1617
- async repairExpansionPack(installDir, packId, pack, integrity, spinner) {
1618
- spinner.start(`Repairing ${pack.name}...`);
1619
-
1620
- try {
1621
- const expansionDotFolder = path.join(installDir, `.${packId}`);
1622
-
1623
- // Back up modified files
1624
- if (integrity.modified.length > 0) {
1625
- spinner.text = "Backing up modified files...";
1626
- for (const file of integrity.modified) {
1627
- const filePath = path.join(installDir, file);
1628
- if (await fileManager.pathExists(filePath)) {
1629
- const backupPath = await fileManager.backupFile(filePath);
1630
- console.log(chalk.dim(` Backed up: ${file} → ${path.basename(backupPath)}`));
1631
- }
1632
- }
1633
- }
1634
-
1635
- // Restore missing and modified files
1636
- spinner.text = "Restoring files...";
1637
- const filesToRestore = [...integrity.missing, ...integrity.modified];
1638
-
1639
- for (const file of filesToRestore) {
1640
- // Skip the manifest file itself
1641
- if (file.endsWith('install-manifest.yaml')) continue;
1642
-
1643
- const relativePath = file.replace(`.${packId}/`, '');
1644
- const sourcePath = path.join(pack.packPath, relativePath);
1645
- const destPath = path.join(installDir, file);
1646
-
1647
- // Check if this is a common/ file that needs special processing
1648
- const commonBase = path.dirname(path.dirname(path.dirname(path.dirname(__filename))));
1649
- const commonSourcePath = path.join(commonBase, 'common', relativePath);
1650
-
1651
- if (await fileManager.pathExists(commonSourcePath)) {
1652
- // This is a common/ file - needs template processing
1653
- const fs = require('fs').promises;
1654
- const content = await fs.readFile(commonSourcePath, 'utf8');
1655
- const updatedContent = content.replace(/\{root\}/g, `.${packId}`);
1656
- await fileManager.ensureDirectory(path.dirname(destPath));
1657
- await fs.writeFile(destPath, updatedContent, 'utf8');
1658
- spinner.text = `Restored: ${file}`;
1659
- } else if (await fileManager.pathExists(sourcePath)) {
1660
- // Regular file from expansion pack
1661
- await fileManager.copyFile(sourcePath, destPath);
1662
- spinner.text = `Restored: ${file}`;
1663
- } else {
1664
- console.warn(chalk.yellow(` Warning: Source file not found: ${file}`));
1665
- }
1666
- }
1667
-
1668
- spinner.succeed(`${pack.name} repaired successfully!`);
1669
-
1670
- // Show summary
1671
- console.log(chalk.green(`\n✓ ${pack.name} repaired!`));
1672
- if (integrity.missing.length > 0) {
1673
- console.log(chalk.green(` Restored ${integrity.missing.length} missing files`));
1674
- }
1675
- if (integrity.modified.length > 0) {
1676
- console.log(chalk.green(` Restored ${integrity.modified.length} modified files (backups created)`));
1677
- }
1678
-
1679
- } catch (error) {
1680
- spinner.fail(`Failed to repair ${pack.name}`);
1681
- console.error(chalk.red(`Error: ${error.message}`));
1682
- }
1683
- }
1684
-
1685
- compareVersions(v1, v2) {
1686
- // Simple semver comparison
1687
- const parts1 = v1.split('.').map(Number);
1688
- const parts2 = v2.split('.').map(Number);
1689
-
1690
- for (let i = 0; i < 3; i++) {
1691
- const part1 = parts1[i] || 0;
1692
- const part2 = parts2[i] || 0;
1693
-
1694
- if (part1 > part2) return 1;
1695
- if (part1 < part2) return -1;
1696
- }
1697
-
1698
- return 0;
1699
- }
1700
-
1701
- async cleanupLegacyYmlFiles(installDir, spinner) {
1702
- const glob = require('glob');
1703
- const fs = require('fs').promises;
1704
-
1705
- try {
1706
- // Find all .yml files in the installation directory
1707
- const ymlFiles = glob.sync('**/*.yml', {
1708
- cwd: installDir,
1709
- ignore: ['**/node_modules/**', '**/.git/**']
1710
- });
1711
-
1712
- let deletedCount = 0;
1713
-
1714
- for (const ymlFile of ymlFiles) {
1715
- // Check if corresponding .yaml file exists
1716
- const yamlFile = ymlFile.replace(/\.yml$/, '.yaml');
1717
- const ymlPath = path.join(installDir, ymlFile);
1718
- const yamlPath = path.join(installDir, yamlFile);
1719
-
1720
- if (await fileManager.pathExists(yamlPath)) {
1721
- // .yaml counterpart exists, delete the .yml file
1722
- await fs.unlink(ymlPath);
1723
- deletedCount++;
1724
- console.log(chalk.dim(` Removed legacy: ${ymlFile} (replaced by ${yamlFile})`));
1725
- }
1726
- }
1727
-
1728
- if (deletedCount > 0) {
1729
- console.log(chalk.green(`✓ Cleaned up ${deletedCount} legacy .yml files`));
1730
- }
1731
-
1732
- } catch (error) {
1733
- console.warn(chalk.yellow(`Warning: Could not cleanup legacy .yml files: ${error.message}`));
1734
- }
1735
- }
1736
-
1737
627
  async findInstallation() {
1738
628
  // Look for .bmad-core in current directory or parent directories
1739
629
  let currentDir = process.cwd();
1740
630
 
1741
631
  while (currentDir !== path.dirname(currentDir)) {
1742
632
  const bmadDir = path.join(currentDir, ".bmad-core");
1743
- const manifestPath = path.join(bmadDir, "install-manifest.yaml");
633
+ const manifestPath = path.join(bmadDir, "install-manifest.yml");
1744
634
 
1745
635
  if (await fileManager.pathExists(manifestPath)) {
1746
636
  return bmadDir;
@@ -1751,7 +641,7 @@ class Installer {
1751
641
 
1752
642
  // Also check if we're inside a .bmad-core directory
1753
643
  if (path.basename(process.cwd()) === ".bmad-core") {
1754
- const manifestPath = path.join(process.cwd(), "install-manifest.yaml");
644
+ const manifestPath = path.join(process.cwd(), "install-manifest.yml");
1755
645
  if (await fileManager.pathExists(manifestPath)) {
1756
646
  return process.cwd();
1757
647
  }