bmad-method 5.0.0 → 5.1.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 (329) hide show
  1. package/.github/FUNDING.yaml +15 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
  4. package/.github/workflows/discord.yaml +25 -0
  5. package/.github/workflows/format-check.yaml +42 -0
  6. package/.github/workflows/manual-release.yaml +173 -0
  7. package/.husky/pre-commit +3 -2
  8. package/.vscode/settings.json +67 -74
  9. package/CHANGELOG.md +564 -19
  10. package/CONTRIBUTING.md +168 -5
  11. package/LICENSE +1 -1
  12. package/README.md +146 -218
  13. package/bmad-core/agent-teams/team-all.yaml +14 -0
  14. package/bmad-core/agent-teams/team-fullstack.yaml +18 -0
  15. package/bmad-core/agent-teams/team-ide-minimal.yaml +10 -0
  16. package/bmad-core/agent-teams/team-no-ui.yaml +13 -0
  17. package/bmad-core/agents/analyst.md +81 -0
  18. package/bmad-core/agents/architect.md +83 -0
  19. package/bmad-core/agents/bmad-master.md +107 -0
  20. package/bmad-core/agents/bmad-orchestrator.md +149 -0
  21. package/bmad-core/agents/dev.md +75 -0
  22. package/bmad-core/agents/pm.md +81 -0
  23. package/bmad-core/agents/po.md +76 -0
  24. package/bmad-core/agents/qa.md +88 -0
  25. package/bmad-core/agents/sm.md +62 -0
  26. package/bmad-core/agents/ux-expert.md +66 -0
  27. package/{.bmad-core → bmad-core}/checklists/architect-checklist.md +0 -5
  28. package/{.bmad-core → bmad-core}/checklists/change-checklist.md +2 -2
  29. package/{.bmad-core → bmad-core}/checklists/pm-checklist.md +0 -5
  30. package/{.bmad-core → bmad-core}/checklists/po-master-checklist.md +0 -9
  31. package/{.bmad-core → bmad-core}/checklists/story-dod-checklist.md +0 -7
  32. package/{.bmad-core → bmad-core}/checklists/story-draft-checklist.md +1 -4
  33. package/bmad-core/core-config.yaml +20 -0
  34. package/bmad-core/data/bmad-kb.md +806 -0
  35. package/bmad-core/data/brainstorming-techniques.md +36 -0
  36. package/bmad-core/data/elicitation-methods.md +154 -0
  37. package/bmad-core/data/test-levels-framework.md +146 -0
  38. package/bmad-core/data/test-priorities-matrix.md +172 -0
  39. package/bmad-core/tasks/advanced-elicitation.md +117 -0
  40. package/{.bmad-core → bmad-core}/tasks/correct-course.md +9 -12
  41. package/bmad-core/tasks/create-brownfield-story.md +312 -0
  42. package/{.bmad-core → bmad-core}/tasks/create-deep-research-prompt.md +4 -27
  43. package/bmad-core/tasks/create-next-story.md +112 -0
  44. package/bmad-core/tasks/document-project.md +343 -0
  45. package/bmad-core/tasks/facilitate-brainstorming-session.md +136 -0
  46. package/bmad-core/tasks/generate-ai-frontend-prompt.md +51 -0
  47. package/{.bmad-core → bmad-core}/tasks/index-docs.md +3 -13
  48. package/bmad-core/tasks/kb-mode-interaction.md +75 -0
  49. package/bmad-core/tasks/nfr-assess.md +343 -0
  50. package/bmad-core/tasks/qa-gate.md +159 -0
  51. package/bmad-core/tasks/review-story.md +314 -0
  52. package/bmad-core/tasks/risk-profile.md +353 -0
  53. package/{.bmad-core → bmad-core}/tasks/shard-doc.md +27 -15
  54. package/bmad-core/tasks/test-design.md +174 -0
  55. package/bmad-core/tasks/trace-requirements.md +264 -0
  56. package/bmad-core/tasks/validate-next-story.md +134 -0
  57. package/bmad-core/templates/architecture-tmpl.yaml +650 -0
  58. package/bmad-core/templates/brainstorming-output-tmpl.yaml +156 -0
  59. package/bmad-core/templates/brownfield-architecture-tmpl.yaml +476 -0
  60. package/bmad-core/templates/brownfield-prd-tmpl.yaml +280 -0
  61. package/bmad-core/templates/competitor-analysis-tmpl.yaml +306 -0
  62. package/bmad-core/templates/front-end-architecture-tmpl.yaml +218 -0
  63. package/bmad-core/templates/front-end-spec-tmpl.yaml +349 -0
  64. package/bmad-core/templates/fullstack-architecture-tmpl.yaml +823 -0
  65. package/bmad-core/templates/market-research-tmpl.yaml +252 -0
  66. package/bmad-core/templates/prd-tmpl.yaml +202 -0
  67. package/bmad-core/templates/project-brief-tmpl.yaml +221 -0
  68. package/bmad-core/templates/qa-gate-tmpl.yaml +102 -0
  69. package/bmad-core/templates/story-tmpl.yaml +137 -0
  70. package/bmad-core/workflows/brownfield-fullstack.yaml +297 -0
  71. package/bmad-core/workflows/brownfield-service.yaml +187 -0
  72. package/bmad-core/workflows/brownfield-ui.yaml +197 -0
  73. package/{.bmad-core/workflows/greenfield-fullstack.yml → bmad-core/workflows/greenfield-fullstack.yaml} +140 -77
  74. package/bmad-core/workflows/greenfield-service.yaml +206 -0
  75. package/bmad-core/workflows/greenfield-ui.yaml +235 -0
  76. package/common/tasks/create-doc.md +101 -0
  77. package/{.bmad-core → common}/tasks/execute-checklist.md +2 -13
  78. package/common/utils/bmad-doc-template.md +325 -0
  79. package/common/utils/workflow-management.md +69 -0
  80. package/dist/agents/analyst.txt +2889 -0
  81. package/dist/agents/architect.txt +3552 -0
  82. package/dist/agents/bmad-master.txt +8769 -0
  83. package/dist/agents/bmad-orchestrator.txt +1513 -0
  84. package/dist/agents/dev.txt +414 -0
  85. package/{.bmad-core/web-bundles → dist}/agents/pm.txt +668 -1119
  86. package/{.bmad-core/web-bundles → dist}/agents/po.txt +341 -484
  87. package/dist/agents/qa.txt +1987 -0
  88. package/dist/agents/sm.txt +658 -0
  89. package/dist/agents/ux-expert.txt +694 -0
  90. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +2371 -0
  91. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.txt +1620 -0
  92. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.txt +815 -0
  93. package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +10952 -0
  94. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.txt +4012 -0
  95. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.txt +3698 -0
  96. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.txt +450 -0
  97. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.txt +973 -0
  98. package/dist/expansion-packs/bmad-2d-unity-game-dev/teams/unity-2d-game-team.txt +15376 -0
  99. package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +2075 -0
  100. package/dist/teams/team-all.txt +12682 -0
  101. package/dist/teams/team-fullstack.txt +10421 -0
  102. package/dist/teams/team-ide-minimal.txt +5103 -0
  103. package/dist/teams/team-no-ui.txt +8980 -0
  104. package/docs/GUIDING-PRINCIPLES.md +91 -0
  105. package/docs/core-architecture.md +219 -0
  106. package/docs/enhanced-ide-development-workflow.md +248 -0
  107. package/docs/expansion-packs.md +280 -0
  108. package/docs/how-to-contribute-with-pull-requests.md +158 -0
  109. package/docs/user-guide.md +504 -0
  110. package/docs/versioning-and-releases.md +8 -16
  111. package/docs/versions.md +4 -5
  112. package/docs/working-in-the-brownfield.md +597 -0
  113. package/eslint.config.mjs +119 -0
  114. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/Complete AI Agent System - Flowchart.svg +102 -0
  115. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.1 Google Cloud Project Setup/1.1.1 - Initial Project Configuration - bash copy.txt +13 -0
  116. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.1 Google Cloud Project Setup/1.1.1 - Initial Project Configuration - bash.txt +13 -0
  117. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.2 Agent Development Kit Installation/1.2.2 - Basic Project Structure - txt.txt +25 -0
  118. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.3 Core Configuration Files/1.3.1 - settings.py +34 -0
  119. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.3 Core Configuration Files/1.3.2 - main.py - Base Application.py +70 -0
  120. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.4 Deployment Configuration/1.4.2 - cloudbuild.yaml +26 -0
  121. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/README.md +109 -0
  122. package/expansion-packs/README.md +2 -112
  123. package/expansion-packs/bmad-2d-phaser-game-dev/agent-teams/phaser-2d-nodejs-game-team.yaml +13 -0
  124. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.md +71 -0
  125. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.md +78 -0
  126. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.md +64 -0
  127. package/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-design-checklist.md +201 -0
  128. package/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-story-dod-checklist.md +160 -0
  129. package/expansion-packs/bmad-2d-phaser-game-dev/config.yaml +8 -0
  130. package/expansion-packs/bmad-2d-phaser-game-dev/data/bmad-kb.md +250 -0
  131. package/expansion-packs/bmad-2d-phaser-game-dev/data/development-guidelines.md +647 -0
  132. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/advanced-elicitation.md +110 -0
  133. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/create-game-story.md +216 -0
  134. package/expansion-packs/bmad-2d-phaser-game-dev/tasks/game-design-brainstorming.md +290 -0
  135. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-architecture-tmpl.yaml +613 -0
  136. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-brief-tmpl.yaml +356 -0
  137. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-design-doc-tmpl.yaml +343 -0
  138. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-story-tmpl.yaml +253 -0
  139. package/expansion-packs/bmad-2d-phaser-game-dev/templates/level-design-doc-tmpl.yaml +484 -0
  140. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-dev-greenfield.yaml +183 -0
  141. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-prototype.yaml +175 -0
  142. package/expansion-packs/bmad-2d-unity-game-dev/agent-teams/unity-2d-game-team.yaml +14 -0
  143. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.md +80 -0
  144. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.md +77 -0
  145. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.md +78 -0
  146. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.md +65 -0
  147. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-architect-checklist.md +391 -0
  148. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-change-checklist.md +203 -0
  149. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-design-checklist.md +201 -0
  150. package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-story-dod-checklist.md +124 -0
  151. package/expansion-packs/bmad-2d-unity-game-dev/config.yaml +6 -0
  152. package/expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md +769 -0
  153. package/expansion-packs/bmad-2d-unity-game-dev/data/development-guidelines.md +586 -0
  154. package/expansion-packs/bmad-2d-unity-game-dev/tasks/advanced-elicitation.md +110 -0
  155. package/expansion-packs/bmad-2d-unity-game-dev/tasks/correct-course-game.md +141 -0
  156. package/expansion-packs/bmad-2d-unity-game-dev/tasks/create-game-story.md +184 -0
  157. package/expansion-packs/bmad-2d-unity-game-dev/tasks/game-design-brainstorming.md +290 -0
  158. package/expansion-packs/bmad-2d-unity-game-dev/tasks/validate-game-story.md +200 -0
  159. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-architecture-tmpl.yaml +1030 -0
  160. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-brief-tmpl.yaml +356 -0
  161. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml +705 -0
  162. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-story-tmpl.yaml +256 -0
  163. package/expansion-packs/bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml +484 -0
  164. package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-dev-greenfield.yaml +183 -0
  165. package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-prototype.yaml +175 -0
  166. package/expansion-packs/{infrastructure-devops → bmad-infrastructure-devops}/README.md +9 -9
  167. package/expansion-packs/{infrastructure-devops → bmad-infrastructure-devops}/agents/infra-devops-platform.md +30 -18
  168. package/expansion-packs/{infrastructure-devops → bmad-infrastructure-devops}/checklists/infrastructure-checklist.md +1 -1
  169. package/expansion-packs/bmad-infrastructure-devops/config.yaml +9 -0
  170. package/expansion-packs/bmad-infrastructure-devops/data/bmad-kb.md +305 -0
  171. package/expansion-packs/{infrastructure-devops → bmad-infrastructure-devops}/tasks/review-infrastructure.md +4 -5
  172. package/expansion-packs/{infrastructure-devops → bmad-infrastructure-devops}/tasks/validate-infrastructure.md +4 -5
  173. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-architecture-tmpl.yaml +424 -0
  174. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.yaml +629 -0
  175. package/package.json +74 -42
  176. package/prettier.config.mjs +32 -0
  177. package/release_notes.md +25 -0
  178. package/tools/bmad-npx-wrapper.js +13 -15
  179. package/tools/builders/web-builder.js +544 -15
  180. package/tools/bump-all-versions.js +115 -0
  181. package/tools/bump-expansion-version.js +90 -0
  182. package/tools/cli.js +65 -32
  183. package/tools/flattener/aggregate.js +76 -0
  184. package/tools/flattener/binary.js +80 -0
  185. package/tools/flattener/discovery.js +71 -0
  186. package/tools/flattener/files.js +35 -0
  187. package/tools/flattener/ignoreRules.js +176 -0
  188. package/tools/flattener/main.js +573 -0
  189. package/tools/flattener/projectRoot.js +206 -0
  190. package/tools/flattener/prompts.js +44 -0
  191. package/tools/flattener/stats.helpers.js +395 -0
  192. package/tools/flattener/stats.js +80 -0
  193. package/tools/flattener/test-matrix.js +413 -0
  194. package/tools/flattener/xml.js +88 -0
  195. package/tools/installer/README.md +3 -53
  196. package/tools/installer/bin/bmad.js +475 -90
  197. package/tools/installer/config/ide-agent-config.yaml +58 -0
  198. package/tools/installer/config/install.config.yaml +123 -0
  199. package/tools/installer/lib/config-loader.js +208 -40
  200. package/tools/installer/lib/file-manager.js +258 -55
  201. package/tools/installer/lib/ide-base-setup.js +228 -0
  202. package/tools/installer/lib/ide-setup.js +1265 -253
  203. package/tools/installer/lib/installer.js +1651 -310
  204. package/tools/installer/lib/memory-profiler.js +225 -0
  205. package/tools/installer/lib/module-manager.js +114 -0
  206. package/tools/installer/lib/resource-locator.js +308 -0
  207. package/tools/installer/package.json +25 -24
  208. package/tools/lib/dependency-resolver.js +44 -48
  209. package/tools/lib/yaml-utils.js +29 -0
  210. package/tools/md-assets/web-agent-startup-instructions.md +39 -0
  211. package/tools/preview-release-notes.js +66 -0
  212. package/tools/shared/bannerArt.js +105 -0
  213. package/tools/sync-installer-version.js +7 -9
  214. package/tools/update-expansion-version.js +53 -0
  215. package/tools/upgraders/v3-to-v4-upgrader.js +221 -320
  216. package/tools/version-bump.js +42 -27
  217. package/tools/yaml-format.js +57 -44
  218. package/.bmad-core/agent-teams/team-all.yml +0 -16
  219. package/.bmad-core/agent-teams/team-fullstack.yml +0 -26
  220. package/.bmad-core/agent-teams/team-no-ui.yml +0 -15
  221. package/.bmad-core/agents/analyst.md +0 -59
  222. package/.bmad-core/agents/architect.md +0 -66
  223. package/.bmad-core/agents/bmad-master.md +0 -104
  224. package/.bmad-core/agents/bmad-orchestrator.md +0 -81
  225. package/.bmad-core/agents/dev.md +0 -70
  226. package/.bmad-core/agents/pm.md +0 -59
  227. package/.bmad-core/agents/po.md +0 -60
  228. package/.bmad-core/agents/qa.md +0 -52
  229. package/.bmad-core/agents/sm.md +0 -55
  230. package/.bmad-core/agents/ux-expert.md +0 -66
  231. package/.bmad-core/data/bmad-kb.md +0 -47
  232. package/.bmad-core/schemas/agent-team-schema.yml +0 -153
  233. package/.bmad-core/tasks/advanced-elicitation.md +0 -92
  234. package/.bmad-core/tasks/brainstorming-techniques.md +0 -238
  235. package/.bmad-core/tasks/core-dump.md +0 -74
  236. package/.bmad-core/tasks/create-agent.md +0 -202
  237. package/.bmad-core/tasks/create-doc.md +0 -74
  238. package/.bmad-core/tasks/create-expansion-pack.md +0 -425
  239. package/.bmad-core/tasks/create-next-story.md +0 -206
  240. package/.bmad-core/tasks/create-team.md +0 -229
  241. package/.bmad-core/tasks/doc-migration-task.md +0 -143
  242. package/.bmad-core/tasks/generate-ai-frontend-prompt.md +0 -58
  243. package/.bmad-core/templates/agent-tmpl.md +0 -58
  244. package/.bmad-core/templates/architecture-tmpl.md +0 -771
  245. package/.bmad-core/templates/brownfield-architecture-tmpl.md +0 -542
  246. package/.bmad-core/templates/brownfield-prd-tmpl.md +0 -240
  247. package/.bmad-core/templates/competitor-analysis-tmpl.md +0 -289
  248. package/.bmad-core/templates/expansion-pack-plan-tmpl.md +0 -91
  249. package/.bmad-core/templates/front-end-architecture-tmpl.md +0 -173
  250. package/.bmad-core/templates/front-end-spec-tmpl.md +0 -411
  251. package/.bmad-core/templates/fullstack-architecture-tmpl.md +0 -1016
  252. package/.bmad-core/templates/market-research-tmpl.md +0 -261
  253. package/.bmad-core/templates/prd-tmpl.md +0 -200
  254. package/.bmad-core/templates/project-brief-tmpl.md +0 -228
  255. package/.bmad-core/templates/simple-project-prd-tmpl.md +0 -461
  256. package/.bmad-core/templates/story-tmpl.md +0 -61
  257. package/.bmad-core/templates/web-agent-startup-instructions-template.md +0 -39
  258. package/.bmad-core/utils/agent-switcher.ide.md +0 -112
  259. package/.bmad-core/utils/template-format.md +0 -26
  260. package/.bmad-core/utils/workflow-management.md +0 -224
  261. package/.bmad-core/web-bundles/agents/analyst.txt +0 -1684
  262. package/.bmad-core/web-bundles/agents/architect.txt +0 -3584
  263. package/.bmad-core/web-bundles/agents/bmad-master.txt +0 -9491
  264. package/.bmad-core/web-bundles/agents/bmad-orchestrator.txt +0 -1466
  265. package/.bmad-core/web-bundles/agents/dev.txt +0 -316
  266. package/.bmad-core/web-bundles/agents/qa.txt +0 -129
  267. package/.bmad-core/web-bundles/agents/sm.txt +0 -658
  268. package/.bmad-core/web-bundles/agents/ux-expert.txt +0 -1099
  269. package/.bmad-core/web-bundles/teams/team-all.txt +0 -10757
  270. package/.bmad-core/web-bundles/teams/team-fullstack.txt +0 -10109
  271. package/.bmad-core/web-bundles/teams/team-no-ui.txt +0 -8950
  272. package/.bmad-core/workflows/brownfield-fullstack.yml +0 -116
  273. package/.bmad-core/workflows/brownfield-service.yml +0 -117
  274. package/.bmad-core/workflows/brownfield-ui.yml +0 -127
  275. package/.bmad-core/workflows/greenfield-service.yml +0 -143
  276. package/.bmad-core/workflows/greenfield-ui.yml +0 -172
  277. package/.claude/commands/analyst.md +0 -63
  278. package/.claude/commands/architect.md +0 -70
  279. package/.claude/commands/bmad-master.md +0 -108
  280. package/.claude/commands/bmad-orchestrator.md +0 -85
  281. package/.claude/commands/dev.md +0 -74
  282. package/.claude/commands/pm.md +0 -63
  283. package/.claude/commands/po.md +0 -64
  284. package/.claude/commands/qa.md +0 -56
  285. package/.claude/commands/sm.md +0 -59
  286. package/.claude/commands/ux-expert.md +0 -70
  287. package/.cursor/rules/analyst.mdc +0 -77
  288. package/.cursor/rules/architect.mdc +0 -84
  289. package/.cursor/rules/bmad-master.mdc +0 -122
  290. package/.cursor/rules/bmad-orchestrator.mdc +0 -99
  291. package/.cursor/rules/dev.mdc +0 -88
  292. package/.cursor/rules/pm.mdc +0 -77
  293. package/.cursor/rules/po.mdc +0 -78
  294. package/.cursor/rules/qa.mdc +0 -70
  295. package/.cursor/rules/sm.mdc +0 -73
  296. package/.cursor/rules/ux-expert.mdc +0 -84
  297. package/.github/workflows/release.yml +0 -59
  298. package/.releaserc.json +0 -18
  299. package/.roo/.roomodes +0 -95
  300. package/.roo/README.md +0 -38
  301. package/.vscode/extensions.json +0 -6
  302. package/.windsurf/rules/analyst.md +0 -71
  303. package/.windsurf/rules/architect.md +0 -78
  304. package/.windsurf/rules/bmad-master.md +0 -116
  305. package/.windsurf/rules/bmad-orchestrator.md +0 -93
  306. package/.windsurf/rules/dev.md +0 -82
  307. package/.windsurf/rules/pm.md +0 -71
  308. package/.windsurf/rules/po.md +0 -72
  309. package/.windsurf/rules/qa.md +0 -64
  310. package/.windsurf/rules/sm.md +0 -67
  311. package/.windsurf/rules/ux-expert.md +0 -78
  312. package/docs/bmad-workflow-guide.md +0 -161
  313. package/docs/claude-code-guide.md +0 -119
  314. package/docs/cursor-guide.md +0 -127
  315. package/docs/roo-code-guide.md +0 -140
  316. package/docs/sample-output/simple-fullstack-greenfield/prd.md +0 -42
  317. package/docs/windsurf-guide.md +0 -127
  318. package/expansion-packs/infrastructure-devops/manifest.yml +0 -38
  319. package/expansion-packs/infrastructure-devops/templates/infrastructure-architecture-tmpl.md +0 -415
  320. package/expansion-packs/infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.md +0 -0
  321. package/tools/installer/config/install.config.yml +0 -139
  322. package/tools/installer/package-lock.json +0 -906
  323. package/tools/installer/templates/claude-commands.md +0 -7
  324. package/tools/installer/templates/cursor-rules.md +0 -22
  325. package/tools/installer/templates/windsurf-rules.md +0 -22
  326. package/tools/semantic-release-sync-installer.js +0 -31
  327. /package/{.bmad-core → bmad-core}/data/technical-preferences.md +0 -0
  328. /package/{.bmad-core → bmad-core}/tasks/brownfield-create-epic.md +0 -0
  329. /package/{.bmad-core → bmad-core}/tasks/brownfield-create-story.md +0 -0
@@ -1,20 +1,38 @@
1
- const path = require("path");
2
- const fileManager = require("./file-manager");
3
- const configLoader = require("./config-loader");
1
+ const path = require('node:path');
2
+ const fs = require('fs-extra');
3
+ const yaml = require('js-yaml');
4
+ const chalk = require('chalk');
5
+ const inquirer = require('inquirer');
6
+ const fileManager = require('./file-manager');
7
+ const configLoader = require('./config-loader');
8
+ const { extractYamlFromAgent } = require('../../lib/yaml-utils');
9
+ const BaseIdeSetup = require('./ide-base-setup');
10
+ const resourceLocator = require('./resource-locator');
4
11
 
5
- // Dynamic import for ES module
6
- let chalk;
12
+ class IdeSetup extends BaseIdeSetup {
13
+ constructor() {
14
+ super();
15
+ this.ideAgentConfig = null;
16
+ }
17
+
18
+ async loadIdeAgentConfig() {
19
+ if (this.ideAgentConfig) return this.ideAgentConfig;
7
20
 
8
- // Initialize ES modules
9
- async function initializeModules() {
10
- if (!chalk) {
11
- chalk = (await import("chalk")).default;
21
+ try {
22
+ const configPath = path.join(__dirname, '..', 'config', 'ide-agent-config.yaml');
23
+ const configContent = await fs.readFile(configPath, 'utf8');
24
+ this.ideAgentConfig = yaml.load(configContent);
25
+ return this.ideAgentConfig;
26
+ } catch {
27
+ console.warn('Failed to load IDE agent configuration, using defaults');
28
+ return {
29
+ 'roo-permissions': {},
30
+ 'cline-order': {},
31
+ };
32
+ }
12
33
  }
13
- }
14
34
 
15
- class IdeSetup {
16
- async setup(ide, installDir, selectedAgent = null) {
17
- await initializeModules();
35
+ async setup(ide, installDir, selectedAgent = null, spinner = null, preConfiguredSettings = null) {
18
36
  const ideConfig = await configLoader.getIdeConfiguration(ide);
19
37
 
20
38
  if (!ideConfig) {
@@ -23,108 +41,185 @@ class IdeSetup {
23
41
  }
24
42
 
25
43
  switch (ide) {
26
- case "cursor":
44
+ case 'cursor': {
27
45
  return this.setupCursor(installDir, selectedAgent);
28
- case "claude-code":
46
+ }
47
+ case 'claude-code': {
29
48
  return this.setupClaudeCode(installDir, selectedAgent);
30
- case "windsurf":
49
+ }
50
+ case 'crush': {
51
+ return this.setupCrush(installDir, selectedAgent);
52
+ }
53
+ case 'windsurf': {
31
54
  return this.setupWindsurf(installDir, selectedAgent);
32
- case "roo":
55
+ }
56
+ case 'trae': {
57
+ return this.setupTrae(installDir, selectedAgent);
58
+ }
59
+ case 'roo': {
33
60
  return this.setupRoo(installDir, selectedAgent);
34
- default:
61
+ }
62
+ case 'cline': {
63
+ return this.setupCline(installDir, selectedAgent);
64
+ }
65
+ case 'kilo': {
66
+ return this.setupKilocode(installDir, selectedAgent);
67
+ }
68
+ case 'gemini': {
69
+ return this.setupGeminiCli(installDir, selectedAgent);
70
+ }
71
+ case 'github-copilot': {
72
+ return this.setupGitHubCopilot(installDir, selectedAgent, spinner, preConfiguredSettings);
73
+ }
74
+ case 'qwen-code': {
75
+ return this.setupQwenCode(installDir, selectedAgent);
76
+ }
77
+ default: {
35
78
  console.log(chalk.yellow(`\nIDE ${ide} not yet supported`));
36
79
  return false;
80
+ }
37
81
  }
38
82
  }
39
83
 
40
84
  async setupCursor(installDir, selectedAgent) {
41
- const cursorRulesDir = path.join(installDir, ".cursor", "rules");
42
- const agents = selectedAgent
43
- ? [selectedAgent]
44
- : await this.getAllAgentIds(installDir);
85
+ const cursorRulesDir = path.join(installDir, '.cursor', 'rules', 'bmad');
86
+ const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
45
87
 
46
88
  await fileManager.ensureDirectory(cursorRulesDir);
47
89
 
48
90
  for (const agentId of agents) {
49
- // Check if .bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
50
- let agentPath = path.join(
51
- installDir,
52
- ".bmad-core",
53
- "agents",
54
- `${agentId}.md`
55
- );
56
- if (!(await fileManager.pathExists(agentPath))) {
57
- agentPath = path.join(installDir, "agents", `${agentId}.md`);
58
- }
91
+ const agentPath = await this.findAgentPath(agentId, installDir);
59
92
 
60
- if (await fileManager.pathExists(agentPath)) {
61
- const agentContent = await fileManager.readFile(agentPath);
93
+ if (agentPath) {
94
+ const mdcContent = await this.createAgentRuleContent(agentId, agentPath, installDir, 'mdc');
62
95
  const mdcPath = path.join(cursorRulesDir, `${agentId}.mdc`);
63
-
64
- // Create MDC content with proper format
65
- let mdcContent = "---\n";
66
- mdcContent += "description: \n";
67
- mdcContent += "globs: []\n";
68
- mdcContent += "alwaysApply: false\n";
69
- mdcContent += "---\n\n";
70
- mdcContent += `# ${agentId.toUpperCase()} Agent Rule\n\n`;
71
- mdcContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${this.getAgentTitle(
72
- agentId
73
- )} agent persona.\n\n`;
74
- mdcContent += "## Agent Activation\n\n";
75
- mdcContent +=
76
- "CRITICAL: Read the full YML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n";
77
- mdcContent += "```yml\n";
78
- // Extract just the YAML content from the agent file
79
- const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
80
- if (yamlMatch) {
81
- mdcContent += yamlMatch[1].trim();
82
- } else {
83
- // If no YAML found, include the whole content minus the header
84
- mdcContent += agentContent.replace(/^#.*$/m, "").trim();
85
- }
86
- mdcContent += "\n```\n\n";
87
- mdcContent += "## File Reference\n\n";
88
- mdcContent += `The complete agent definition is available in [.bmad-core/agents/${agentId}.md](mdc:.bmad-core/agents/${agentId}.md).\n\n`;
89
- mdcContent += "## Usage\n\n";
90
- mdcContent += `When the user types \`@${agentId}\`, activate this ${this.getAgentTitle(
91
- agentId
92
- )} persona and follow all instructions defined in the YML configuration above.\n`;
93
-
94
96
  await fileManager.writeFile(mdcPath, mdcContent);
95
97
  console.log(chalk.green(`✓ Created rule: ${agentId}.mdc`));
96
98
  }
97
99
  }
98
100
 
99
101
  console.log(chalk.green(`\n✓ Created Cursor rules in ${cursorRulesDir}`));
102
+ return true;
103
+ }
104
+
105
+ async setupCrush(installDir, selectedAgent) {
106
+ // Setup bmad-core commands
107
+ const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
108
+ const coreAgents = selectedAgent ? [selectedAgent] : await this.getCoreAgentIds(installDir);
109
+ const coreTasks = await this.getCoreTaskIds(installDir);
110
+ await this.setupCrushForPackage(
111
+ installDir,
112
+ 'core',
113
+ coreSlashPrefix,
114
+ coreAgents,
115
+ coreTasks,
116
+ '.bmad-core',
117
+ );
118
+
119
+ // Setup expansion pack commands
120
+ const expansionPacks = await this.getInstalledExpansionPacks(installDir);
121
+ for (const packInfo of expansionPacks) {
122
+ const packSlashPrefix = await this.getExpansionPackSlashPrefix(packInfo.path);
123
+ const packAgents = await this.getExpansionPackAgents(packInfo.path);
124
+ const packTasks = await this.getExpansionPackTasks(packInfo.path);
125
+
126
+ if (packAgents.length > 0 || packTasks.length > 0) {
127
+ // Use the actual directory name where the expansion pack is installed
128
+ const rootPath = path.relative(installDir, packInfo.path);
129
+ await this.setupCrushForPackage(
130
+ installDir,
131
+ packInfo.name,
132
+ packSlashPrefix,
133
+ packAgents,
134
+ packTasks,
135
+ rootPath,
136
+ );
137
+ }
138
+ }
100
139
 
101
140
  return true;
102
141
  }
103
142
 
104
143
  async setupClaudeCode(installDir, selectedAgent) {
105
- const commandsDir = path.join(installDir, ".claude", "commands");
106
- const agents = selectedAgent
107
- ? [selectedAgent]
108
- : await this.getAllAgentIds(installDir);
144
+ // Setup bmad-core commands
145
+ const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
146
+ const coreAgents = selectedAgent ? [selectedAgent] : await this.getCoreAgentIds(installDir);
147
+ const coreTasks = await this.getCoreTaskIds(installDir);
148
+ await this.setupClaudeCodeForPackage(
149
+ installDir,
150
+ 'core',
151
+ coreSlashPrefix,
152
+ coreAgents,
153
+ coreTasks,
154
+ '.bmad-core',
155
+ );
109
156
 
110
- await fileManager.ensureDirectory(commandsDir);
157
+ // Setup expansion pack commands
158
+ const expansionPacks = await this.getInstalledExpansionPacks(installDir);
159
+ for (const packInfo of expansionPacks) {
160
+ const packSlashPrefix = await this.getExpansionPackSlashPrefix(packInfo.path);
161
+ const packAgents = await this.getExpansionPackAgents(packInfo.path);
162
+ const packTasks = await this.getExpansionPackTasks(packInfo.path);
111
163
 
112
- for (const agentId of agents) {
113
- // Check if .bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
114
- let agentPath = path.join(
115
- installDir,
116
- ".bmad-core",
117
- "agents",
118
- `${agentId}.md`
119
- );
120
- if (!(await fileManager.pathExists(agentPath))) {
121
- agentPath = path.join(installDir, "agents", `${agentId}.md`);
164
+ if (packAgents.length > 0 || packTasks.length > 0) {
165
+ // Use the actual directory name where the expansion pack is installed
166
+ const rootPath = path.relative(installDir, packInfo.path);
167
+ await this.setupClaudeCodeForPackage(
168
+ installDir,
169
+ packInfo.name,
170
+ packSlashPrefix,
171
+ packAgents,
172
+ packTasks,
173
+ rootPath,
174
+ );
122
175
  }
123
- const commandPath = path.join(commandsDir, `${agentId}.md`);
176
+ }
124
177
 
125
- if (await fileManager.pathExists(agentPath)) {
178
+ return true;
179
+ }
180
+
181
+ async setupClaudeCodeForPackage(
182
+ installDir,
183
+ packageName,
184
+ slashPrefix,
185
+ agentIds,
186
+ taskIds,
187
+ rootPath,
188
+ ) {
189
+ const commandsBaseDir = path.join(installDir, '.claude', 'commands', slashPrefix);
190
+ const agentsDir = path.join(commandsBaseDir, 'agents');
191
+ const tasksDir = path.join(commandsBaseDir, 'tasks');
192
+
193
+ // Ensure directories exist
194
+ await fileManager.ensureDirectory(agentsDir);
195
+ await fileManager.ensureDirectory(tasksDir);
196
+
197
+ // Setup agents
198
+ for (const agentId of agentIds) {
199
+ // Find the agent file - for expansion packs, prefer the expansion pack version
200
+ let agentPath;
201
+ if (packageName === 'core') {
202
+ // For core, use the normal search
203
+ agentPath = await this.findAgentPath(agentId, installDir);
204
+ } else {
205
+ // For expansion packs, first try to find the agent in the expansion pack directory
206
+ const expansionPackPath = path.join(installDir, rootPath, 'agents', `${agentId}.md`);
207
+ if (await fileManager.pathExists(expansionPackPath)) {
208
+ agentPath = expansionPackPath;
209
+ } else {
210
+ // Fall back to core if not found in expansion pack
211
+ agentPath = await this.findAgentPath(agentId, installDir);
212
+ }
213
+ }
214
+
215
+ const commandPath = path.join(agentsDir, `${agentId}.md`);
216
+
217
+ if (agentPath) {
126
218
  // Create command file with agent content
127
- const agentContent = await fileManager.readFile(agentPath);
219
+ let agentContent = await fileManager.readFile(agentPath);
220
+
221
+ // Replace {root} placeholder with the appropriate root path for this context
222
+ agentContent = agentContent.replaceAll('{root}', rootPath);
128
223
 
129
224
  // Add command header
130
225
  let commandContent = `# /${agentId} Command\n\n`;
@@ -132,119 +227,551 @@ class IdeSetup {
132
227
  commandContent += agentContent;
133
228
 
134
229
  await fileManager.writeFile(commandPath, commandContent);
135
- console.log(chalk.green(`✓ Created command: /${agentId}`));
230
+ console.log(chalk.green(`✓ Created agent command: /${agentId}`));
231
+ }
232
+ }
233
+
234
+ // Setup tasks
235
+ for (const taskId of taskIds) {
236
+ // Find the task file - for expansion packs, prefer the expansion pack version
237
+ let taskPath;
238
+ if (packageName === 'core') {
239
+ // For core, use the normal search
240
+ taskPath = await this.findTaskPath(taskId, installDir);
241
+ } else {
242
+ // For expansion packs, first try to find the task in the expansion pack directory
243
+ const expansionPackPath = path.join(installDir, rootPath, 'tasks', `${taskId}.md`);
244
+ if (await fileManager.pathExists(expansionPackPath)) {
245
+ taskPath = expansionPackPath;
246
+ } else {
247
+ // Fall back to core if not found in expansion pack
248
+ taskPath = await this.findTaskPath(taskId, installDir);
249
+ }
250
+ }
251
+
252
+ const commandPath = path.join(tasksDir, `${taskId}.md`);
253
+
254
+ if (taskPath) {
255
+ // Create command file with task content
256
+ let taskContent = await fileManager.readFile(taskPath);
257
+
258
+ // Replace {root} placeholder with the appropriate root path for this context
259
+ taskContent = taskContent.replaceAll('{root}', rootPath);
260
+
261
+ // Add command header
262
+ let commandContent = `# /${taskId} Task\n\n`;
263
+ commandContent += `When this command is used, execute the following task:\n\n`;
264
+ commandContent += taskContent;
265
+
266
+ await fileManager.writeFile(commandPath, commandContent);
267
+ console.log(chalk.green(`✓ Created task command: /${taskId}`));
136
268
  }
137
269
  }
138
270
 
139
271
  console.log(
140
- chalk.green(`\n✓ Created Claude Code commands in ${commandsDir}`)
272
+ chalk.green(`\n✓ Created Claude Code commands for ${packageName} in ${commandsBaseDir}`),
141
273
  );
274
+ console.log(chalk.dim(` - Agents in: ${agentsDir}`));
275
+ console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
276
+ }
142
277
 
143
- return true;
278
+ async setupCrushForPackage(installDir, packageName, slashPrefix, agentIds, taskIds, rootPath) {
279
+ const commandsBaseDir = path.join(installDir, '.crush', 'commands', slashPrefix);
280
+ const agentsDir = path.join(commandsBaseDir, 'agents');
281
+ const tasksDir = path.join(commandsBaseDir, 'tasks');
282
+
283
+ // Ensure directories exist
284
+ await fileManager.ensureDirectory(agentsDir);
285
+ await fileManager.ensureDirectory(tasksDir);
286
+
287
+ // Setup agents
288
+ for (const agentId of agentIds) {
289
+ // Find the agent file - for expansion packs, prefer the expansion pack version
290
+ let agentPath;
291
+ if (packageName === 'core') {
292
+ // For core, use the normal search
293
+ agentPath = await this.findAgentPath(agentId, installDir);
294
+ } else {
295
+ // For expansion packs, first try to find the agent in the expansion pack directory
296
+ const expansionPackPath = path.join(installDir, rootPath, 'agents', `${agentId}.md`);
297
+ if (await fileManager.pathExists(expansionPackPath)) {
298
+ agentPath = expansionPackPath;
299
+ } else {
300
+ // Fall back to core if not found in expansion pack
301
+ agentPath = await this.findAgentPath(agentId, installDir);
302
+ }
303
+ }
304
+
305
+ const commandPath = path.join(agentsDir, `${agentId}.md`);
306
+
307
+ if (agentPath) {
308
+ // Create command file with agent content
309
+ let agentContent = await fileManager.readFile(agentPath);
310
+
311
+ // Replace {root} placeholder with the appropriate root path for this context
312
+ agentContent = agentContent.replaceAll('{root}', rootPath);
313
+
314
+ // Add command header
315
+ let commandContent = `# /${agentId} Command\n\n`;
316
+ commandContent += `When this command is used, adopt the following agent persona:\n\n`;
317
+ commandContent += agentContent;
318
+
319
+ await fileManager.writeFile(commandPath, commandContent);
320
+ console.log(chalk.green(`✓ Created agent command: /${agentId}`));
321
+ }
322
+ }
323
+
324
+ // Setup tasks
325
+ for (const taskId of taskIds) {
326
+ // Find the task file - for expansion packs, prefer the expansion pack version
327
+ let taskPath;
328
+ if (packageName === 'core') {
329
+ // For core, use the normal search
330
+ taskPath = await this.findTaskPath(taskId, installDir);
331
+ } else {
332
+ // For expansion packs, first try to find the task in the expansion pack directory
333
+ const expansionPackPath = path.join(installDir, rootPath, 'tasks', `${taskId}.md`);
334
+ if (await fileManager.pathExists(expansionPackPath)) {
335
+ taskPath = expansionPackPath;
336
+ } else {
337
+ // Fall back to core if not found in expansion pack
338
+ taskPath = await this.findTaskPath(taskId, installDir);
339
+ }
340
+ }
341
+
342
+ const commandPath = path.join(tasksDir, `${taskId}.md`);
343
+
344
+ if (taskPath) {
345
+ // Create command file with task content
346
+ let taskContent = await fileManager.readFile(taskPath);
347
+
348
+ // Replace {root} placeholder with the appropriate root path for this context
349
+ taskContent = taskContent.replaceAll('{root}', rootPath);
350
+
351
+ // Add command header
352
+ let commandContent = `# /${taskId} Task\n\n`;
353
+ commandContent += `When this command is used, execute the following task:\n\n`;
354
+ commandContent += taskContent;
355
+
356
+ await fileManager.writeFile(commandPath, commandContent);
357
+ console.log(chalk.green(`✓ Created task command: /${taskId}`));
358
+ }
359
+ }
360
+
361
+ console.log(chalk.green(`\n✓ Created Crush commands for ${packageName} in ${commandsBaseDir}`));
362
+ console.log(chalk.dim(` - Agents in: ${agentsDir}`));
363
+ console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
144
364
  }
145
365
 
146
366
  async setupWindsurf(installDir, selectedAgent) {
147
- const windsurfRulesDir = path.join(installDir, ".windsurf", "rules");
148
- const agents = selectedAgent
149
- ? [selectedAgent]
150
- : await this.getAllAgentIds(installDir);
367
+ const windsurfWorkflowDir = path.join(installDir, '.windsurf', 'workflows');
368
+ const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
151
369
 
152
- await fileManager.ensureDirectory(windsurfRulesDir);
370
+ await fileManager.ensureDirectory(windsurfWorkflowDir);
153
371
 
154
372
  for (const agentId of agents) {
155
- // Check if .bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
156
- let agentPath = path.join(
157
- installDir,
158
- ".bmad-core",
159
- "agents",
160
- `${agentId}.md`
161
- );
162
- if (!(await fileManager.pathExists(agentPath))) {
163
- agentPath = path.join(installDir, "agents", `${agentId}.md`);
373
+ // Find the agent file
374
+ const agentPath = await this.findAgentPath(agentId, installDir);
375
+
376
+ if (agentPath) {
377
+ const agentContent = await fileManager.readFile(agentPath);
378
+ const mdPath = path.join(windsurfWorkflowDir, `${agentId}.md`);
379
+
380
+ // Write the agent file contents prefixed with Windsurf frontmatter
381
+ let mdContent = `---\n`;
382
+ mdContent += `description: ${agentId}\n`;
383
+ mdContent += `auto_execution_mode: 3\n`;
384
+ mdContent += `---\n\n`;
385
+ mdContent += agentContent;
386
+
387
+ await fileManager.writeFile(mdPath, mdContent);
388
+ console.log(chalk.green(`✓ Created workflow: ${agentId}.md`));
164
389
  }
390
+ }
165
391
 
166
- if (await fileManager.pathExists(agentPath)) {
392
+ console.log(chalk.green(`\n✓ Created Windsurf workflows in ${windsurfWorkflowDir}`));
393
+
394
+ return true;
395
+ }
396
+
397
+ async setupTrae(installDir, selectedAgent) {
398
+ const traeRulesDir = path.join(installDir, '.trae', 'rules');
399
+ const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
400
+
401
+ await fileManager.ensureDirectory(traeRulesDir);
402
+
403
+ for (const agentId of agents) {
404
+ // Find the agent file
405
+ const agentPath = await this.findAgentPath(agentId, installDir);
406
+
407
+ if (agentPath) {
167
408
  const agentContent = await fileManager.readFile(agentPath);
168
- const mdPath = path.join(windsurfRulesDir, `${agentId}.md`);
409
+ const mdPath = path.join(traeRulesDir, `${agentId}.md`);
169
410
 
170
411
  // Create MD content (similar to Cursor but without frontmatter)
171
412
  let mdContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
172
- mdContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${this.getAgentTitle(
173
- agentId
413
+ mdContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${await this.getAgentTitle(
414
+ agentId,
415
+ installDir,
174
416
  )} agent persona.\n\n`;
175
- mdContent += "## Agent Activation\n\n";
417
+ mdContent += '## Agent Activation\n\n';
176
418
  mdContent +=
177
- "CRITICAL: Read the full YML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n";
178
- mdContent += "```yml\n";
419
+ 'CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n';
420
+ mdContent += '```yaml\n';
179
421
  // Extract just the YAML content from the agent file
180
- const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
181
- if (yamlMatch) {
182
- mdContent += yamlMatch[1].trim();
422
+ const yamlContent = extractYamlFromAgent(agentContent);
423
+ if (yamlContent) {
424
+ mdContent += yamlContent;
183
425
  } else {
184
426
  // If no YAML found, include the whole content minus the header
185
- mdContent += agentContent.replace(/^#.*$/m, "").trim();
427
+ mdContent += agentContent.replace(/^#.*$/m, '').trim();
186
428
  }
187
- mdContent += "\n```\n\n";
188
- mdContent += "## File Reference\n\n";
189
- mdContent += `The complete agent definition is available in [.bmad-core/agents/${agentId}.md](.bmad-core/agents/${agentId}.md).\n\n`;
190
- mdContent += "## Usage\n\n";
191
- mdContent += `When the user types \`@${agentId}\`, activate this ${this.getAgentTitle(
192
- agentId
193
- )} persona and follow all instructions defined in the YML configuration above.\n`;
429
+ mdContent += '\n```\n\n';
430
+ mdContent += '## File Reference\n\n';
431
+ const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
432
+ mdContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
433
+ mdContent += '## Usage\n\n';
434
+ mdContent += `When the user types \`@${agentId}\`, activate this ${await this.getAgentTitle(
435
+ agentId,
436
+ installDir,
437
+ )} persona and follow all instructions defined in the YAML configuration above.\n`;
194
438
 
195
439
  await fileManager.writeFile(mdPath, mdContent);
196
440
  console.log(chalk.green(`✓ Created rule: ${agentId}.md`));
197
441
  }
198
442
  }
443
+ }
199
444
 
200
- console.log(
201
- chalk.green(`\n✓ Created Windsurf rules in ${windsurfRulesDir}`)
202
- );
445
+ async findAgentPath(agentId, installDir) {
446
+ // Try to find the agent file in various locations
447
+ const possiblePaths = [
448
+ path.join(installDir, '.bmad-core', 'agents', `${agentId}.md`),
449
+ path.join(installDir, 'agents', `${agentId}.md`),
450
+ ];
203
451
 
204
- return true;
452
+ // Also check expansion pack directories
453
+ const glob = require('glob');
454
+ const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
455
+ for (const expDir of expansionDirectories) {
456
+ possiblePaths.push(path.join(installDir, expDir, `${agentId}.md`));
457
+ }
458
+
459
+ for (const agentPath of possiblePaths) {
460
+ if (await fileManager.pathExists(agentPath)) {
461
+ return agentPath;
462
+ }
463
+ }
464
+
465
+ return null;
205
466
  }
206
467
 
207
468
  async getAllAgentIds(installDir) {
208
- // Check if .bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
209
- let agentsDir = path.join(installDir, ".bmad-core", "agents");
469
+ const glob = require('glob');
470
+ const allAgentIds = [];
471
+
472
+ // Check core agents in .bmad-core or root
473
+ let agentsDir = path.join(installDir, '.bmad-core', 'agents');
210
474
  if (!(await fileManager.pathExists(agentsDir))) {
211
- agentsDir = path.join(installDir, "agents");
475
+ agentsDir = path.join(installDir, 'agents');
476
+ }
477
+
478
+ if (await fileManager.pathExists(agentsDir)) {
479
+ const agentFiles = glob.sync('*.md', { cwd: agentsDir });
480
+ allAgentIds.push(...agentFiles.map((file) => path.basename(file, '.md')));
212
481
  }
213
482
 
214
- const glob = require("glob");
215
- const agentFiles = glob.sync("*.md", { cwd: agentsDir });
216
- return agentFiles.map((file) => path.basename(file, ".md"));
483
+ // Also check for expansion pack agents in dot folders
484
+ const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
485
+ for (const expDir of expansionDirectories) {
486
+ const fullExpDir = path.join(installDir, expDir);
487
+ const expAgentFiles = glob.sync('*.md', { cwd: fullExpDir });
488
+ allAgentIds.push(...expAgentFiles.map((file) => path.basename(file, '.md')));
489
+ }
490
+
491
+ // Remove duplicates
492
+ return [...new Set(allAgentIds)];
217
493
  }
218
494
 
219
- getAgentTitle(agentId) {
220
- const agentTitles = {
221
- analyst: "Business Analyst",
222
- architect: "Solution Architect",
223
- "bmad-master": "BMAD Master",
224
- "bmad-orchestrator": "BMAD Orchestrator",
225
- dev: "Developer",
226
- pm: "Product Manager",
227
- po: "Product Owner",
228
- qa: "QA Specialist",
229
- sm: "Scrum Master",
230
- "ux-expert": "UX Expert",
231
- };
232
- return agentTitles[agentId] || agentId;
495
+ async getCoreAgentIds(installDir) {
496
+ const allAgentIds = [];
497
+
498
+ // Check core agents in .bmad-core or root only
499
+ let agentsDir = path.join(installDir, '.bmad-core', 'agents');
500
+ if (!(await fileManager.pathExists(agentsDir))) {
501
+ agentsDir = path.join(installDir, 'bmad-core', 'agents');
502
+ }
503
+
504
+ if (await fileManager.pathExists(agentsDir)) {
505
+ const glob = require('glob');
506
+ const agentFiles = glob.sync('*.md', { cwd: agentsDir });
507
+ allAgentIds.push(...agentFiles.map((file) => path.basename(file, '.md')));
508
+ }
509
+
510
+ return [...new Set(allAgentIds)];
233
511
  }
234
512
 
235
- async setupRoo(installDir, selectedAgent) {
236
- const agents = selectedAgent
237
- ? [selectedAgent]
238
- : await this.getAllAgentIds(installDir);
513
+ async getCoreTaskIds(installDir) {
514
+ const allTaskIds = [];
515
+
516
+ // Check core tasks in .bmad-core or root only
517
+ let tasksDir = path.join(installDir, '.bmad-core', 'tasks');
518
+ if (!(await fileManager.pathExists(tasksDir))) {
519
+ tasksDir = path.join(installDir, 'bmad-core', 'tasks');
520
+ }
521
+
522
+ if (await fileManager.pathExists(tasksDir)) {
523
+ const glob = require('glob');
524
+ const taskFiles = glob.sync('*.md', { cwd: tasksDir });
525
+ allTaskIds.push(...taskFiles.map((file) => path.basename(file, '.md')));
526
+ }
527
+
528
+ // Check common tasks
529
+ const commonTasksDir = path.join(installDir, 'common', 'tasks');
530
+ if (await fileManager.pathExists(commonTasksDir)) {
531
+ const commonTaskFiles = glob.sync('*.md', { cwd: commonTasksDir });
532
+ allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, '.md')));
533
+ }
534
+
535
+ return [...new Set(allTaskIds)];
536
+ }
537
+
538
+ async getAgentTitle(agentId, installDir) {
539
+ // Try to find the agent file in various locations
540
+ const possiblePaths = [
541
+ path.join(installDir, '.bmad-core', 'agents', `${agentId}.md`),
542
+ path.join(installDir, 'agents', `${agentId}.md`),
543
+ ];
239
544
 
240
- // Create .roo directory first
241
- const rooDir = path.join(installDir, ".roo");
242
- await fileManager.ensureDirectory(rooDir);
545
+ // Also check expansion pack directories
546
+ const glob = require('glob');
547
+ const expansionDirectories = glob.sync('.*/agents', { cwd: installDir });
548
+ for (const expDir of expansionDirectories) {
549
+ possiblePaths.push(path.join(installDir, expDir, `${agentId}.md`));
550
+ }
551
+
552
+ for (const agentPath of possiblePaths) {
553
+ if (await fileManager.pathExists(agentPath)) {
554
+ try {
555
+ const agentContent = await fileManager.readFile(agentPath);
556
+ const yamlMatch = agentContent.match(/```ya?ml\r?\n([\s\S]*?)```/);
557
+
558
+ if (yamlMatch) {
559
+ const yaml = yamlMatch[1];
560
+ const titleMatch = yaml.match(/title:\s*(.+)/);
561
+ if (titleMatch) {
562
+ return titleMatch[1].trim();
563
+ }
564
+ }
565
+ } catch (error) {
566
+ console.warn(`Failed to read agent title for ${agentId}: ${error.message}`);
567
+ }
568
+ }
569
+ }
570
+
571
+ // Fallback to formatted agent ID
572
+ return agentId
573
+ .split('-')
574
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
575
+ .join(' ');
576
+ }
577
+
578
+ async getAllTaskIds(installDir) {
579
+ const glob = require('glob');
580
+ const allTaskIds = [];
581
+
582
+ // Check core tasks in .bmad-core or root
583
+ let tasksDir = path.join(installDir, '.bmad-core', 'tasks');
584
+ if (!(await fileManager.pathExists(tasksDir))) {
585
+ tasksDir = path.join(installDir, 'bmad-core', 'tasks');
586
+ }
587
+
588
+ if (await fileManager.pathExists(tasksDir)) {
589
+ const taskFiles = glob.sync('*.md', { cwd: tasksDir });
590
+ allTaskIds.push(...taskFiles.map((file) => path.basename(file, '.md')));
591
+ }
592
+
593
+ // Check common tasks
594
+ const commonTasksDir = path.join(installDir, 'common', 'tasks');
595
+ if (await fileManager.pathExists(commonTasksDir)) {
596
+ const commonTaskFiles = glob.sync('*.md', { cwd: commonTasksDir });
597
+ allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, '.md')));
598
+ }
599
+
600
+ // Also check for expansion pack tasks in dot folders
601
+ const expansionDirectories = glob.sync('.*/tasks', { cwd: installDir });
602
+ for (const expDir of expansionDirectories) {
603
+ const fullExpDir = path.join(installDir, expDir);
604
+ const expTaskFiles = glob.sync('*.md', { cwd: fullExpDir });
605
+ allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, '.md')));
606
+ }
607
+
608
+ // Check expansion-packs folder tasks
609
+ const expansionPacksDir = path.join(installDir, 'expansion-packs');
610
+ if (await fileManager.pathExists(expansionPacksDir)) {
611
+ const expPackDirectories = glob.sync('*/tasks', { cwd: expansionPacksDir });
612
+ for (const expDir of expPackDirectories) {
613
+ const fullExpDir = path.join(expansionPacksDir, expDir);
614
+ const expTaskFiles = glob.sync('*.md', { cwd: fullExpDir });
615
+ allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, '.md')));
616
+ }
617
+ }
618
+
619
+ // Remove duplicates
620
+ return [...new Set(allTaskIds)];
621
+ }
622
+
623
+ async findTaskPath(taskId, installDir) {
624
+ // Try to find the task file in various locations
625
+ const possiblePaths = [
626
+ path.join(installDir, '.bmad-core', 'tasks', `${taskId}.md`),
627
+ path.join(installDir, 'bmad-core', 'tasks', `${taskId}.md`),
628
+ path.join(installDir, 'common', 'tasks', `${taskId}.md`),
629
+ ];
243
630
 
244
- // Check for existing .roomodes file inside .roo directory
245
- const roomodesPath = path.join(rooDir, ".roomodes");
631
+ // Also check expansion pack directories
632
+ const glob = require('glob');
633
+
634
+ // Check dot folder expansion packs
635
+ const expansionDirectories = glob.sync('.*/tasks', { cwd: installDir });
636
+ for (const expDir of expansionDirectories) {
637
+ possiblePaths.push(path.join(installDir, expDir, `${taskId}.md`));
638
+ }
639
+
640
+ // Check expansion-packs folder
641
+ const expansionPacksDir = path.join(installDir, 'expansion-packs');
642
+ if (await fileManager.pathExists(expansionPacksDir)) {
643
+ const expPackDirectories = glob.sync('*/tasks', { cwd: expansionPacksDir });
644
+ for (const expDir of expPackDirectories) {
645
+ possiblePaths.push(path.join(expansionPacksDir, expDir, `${taskId}.md`));
646
+ }
647
+ }
648
+
649
+ for (const taskPath of possiblePaths) {
650
+ if (await fileManager.pathExists(taskPath)) {
651
+ return taskPath;
652
+ }
653
+ }
654
+
655
+ return null;
656
+ }
657
+
658
+ async getCoreSlashPrefix(installDir) {
659
+ try {
660
+ const coreConfigPath = path.join(installDir, '.bmad-core', 'core-config.yaml');
661
+ if (!(await fileManager.pathExists(coreConfigPath))) {
662
+ // Try bmad-core directory
663
+ const altConfigPath = path.join(installDir, 'bmad-core', 'core-config.yaml');
664
+ if (await fileManager.pathExists(altConfigPath)) {
665
+ const configContent = await fileManager.readFile(altConfigPath);
666
+ const config = yaml.load(configContent);
667
+ return config.slashPrefix || 'BMad';
668
+ }
669
+ return 'BMad'; // fallback
670
+ }
671
+
672
+ const configContent = await fileManager.readFile(coreConfigPath);
673
+ const config = yaml.load(configContent);
674
+ return config.slashPrefix || 'BMad';
675
+ } catch (error) {
676
+ console.warn(`Failed to read core slashPrefix, using default 'BMad': ${error.message}`);
677
+ return 'BMad';
678
+ }
679
+ }
680
+
681
+ async getInstalledExpansionPacks(installDir) {
682
+ const expansionPacks = [];
683
+
684
+ // Check for dot-prefixed expansion packs in install directory
685
+ const glob = require('glob');
686
+ const dotExpansions = glob.sync('.bmad-*', { cwd: installDir });
687
+
688
+ for (const dotExpansion of dotExpansions) {
689
+ if (dotExpansion !== '.bmad-core') {
690
+ const packPath = path.join(installDir, dotExpansion);
691
+ const packName = dotExpansion.slice(1); // remove the dot
692
+ expansionPacks.push({
693
+ name: packName,
694
+ path: packPath,
695
+ });
696
+ }
697
+ }
698
+
699
+ // Check for expansion-packs directory style
700
+ const expansionPacksDir = path.join(installDir, 'expansion-packs');
701
+ if (await fileManager.pathExists(expansionPacksDir)) {
702
+ const packDirectories = glob.sync('*', { cwd: expansionPacksDir });
703
+
704
+ for (const packDir of packDirectories) {
705
+ const packPath = path.join(expansionPacksDir, packDir);
706
+ if (
707
+ (await fileManager.pathExists(packPath)) &&
708
+ (await fileManager.pathExists(path.join(packPath, 'config.yaml')))
709
+ ) {
710
+ expansionPacks.push({
711
+ name: packDir,
712
+ path: packPath,
713
+ });
714
+ }
715
+ }
716
+ }
717
+
718
+ return expansionPacks;
719
+ }
720
+
721
+ async getExpansionPackSlashPrefix(packPath) {
722
+ try {
723
+ const configPath = path.join(packPath, 'config.yaml');
724
+ if (await fileManager.pathExists(configPath)) {
725
+ const configContent = await fileManager.readFile(configPath);
726
+ const config = yaml.load(configContent);
727
+ return config.slashPrefix || path.basename(packPath);
728
+ }
729
+ } catch (error) {
730
+ console.warn(`Failed to read expansion pack slashPrefix from ${packPath}: ${error.message}`);
731
+ }
732
+
733
+ return path.basename(packPath); // fallback to directory name
734
+ }
735
+
736
+ async getExpansionPackAgents(packPath) {
737
+ const agentsDir = path.join(packPath, 'agents');
738
+ if (!(await fileManager.pathExists(agentsDir))) {
739
+ return [];
740
+ }
741
+
742
+ try {
743
+ const glob = require('glob');
744
+ const agentFiles = glob.sync('*.md', { cwd: agentsDir });
745
+ return agentFiles.map((file) => path.basename(file, '.md'));
746
+ } catch (error) {
747
+ console.warn(`Failed to read expansion pack agents from ${packPath}: ${error.message}`);
748
+ return [];
749
+ }
750
+ }
751
+
752
+ async getExpansionPackTasks(packPath) {
753
+ const tasksDir = path.join(packPath, 'tasks');
754
+ if (!(await fileManager.pathExists(tasksDir))) {
755
+ return [];
756
+ }
757
+
758
+ try {
759
+ const glob = require('glob');
760
+ const taskFiles = glob.sync('*.md', { cwd: tasksDir });
761
+ return taskFiles.map((file) => path.basename(file, '.md'));
762
+ } catch (error) {
763
+ console.warn(`Failed to read expansion pack tasks from ${packPath}: ${error.message}`);
764
+ return [];
765
+ }
766
+ }
767
+
768
+ async setupRoo(installDir, selectedAgent) {
769
+ const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
770
+
771
+ // Check for existing .roomodes file in project root
772
+ const roomodesPath = path.join(installDir, '.roomodes');
246
773
  let existingModes = [];
247
- let existingContent = "";
774
+ let existingContent = '';
248
775
 
249
776
  if (await fileManager.pathExists(roomodesPath)) {
250
777
  existingContent = await fileManager.readFile(roomodesPath);
@@ -253,76 +780,33 @@ class IdeSetup {
253
780
  for (const match of modeMatches) {
254
781
  existingModes.push(match[1]);
255
782
  }
256
- console.log(
257
- chalk.yellow(
258
- `Found existing .roomodes file with ${existingModes.length} modes`
259
- )
260
- );
783
+ console.log(chalk.yellow(`Found existing .roomodes file with ${existingModes.length} modes`));
261
784
  }
262
785
 
263
786
  // Create new modes content
264
- let newModesContent = "";
265
-
266
- // Define file permissions for each agent type
267
- const agentPermissions = {
268
- 'analyst': {
269
- fileRegex: '\\.(md|txt)$',
270
- description: 'Documentation and text files'
271
- },
272
- 'pm': {
273
- fileRegex: '\\.(md|txt)$',
274
- description: 'Product documentation'
275
- },
276
- 'architect': {
277
- fileRegex: '\\.(md|txt|yml|yaml|json)$',
278
- description: 'Architecture docs and configs'
279
- },
280
- 'dev': null, // Full edit access
281
- 'qa': {
282
- fileRegex: '\\.(test|spec)\\.(js|ts|jsx|tsx)$|\\.md$',
283
- description: 'Test files and documentation'
284
- },
285
- 'ux-expert': {
286
- fileRegex: '\\.(md|css|scss|html|jsx|tsx)$',
287
- description: 'Design-related files'
288
- },
289
- 'po': {
290
- fileRegex: '\\.(md|txt)$',
291
- description: 'Story and requirement docs'
292
- },
293
- 'sm': {
294
- fileRegex: '\\.(md|txt)$',
295
- description: 'Process and planning docs'
296
- },
297
- 'bmad-orchestrator': null, // Full edit access
298
- 'bmad-master': null // Full edit access
299
- };
787
+ let newModesContent = '';
788
+
789
+ // Load dynamic agent permissions from configuration
790
+ const config = await this.loadIdeAgentConfig();
791
+ const agentPermissions = config['roo-permissions'] || {};
300
792
 
301
793
  for (const agentId of agents) {
302
794
  // Skip if already exists
303
- if (existingModes.includes(`bmad-${agentId}`)) {
304
- console.log(
305
- chalk.dim(`Skipping ${agentId} - already exists in .roomodes`)
306
- );
795
+ // Check both with and without bmad- prefix to handle both cases
796
+ const checkSlug = agentId.startsWith('bmad-') ? agentId : `bmad-${agentId}`;
797
+ if (existingModes.includes(checkSlug)) {
798
+ console.log(chalk.dim(`Skipping ${agentId} - already exists in .roomodes`));
307
799
  continue;
308
800
  }
309
801
 
310
802
  // Read agent file to extract all information
311
- let agentPath = path.join(
312
- installDir,
313
- ".bmad-core",
314
- "agents",
315
- `${agentId}.md`
316
- );
317
- if (!(await fileManager.pathExists(agentPath))) {
318
- agentPath = path.join(installDir, "agents", `${agentId}.md`);
319
- }
803
+ const agentPath = await this.findAgentPath(agentId, installDir);
320
804
 
321
- if (await fileManager.pathExists(agentPath)) {
805
+ if (agentPath) {
322
806
  const agentContent = await fileManager.readFile(agentPath);
323
807
 
324
808
  // Extract YAML content
325
- const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
809
+ const yamlMatch = agentContent.match(/```ya?ml\r?\n([\s\S]*?)```/);
326
810
  if (yamlMatch) {
327
811
  const yaml = yamlMatch[1];
328
812
 
@@ -332,26 +816,33 @@ class IdeSetup {
332
816
  const whenToUseMatch = yaml.match(/whenToUse:\s*"(.+)"/);
333
817
  const roleDefinitionMatch = yaml.match(/roleDefinition:\s*"(.+)"/);
334
818
 
335
- const title = titleMatch ? titleMatch[1].trim() : this.getAgentTitle(agentId);
336
- const icon = iconMatch ? iconMatch[1].trim() : "🤖";
337
- const whenToUse = whenToUseMatch
338
- ? whenToUseMatch[1].trim()
339
- : `Use for ${title} tasks`;
819
+ const title = titleMatch
820
+ ? titleMatch[1].trim()
821
+ : await this.getAgentTitle(agentId, installDir);
822
+ const icon = iconMatch ? iconMatch[1].trim() : '🤖';
823
+ const whenToUse = whenToUseMatch ? whenToUseMatch[1].trim() : `Use for ${title} tasks`;
340
824
  const roleDefinition = roleDefinitionMatch
341
825
  ? roleDefinitionMatch[1].trim()
342
826
  : `You are a ${title} specializing in ${title.toLowerCase()} tasks and responsibilities.`;
343
827
 
828
+ // Add permissions based on agent type
829
+ const permissions = agentPermissions[agentId];
344
830
  // Build mode entry with proper formatting (matching exact indentation)
345
- newModesContent += ` - slug: bmad-${agentId}\n`;
831
+ // Avoid double "bmad-" prefix for agents that already have it
832
+ const slug = agentId.startsWith('bmad-') ? agentId : `bmad-${agentId}`;
833
+ newModesContent += ` - slug: ${slug}\n`;
346
834
  newModesContent += ` name: '${icon} ${title}'\n`;
835
+ if (permissions) {
836
+ newModesContent += ` description: '${permissions.description}'\n`;
837
+ }
347
838
  newModesContent += ` roleDefinition: ${roleDefinition}\n`;
348
839
  newModesContent += ` whenToUse: ${whenToUse}\n`;
349
- newModesContent += ` customInstructions: CRITICAL Read the full YML from .bmad-core/agents/${agentId}.md start activation to alter your state of being follow startup section instructions stay in this being until told to exit this mode\n`;
840
+ // Get relative path from installDir to agent file
841
+ const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
842
+ newModesContent += ` customInstructions: CRITICAL Read the full YAML from ${relativePath} start activation to alter your state of being follow startup section instructions stay in this being until told to exit this mode\n`;
350
843
  newModesContent += ` groups:\n`;
351
844
  newModesContent += ` - read\n`;
352
-
353
- // Add permissions based on agent type
354
- const permissions = agentPermissions[agentId];
845
+
355
846
  if (permissions) {
356
847
  newModesContent += ` - - edit\n`;
357
848
  newModesContent += ` - fileRegex: ${permissions.fileRegex}\n`;
@@ -360,70 +851,591 @@ class IdeSetup {
360
851
  newModesContent += ` - edit\n`;
361
852
  }
362
853
 
363
- console.log(
364
- chalk.green(`✓ Added mode: bmad-${agentId} (${icon} ${title})`)
365
- );
854
+ console.log(chalk.green(`✓ Added mode: bmad-${agentId} (${icon} ${title})`));
366
855
  }
367
856
  }
368
857
  }
369
858
 
370
859
  // Build final roomodes content
371
- let roomodesContent = "";
860
+ let roomodesContent = '';
372
861
  if (existingContent) {
373
862
  // If there's existing content, append new modes to it
374
- roomodesContent = existingContent.trim() + "\n" + newModesContent;
863
+ roomodesContent = existingContent.trim() + '\n' + newModesContent;
375
864
  } else {
376
865
  // Create new .roomodes file with proper YAML structure
377
- roomodesContent = "customModes:\n" + newModesContent;
866
+ roomodesContent = 'customModes:\n' + newModesContent;
378
867
  }
379
868
 
380
869
  // Write .roomodes file
381
870
  await fileManager.writeFile(roomodesPath, roomodesContent);
382
- console.log(chalk.green("✓ Created .roo/.roomodes file"));
871
+ console.log(chalk.green('✓ Created .roomodes file in project root'));
872
+
873
+ console.log(chalk.green(`\n✓ Roo Code setup complete!`));
874
+ console.log(chalk.dim('Custom modes will be available when you open this project in Roo Code'));
875
+
876
+ return true;
877
+ }
878
+
879
+ async setupKilocode(installDir, selectedAgent) {
880
+ const filePath = path.join(installDir, '.kilocodemodes');
881
+ const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
882
+
883
+ let existingModes = [],
884
+ existingContent = '';
885
+ if (await fileManager.pathExists(filePath)) {
886
+ existingContent = await fileManager.readFile(filePath);
887
+ for (const match of existingContent.matchAll(/- slug: ([\w-]+)/g)) {
888
+ existingModes.push(match[1]);
889
+ }
890
+ console.log(
891
+ chalk.yellow(`Found existing .kilocodemodes file with ${existingModes.length} modes`),
892
+ );
893
+ }
383
894
 
384
- // Create README in .roo directory
385
- const rooReadme = `# Roo Code Custom Modes for BMAD-METHOD
895
+ const config = await this.loadIdeAgentConfig();
896
+ const permissions = config['roo-permissions'] || {}; // reuse same roo permissions block (Kilo Code understands same mode schema)
386
897
 
387
- This directory contains custom mode configurations for Roo Code to enable BMAD agent personalities.
898
+ let newContent = '';
388
899
 
389
- ## Setup
900
+ for (const agentId of agents) {
901
+ const slug = agentId.startsWith('bmad-') ? agentId : `bmad-${agentId}`;
902
+ if (existingModes.includes(slug)) {
903
+ console.log(chalk.dim(`Skipping ${agentId} - already exists in .kilocodemodes`));
904
+ continue;
905
+ }
906
+
907
+ const agentPath = await this.findAgentPath(agentId, installDir);
908
+ if (!agentPath) {
909
+ console.log(chalk.red(`✗ Could not find agent file for ${agentId}`));
910
+ continue;
911
+ }
912
+
913
+ const agentContent = await fileManager.readFile(agentPath);
914
+ const yamlMatch = agentContent.match(/```ya?ml\r?\n([\s\S]*?)```/);
915
+ if (!yamlMatch) {
916
+ console.log(chalk.red(`✗ Could not extract YAML block for ${agentId}`));
917
+ continue;
918
+ }
919
+
920
+ const yaml = yamlMatch[1];
921
+
922
+ // Robust fallback for title and icon
923
+ const title =
924
+ yaml.match(/title:\s*(.+)/)?.[1]?.trim() || (await this.getAgentTitle(agentId, installDir));
925
+ const icon = yaml.match(/icon:\s*(.+)/)?.[1]?.trim() || '🤖';
926
+ const whenToUse = yaml.match(/whenToUse:\s*"(.+)"/)?.[1]?.trim() || `Use for ${title} tasks`;
927
+ const roleDefinition =
928
+ yaml.match(/roleDefinition:\s*"(.+)"/)?.[1]?.trim() ||
929
+ `You are a ${title} specializing in ${title.toLowerCase()} tasks and responsibilities.`;
930
+
931
+ const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
932
+ const customInstructions = `CRITICAL Read the full YAML from ${relativePath} start activation to alter your state of being follow startup section instructions stay in this being until told to exit this mode`;
933
+
934
+ // Add permissions from config if they exist
935
+ const agentPermission = permissions[agentId];
936
+
937
+ // Begin .kilocodemodes block
938
+ newContent += ` - slug: ${slug}\n`;
939
+ newContent += ` name: '${icon} ${title}'\n`;
940
+ if (agentPermission) {
941
+ newContent += ` description: '${agentPermission.description}'\n`;
942
+ }
943
+
944
+ newContent += ` roleDefinition: ${roleDefinition}\n`;
945
+ newContent += ` whenToUse: ${whenToUse}\n`;
946
+ newContent += ` customInstructions: ${customInstructions}\n`;
947
+ newContent += ` groups:\n`;
948
+ newContent += ` - read\n`;
949
+
950
+ if (agentPermission) {
951
+ newContent += ` - - edit\n`;
952
+ newContent += ` - fileRegex: ${agentPermission.fileRegex}\n`;
953
+ newContent += ` description: ${agentPermission.description}\n`;
954
+ } else {
955
+ // Fallback to generic edit
956
+ newContent += ` - edit\n`;
957
+ }
958
+
959
+ console.log(chalk.green(`✓ Added Kilo mode: ${slug} (${icon} ${title})`));
960
+ }
961
+
962
+ const finalContent = existingContent
963
+ ? existingContent.trim() + '\n' + newContent
964
+ : 'customModes:\n' + newContent;
965
+
966
+ await fileManager.writeFile(filePath, finalContent);
967
+ console.log(chalk.green('✓ Created .kilocodemodes file in project root'));
968
+ console.log(chalk.green(`✓ KiloCode setup complete!`));
969
+ console.log(chalk.dim('Custom modes will be available when you open this project in KiloCode'));
970
+
971
+ return true;
972
+ }
390
973
 
391
- The \`.roomodes\` file defines all BMAD agents as custom modes using the proper \`customModes:\` structure. Modes are automatically available in Roo Code when you open this project.
974
+ async setupCline(installDir, selectedAgent) {
975
+ const clineRulesDir = path.join(installDir, '.clinerules');
976
+ const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
392
977
 
393
- ## Available Modes
978
+ await fileManager.ensureDirectory(clineRulesDir);
394
979
 
395
- ${agents.map((id) => `- **bmad-${id}** - ${this.getAgentTitle(id)}`).join("\n")}
980
+ // Load dynamic agent ordering from configuration
981
+ const config = await this.loadIdeAgentConfig();
982
+ const agentOrder = config['cline-order'] || {};
396
983
 
397
- ## Usage
984
+ for (const agentId of agents) {
985
+ // Find the agent file
986
+ const agentPath = await this.findAgentPath(agentId, installDir);
987
+
988
+ if (agentPath) {
989
+ const agentContent = await fileManager.readFile(agentPath);
990
+
991
+ // Get numeric prefix for ordering
992
+ const order = agentOrder[agentId] || 99;
993
+ const prefix = order.toString().padStart(2, '0');
994
+ const mdPath = path.join(clineRulesDir, `${prefix}-${agentId}.md`);
398
995
 
399
- In Roo Code:
400
- 1. Open the mode selector (usually in the status bar)
401
- 2. Select any BMAD agent mode
402
- 3. The AI will adopt that agent's personality and expertise
996
+ // Create MD content for Cline (focused on project standards and role)
997
+ let mdContent = `# ${await this.getAgentTitle(agentId, installDir)} Agent\n\n`;
998
+ mdContent += `This rule defines the ${await this.getAgentTitle(agentId, installDir)} persona and project standards.\n\n`;
999
+ mdContent += '## Role Definition\n\n';
1000
+ mdContent +=
1001
+ 'When the user types `@' +
1002
+ agentId +
1003
+ '`, adopt this persona and follow these guidelines:\n\n';
1004
+ mdContent += '```yaml\n';
1005
+ // Extract just the YAML content from the agent file
1006
+ const yamlContent = extractYamlFromAgent(agentContent);
1007
+ if (yamlContent) {
1008
+ mdContent += yamlContent;
1009
+ } else {
1010
+ // If no YAML found, include the whole content minus the header
1011
+ mdContent += agentContent.replace(/^#.*$/m, '').trim();
1012
+ }
1013
+ mdContent += '\n```\n\n';
1014
+ mdContent += '## Project Standards\n\n';
1015
+ mdContent += `- Always maintain consistency with project documentation in .bmad-core/\n`;
1016
+ mdContent += `- Follow the agent's specific guidelines and constraints\n`;
1017
+ mdContent += `- Update relevant project files when making changes\n`;
1018
+ const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
1019
+ mdContent += `- Reference the complete agent definition in [${relativePath}](${relativePath})\n\n`;
1020
+ mdContent += '## Usage\n\n';
1021
+ mdContent += `Type \`@${agentId}\` to activate this ${await this.getAgentTitle(agentId, installDir)} persona.\n`;
1022
+
1023
+ await fileManager.writeFile(mdPath, mdContent);
1024
+ console.log(chalk.green(`✓ Created rule: ${prefix}-${agentId}.md`));
1025
+ }
1026
+ }
403
1027
 
404
- ## File Permissions
1028
+ console.log(chalk.green(`\n✓ Created Cline rules in ${clineRulesDir}`));
1029
+
1030
+ return true;
1031
+ }
1032
+
1033
+ async setupGeminiCli(installDir) {
1034
+ const geminiDir = path.join(installDir, '.gemini');
1035
+ const bmadMethodDir = path.join(geminiDir, 'bmad-method');
1036
+ await fileManager.ensureDirectory(bmadMethodDir);
1037
+
1038
+ // Update logic for existing settings.json
1039
+ const settingsPath = path.join(geminiDir, 'settings.json');
1040
+ if (await fileManager.pathExists(settingsPath)) {
1041
+ try {
1042
+ const settingsContent = await fileManager.readFile(settingsPath);
1043
+ const settings = JSON.parse(settingsContent);
1044
+ let updated = false;
1045
+
1046
+ // Handle contextFileName property
1047
+ if (settings.contextFileName && Array.isArray(settings.contextFileName)) {
1048
+ const originalLength = settings.contextFileName.length;
1049
+ settings.contextFileName = settings.contextFileName.filter(
1050
+ (fileName) => !fileName.startsWith('agents/'),
1051
+ );
1052
+ if (settings.contextFileName.length !== originalLength) {
1053
+ updated = true;
1054
+ }
1055
+ }
1056
+
1057
+ if (updated) {
1058
+ await fileManager.writeFile(settingsPath, JSON.stringify(settings, null, 2));
1059
+ console.log(
1060
+ chalk.green('✓ Updated .gemini/settings.json - removed agent file references'),
1061
+ );
1062
+ }
1063
+ } catch (error) {
1064
+ console.warn(chalk.yellow('Could not update .gemini/settings.json'), error);
1065
+ }
1066
+ }
1067
+
1068
+ // Remove old agents directory
1069
+ const agentsDir = path.join(geminiDir, 'agents');
1070
+ if (await fileManager.pathExists(agentsDir)) {
1071
+ await fileManager.removeDirectory(agentsDir);
1072
+ console.log(chalk.green('✓ Removed old .gemini/agents directory'));
1073
+ }
1074
+
1075
+ // Get all available agents
1076
+ const agents = await this.getAllAgentIds(installDir);
1077
+ let concatenatedContent = '';
1078
+
1079
+ for (const agentId of agents) {
1080
+ // Find the source agent file
1081
+ const agentPath = await this.findAgentPath(agentId, installDir);
1082
+
1083
+ if (agentPath) {
1084
+ const agentContent = await fileManager.readFile(agentPath);
1085
+
1086
+ // Create properly formatted agent rule content (similar to trae)
1087
+ let agentRuleContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
1088
+ agentRuleContent += `This rule is triggered when the user types \`*${agentId}\` and activates the ${await this.getAgentTitle(
1089
+ agentId,
1090
+ installDir,
1091
+ )} agent persona.\n\n`;
1092
+ agentRuleContent += '## Agent Activation\n\n';
1093
+ agentRuleContent +=
1094
+ 'CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n';
1095
+ agentRuleContent += '```yaml\n';
1096
+ // Extract just the YAML content from the agent file
1097
+ const yamlContent = extractYamlFromAgent(agentContent);
1098
+ if (yamlContent) {
1099
+ agentRuleContent += yamlContent;
1100
+ } else {
1101
+ // If no YAML found, include the whole content minus the header
1102
+ agentRuleContent += agentContent.replace(/^#.*$/m, '').trim();
1103
+ }
1104
+ agentRuleContent += '\n```\n\n';
1105
+ agentRuleContent += '## File Reference\n\n';
1106
+ const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
1107
+ agentRuleContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
1108
+ agentRuleContent += '## Usage\n\n';
1109
+ agentRuleContent += `When the user types \`*${agentId}\`, activate this ${await this.getAgentTitle(
1110
+ agentId,
1111
+ installDir,
1112
+ )} persona and follow all instructions defined in the YAML configuration above.\n`;
1113
+
1114
+ // Add to concatenated content with separator
1115
+ concatenatedContent += agentRuleContent + '\n\n---\n\n';
1116
+ console.log(chalk.green(`✓ Added context for @${agentId}`));
1117
+ }
1118
+ }
1119
+
1120
+ // Write the concatenated content to GEMINI.md
1121
+ const geminiMdPath = path.join(bmadMethodDir, 'GEMINI.md');
1122
+ await fileManager.writeFile(geminiMdPath, concatenatedContent);
1123
+ console.log(chalk.green(`\n✓ Created GEMINI.md in ${bmadMethodDir}`));
1124
+
1125
+ return true;
1126
+ }
1127
+
1128
+ async setupQwenCode(installDir, selectedAgent) {
1129
+ const qwenDir = path.join(installDir, '.qwen');
1130
+ const bmadMethodDir = path.join(qwenDir, 'bmad-method');
1131
+ await fileManager.ensureDirectory(bmadMethodDir);
1132
+
1133
+ // Update logic for existing settings.json
1134
+ const settingsPath = path.join(qwenDir, 'settings.json');
1135
+ if (await fileManager.pathExists(settingsPath)) {
1136
+ try {
1137
+ const settingsContent = await fileManager.readFile(settingsPath);
1138
+ const settings = JSON.parse(settingsContent);
1139
+ let updated = false;
1140
+
1141
+ // Handle contextFileName property
1142
+ if (settings.contextFileName && Array.isArray(settings.contextFileName)) {
1143
+ const originalLength = settings.contextFileName.length;
1144
+ settings.contextFileName = settings.contextFileName.filter(
1145
+ (fileName) => !fileName.startsWith('agents/'),
1146
+ );
1147
+ if (settings.contextFileName.length !== originalLength) {
1148
+ updated = true;
1149
+ }
1150
+ }
1151
+
1152
+ if (updated) {
1153
+ await fileManager.writeFile(settingsPath, JSON.stringify(settings, null, 2));
1154
+ console.log(chalk.green('✓ Updated .qwen/settings.json - removed agent file references'));
1155
+ }
1156
+ } catch (error) {
1157
+ console.warn(chalk.yellow('Could not update .qwen/settings.json'), error);
1158
+ }
1159
+ }
1160
+
1161
+ // Remove old agents directory
1162
+ const agentsDir = path.join(qwenDir, 'agents');
1163
+ if (await fileManager.pathExists(agentsDir)) {
1164
+ await fileManager.removeDirectory(agentsDir);
1165
+ console.log(chalk.green('✓ Removed old .qwen/agents directory'));
1166
+ }
1167
+
1168
+ // Get all available agents
1169
+ const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
1170
+ let concatenatedContent = '';
1171
+
1172
+ for (const agentId of agents) {
1173
+ // Find the source agent file
1174
+ const agentPath = await this.findAgentPath(agentId, installDir);
1175
+
1176
+ if (agentPath) {
1177
+ const agentContent = await fileManager.readFile(agentPath);
1178
+
1179
+ // Create properly formatted agent rule content (similar to gemini)
1180
+ let agentRuleContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
1181
+ agentRuleContent += `This rule is triggered when the user types \`*${agentId}\` and activates the ${await this.getAgentTitle(
1182
+ agentId,
1183
+ installDir,
1184
+ )} agent persona.\n\n`;
1185
+ agentRuleContent += '## Agent Activation\n\n';
1186
+ agentRuleContent +=
1187
+ 'CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n';
1188
+ agentRuleContent += '```yaml\n';
1189
+ // Extract just the YAML content from the agent file
1190
+ const yamlContent = extractYamlFromAgent(agentContent);
1191
+ if (yamlContent) {
1192
+ agentRuleContent += yamlContent;
1193
+ } else {
1194
+ // If no YAML found, include the whole content minus the header
1195
+ agentRuleContent += agentContent.replace(/^#.*$/m, '').trim();
1196
+ }
1197
+ agentRuleContent += '\n```\n\n';
1198
+ agentRuleContent += '## File Reference\n\n';
1199
+ const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
1200
+ agentRuleContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
1201
+ agentRuleContent += '## Usage\n\n';
1202
+ agentRuleContent += `When the user types \`*${agentId}\`, activate this ${await this.getAgentTitle(
1203
+ agentId,
1204
+ installDir,
1205
+ )} persona and follow all instructions defined in the YAML configuration above.\n`;
1206
+
1207
+ // Add to concatenated content with separator
1208
+ concatenatedContent += agentRuleContent + '\n\n---\n\n';
1209
+ console.log(chalk.green(`✓ Added context for *${agentId}`));
1210
+ }
1211
+ }
1212
+
1213
+ // Write the concatenated content to QWEN.md
1214
+ const qwenMdPath = path.join(bmadMethodDir, 'QWEN.md');
1215
+ await fileManager.writeFile(qwenMdPath, concatenatedContent);
1216
+ console.log(chalk.green(`\n✓ Created QWEN.md in ${bmadMethodDir}`));
1217
+
1218
+ return true;
1219
+ }
1220
+
1221
+ async setupGitHubCopilot(
1222
+ installDir,
1223
+ selectedAgent,
1224
+ spinner = null,
1225
+ preConfiguredSettings = null,
1226
+ ) {
1227
+ // Configure VS Code workspace settings first to avoid UI conflicts with loading spinners
1228
+ await this.configureVsCodeSettings(installDir, spinner, preConfiguredSettings);
1229
+
1230
+ const chatmodesDir = path.join(installDir, '.github', 'chatmodes');
1231
+ const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
1232
+
1233
+ await fileManager.ensureDirectory(chatmodesDir);
1234
+
1235
+ for (const agentId of agents) {
1236
+ // Find the agent file
1237
+ const agentPath = await this.findAgentPath(agentId, installDir);
1238
+ const chatmodePath = path.join(chatmodesDir, `${agentId}.chatmode.md`);
1239
+
1240
+ if (agentPath) {
1241
+ // Create chat mode file with agent content
1242
+ const agentContent = await fileManager.readFile(agentPath);
1243
+ const agentTitle = await this.getAgentTitle(agentId, installDir);
1244
+
1245
+ // Extract whenToUse for the description
1246
+ const yamlMatch = agentContent.match(/```ya?ml\r?\n([\s\S]*?)```/);
1247
+ let description = `Activates the ${agentTitle} agent persona.`;
1248
+ if (yamlMatch) {
1249
+ const whenToUseMatch = yamlMatch[1].match(/whenToUse:\s*"(.*?)"/);
1250
+ if (whenToUseMatch && whenToUseMatch[1]) {
1251
+ description = whenToUseMatch[1];
1252
+ }
1253
+ }
1254
+
1255
+ let chatmodeContent = `---
1256
+ description: "${description.replaceAll('"', String.raw`\"`)}"
1257
+ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems', 'usages', 'editFiles', 'runCommands', 'runTasks', 'runTests', 'search', 'searchResults', 'terminalLastCommand', 'terminalSelection', 'testFailure']
1258
+ ---
405
1259
 
406
- Each agent has specific file access permissions:
407
- - **Analysts, PM, PO, SM**: Limited to documentation files (.md, .txt)
408
- - **Architect**: Architecture docs and configs (.md, .txt, .yml, .yaml, .json)
409
- - **QA**: Test files and documentation
410
- - **UX Expert**: Design-related files (.md, .css, .scss, .html, .jsx, .tsx)
411
- - **Developer, Orchestrator, Master**: Full edit access to all files
412
1260
  `;
1261
+ chatmodeContent += agentContent;
413
1262
 
414
- const readmePath = path.join(rooDir, "README.md");
415
- await fileManager.writeFile(readmePath, rooReadme);
416
- console.log(chalk.green("✓ Created .roo/README.md"));
1263
+ await fileManager.writeFile(chatmodePath, chatmodeContent);
1264
+ console.log(chalk.green(`✓ Created chat mode: ${agentId}.chatmode.md`));
1265
+ }
1266
+ }
417
1267
 
418
- console.log(chalk.green(`\n✓ Roo Code setup complete!`));
419
- console.log(
420
- chalk.dim(
421
- "Custom modes will be available when you open this project in Roo Code"
422
- )
423
- );
1268
+ console.log(chalk.green(`\n✓ Github Copilot setup complete!`));
1269
+ console.log(chalk.dim(`You can now find the BMad agents in the Chat view's mode selector.`));
424
1270
 
425
1271
  return true;
426
1272
  }
1273
+
1274
+ async configureVsCodeSettings(installDir, spinner, preConfiguredSettings = null) {
1275
+ const vscodeDir = path.join(installDir, '.vscode');
1276
+ const settingsPath = path.join(vscodeDir, 'settings.json');
1277
+
1278
+ await fileManager.ensureDirectory(vscodeDir);
1279
+
1280
+ // Read existing settings if they exist
1281
+ let existingSettings = {};
1282
+ if (await fileManager.pathExists(settingsPath)) {
1283
+ try {
1284
+ const existingContent = await fileManager.readFile(settingsPath);
1285
+ existingSettings = JSON.parse(existingContent);
1286
+ console.log(chalk.yellow('Found existing .vscode/settings.json. Merging BMad settings...'));
1287
+ } catch {
1288
+ console.warn(chalk.yellow('Could not parse existing settings.json. Creating new one.'));
1289
+ existingSettings = {};
1290
+ }
1291
+ }
1292
+
1293
+ // Use pre-configured settings if provided, otherwise prompt
1294
+ let configChoice;
1295
+ if (preConfiguredSettings && preConfiguredSettings.configChoice) {
1296
+ configChoice = preConfiguredSettings.configChoice;
1297
+ console.log(chalk.dim(`Using pre-configured GitHub Copilot settings: ${configChoice}`));
1298
+ } else {
1299
+ // Clear any previous output and add spacing to avoid conflicts with loaders
1300
+ console.log('\n'.repeat(2));
1301
+ console.log(chalk.blue('🔧 Github Copilot Agent Settings Configuration'));
1302
+ console.log(
1303
+ chalk.dim('BMad works best with specific VS Code settings for optimal agent experience.'),
1304
+ );
1305
+ console.log(''); // Add extra spacing
1306
+
1307
+ const response = await inquirer.prompt([
1308
+ {
1309
+ type: 'list',
1310
+ name: 'configChoice',
1311
+ message: chalk.yellow('How would you like to configure GitHub Copilot settings?'),
1312
+ choices: [
1313
+ {
1314
+ name: 'Use recommended defaults (fastest setup)',
1315
+ value: 'defaults',
1316
+ },
1317
+ {
1318
+ name: 'Configure each setting manually (customize to your preferences)',
1319
+ value: 'manual',
1320
+ },
1321
+ {
1322
+ name: "Skip settings configuration (I'll configure manually later)",
1323
+ value: 'skip',
1324
+ },
1325
+ ],
1326
+ default: 'defaults',
1327
+ },
1328
+ ]);
1329
+ configChoice = response.configChoice;
1330
+ }
1331
+
1332
+ let bmadSettings = {};
1333
+
1334
+ if (configChoice === 'skip') {
1335
+ console.log(chalk.yellow('⚠️ Skipping VS Code settings configuration.'));
1336
+ console.log(chalk.dim('You can manually configure these settings in .vscode/settings.json:'));
1337
+ console.log(chalk.dim(' • chat.agent.enabled: true'));
1338
+ console.log(chalk.dim(' • chat.agent.maxRequests: 15'));
1339
+ console.log(chalk.dim(' • github.copilot.chat.agent.runTasks: true'));
1340
+ console.log(chalk.dim(' • chat.mcp.discovery.enabled: true'));
1341
+ console.log(chalk.dim(' • github.copilot.chat.agent.autoFix: true'));
1342
+ console.log(chalk.dim(' • chat.tools.autoApprove: false'));
1343
+ return true;
1344
+ }
1345
+
1346
+ if (configChoice === 'defaults') {
1347
+ // Use recommended defaults
1348
+ bmadSettings = {
1349
+ 'chat.agent.enabled': true,
1350
+ 'chat.agent.maxRequests': 15,
1351
+ 'github.copilot.chat.agent.runTasks': true,
1352
+ 'chat.mcp.discovery.enabled': true,
1353
+ 'github.copilot.chat.agent.autoFix': true,
1354
+ 'chat.tools.autoApprove': false,
1355
+ };
1356
+ console.log(chalk.green('✓ Using recommended BMad defaults for Github Copilot settings'));
1357
+ } else {
1358
+ // Manual configuration
1359
+ console.log(chalk.blue("\n📋 Let's configure each setting for your preferences:"));
1360
+
1361
+ // Pause spinner during manual configuration prompts
1362
+ let spinnerWasActive = false;
1363
+ if (spinner && spinner.isSpinning) {
1364
+ spinner.stop();
1365
+ spinnerWasActive = true;
1366
+ }
1367
+
1368
+ const manualSettings = await inquirer.prompt([
1369
+ {
1370
+ type: 'input',
1371
+ name: 'maxRequests',
1372
+ message: 'Maximum requests per agent session (recommended: 15)?',
1373
+ default: '15',
1374
+ validate: (input) => {
1375
+ const number_ = Number.parseInt(input);
1376
+ if (isNaN(number_) || number_ < 1 || number_ > 50) {
1377
+ return 'Please enter a number between 1 and 50';
1378
+ }
1379
+ return true;
1380
+ },
1381
+ },
1382
+ {
1383
+ type: 'confirm',
1384
+ name: 'runTasks',
1385
+ message: 'Allow agents to run workspace tasks (package.json scripts, etc.)?',
1386
+ default: true,
1387
+ },
1388
+ {
1389
+ type: 'confirm',
1390
+ name: 'mcpDiscovery',
1391
+ message: 'Enable MCP (Model Context Protocol) server discovery?',
1392
+ default: true,
1393
+ },
1394
+ {
1395
+ type: 'confirm',
1396
+ name: 'autoFix',
1397
+ message: 'Enable automatic error detection and fixing in generated code?',
1398
+ default: true,
1399
+ },
1400
+ {
1401
+ type: 'confirm',
1402
+ name: 'autoApprove',
1403
+ message: 'Auto-approve ALL tools without confirmation? (⚠️ EXPERIMENTAL - less secure)',
1404
+ default: false,
1405
+ },
1406
+ ]);
1407
+
1408
+ // Restart spinner if it was active before prompts
1409
+ if (spinner && spinnerWasActive) {
1410
+ spinner.start();
1411
+ }
1412
+
1413
+ bmadSettings = {
1414
+ 'chat.agent.enabled': true, // Always enabled - required for BMad agents
1415
+ 'chat.agent.maxRequests': Number.parseInt(manualSettings.maxRequests),
1416
+ 'github.copilot.chat.agent.runTasks': manualSettings.runTasks,
1417
+ 'chat.mcp.discovery.enabled': manualSettings.mcpDiscovery,
1418
+ 'github.copilot.chat.agent.autoFix': manualSettings.autoFix,
1419
+ 'chat.tools.autoApprove': manualSettings.autoApprove,
1420
+ };
1421
+
1422
+ console.log(chalk.green('✓ Custom settings configured'));
1423
+ }
1424
+
1425
+ // Merge settings (existing settings take precedence to avoid overriding user preferences)
1426
+ const mergedSettings = { ...bmadSettings, ...existingSettings };
1427
+
1428
+ // Write the updated settings
1429
+ await fileManager.writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2));
1430
+
1431
+ console.log(chalk.green('✓ VS Code workspace settings configured successfully'));
1432
+ console.log(chalk.dim(' Settings written to .vscode/settings.json:'));
1433
+ for (const [key, value] of Object.entries(bmadSettings)) {
1434
+ console.log(chalk.dim(` • ${key}: ${value}`));
1435
+ }
1436
+ console.log(chalk.dim(''));
1437
+ console.log(chalk.dim('You can modify these settings anytime in .vscode/settings.json'));
1438
+ }
427
1439
  }
428
1440
 
429
1441
  module.exports = new IdeSetup();