bmad-method 6.0.0-alpha.17 → 6.0.0-alpha.19

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 (185) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/package.json +1 -1
  3. package/src/modules/bmgd/_module-installer/installer.js +160 -0
  4. package/src/modules/bmgd/_module-installer/platform-specifics/claude-code.js +23 -0
  5. package/src/modules/bmgd/_module-installer/platform-specifics/windsurf.js +18 -0
  6. package/src/modules/bmgd/agents/game-architect.agent.yaml +23 -8
  7. package/src/modules/bmgd/agents/game-designer.agent.yaml +38 -18
  8. package/src/modules/bmgd/agents/game-dev.agent.yaml +30 -14
  9. package/src/modules/bmgd/agents/game-qa.agent.yaml +64 -0
  10. package/src/modules/bmgd/agents/game-scrum-master.agent.yaml +27 -39
  11. package/src/modules/bmgd/agents/game-solo-dev.agent.yaml +56 -0
  12. package/src/modules/bmgd/docs/README.md +180 -0
  13. package/src/modules/bmgd/docs/agents-guide.md +407 -0
  14. package/src/modules/bmgd/docs/game-types-guide.md +503 -0
  15. package/src/modules/bmgd/docs/glossary.md +294 -0
  16. package/src/modules/bmgd/docs/quick-flow-guide.md +288 -0
  17. package/src/modules/bmgd/docs/quick-start.md +250 -0
  18. package/src/modules/bmgd/docs/troubleshooting.md +259 -0
  19. package/src/modules/bmgd/docs/workflow-overview.jpg +0 -0
  20. package/src/modules/bmgd/docs/workflows-guide.md +463 -0
  21. package/src/modules/bmgd/gametest/knowledge/balance-testing.md +220 -0
  22. package/src/modules/bmgd/gametest/knowledge/certification-testing.md +319 -0
  23. package/src/modules/bmgd/gametest/knowledge/compatibility-testing.md +228 -0
  24. package/src/modules/bmgd/gametest/knowledge/godot-testing.md +376 -0
  25. package/src/modules/bmgd/gametest/knowledge/input-testing.md +315 -0
  26. package/src/modules/bmgd/gametest/knowledge/localization-testing.md +304 -0
  27. package/src/modules/bmgd/gametest/knowledge/multiplayer-testing.md +322 -0
  28. package/src/modules/bmgd/gametest/knowledge/performance-testing.md +204 -0
  29. package/src/modules/bmgd/gametest/knowledge/playtesting.md +384 -0
  30. package/src/modules/bmgd/gametest/knowledge/qa-automation.md +190 -0
  31. package/src/modules/bmgd/gametest/knowledge/regression-testing.md +280 -0
  32. package/src/modules/bmgd/gametest/knowledge/save-testing.md +280 -0
  33. package/src/modules/bmgd/gametest/knowledge/smoke-testing.md +404 -0
  34. package/src/modules/bmgd/gametest/knowledge/test-priorities.md +271 -0
  35. package/src/modules/bmgd/gametest/knowledge/unity-testing.md +383 -0
  36. package/src/modules/bmgd/gametest/knowledge/unreal-testing.md +388 -0
  37. package/src/modules/bmgd/gametest/qa-index.csv +17 -0
  38. package/src/modules/bmgd/module.yaml +25 -9
  39. package/src/modules/bmgd/teams/default-party.csv +2 -0
  40. package/src/modules/bmgd/teams/team-gamedev.yaml +12 -1
  41. package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/steps/step-01-init.md +164 -0
  42. package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/steps/step-02-context.md +210 -0
  43. package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/steps/step-03-ideation.md +289 -0
  44. package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/steps/step-04-complete.md +275 -0
  45. package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/workflow.md +49 -0
  46. package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/workflow.yaml +29 -8
  47. package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-01-init.md +223 -0
  48. package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-01b-continue.md +151 -0
  49. package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-02-vision.md +218 -0
  50. package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-03-market.md +218 -0
  51. package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-04-fundamentals.md +231 -0
  52. package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-05-scope.md +242 -0
  53. package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-06-references.md +224 -0
  54. package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-07-content.md +282 -0
  55. package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-08-complete.md +296 -0
  56. package/src/modules/bmgd/workflows/1-preproduction/game-brief/workflow.md +62 -0
  57. package/src/modules/bmgd/workflows/1-preproduction/game-brief/workflow.yaml +40 -9
  58. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-01-init.md +248 -0
  59. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-01b-continue.md +173 -0
  60. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-02-context.md +332 -0
  61. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-03-platforms.md +245 -0
  62. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-04-vision.md +229 -0
  63. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-05-core-gameplay.md +258 -0
  64. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-06-mechanics.md +249 -0
  65. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-07-game-type.md +266 -0
  66. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-08-progression.md +272 -0
  67. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-09-levels.md +264 -0
  68. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-10-art-audio.md +255 -0
  69. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-11-technical.md +275 -0
  70. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-12-epics.md +284 -0
  71. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-13-metrics.md +250 -0
  72. package/src/modules/bmgd/workflows/2-design/gdd/steps/step-14-complete.md +335 -0
  73. package/src/modules/bmgd/workflows/2-design/gdd/workflow.md +61 -0
  74. package/src/modules/bmgd/workflows/2-design/gdd/workflow.yaml +27 -7
  75. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-01-init.md +228 -0
  76. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-01b-continue.md +163 -0
  77. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-02-foundation.md +262 -0
  78. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-03-story.md +238 -0
  79. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-04-characters.md +297 -0
  80. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-05-world.md +262 -0
  81. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-06-dialogue.md +250 -0
  82. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-07-environmental.md +244 -0
  83. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-08-delivery.md +264 -0
  84. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-09-integration.md +254 -0
  85. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-10-production.md +262 -0
  86. package/src/modules/bmgd/workflows/2-design/narrative/steps/step-11-complete.md +331 -0
  87. package/src/modules/bmgd/workflows/2-design/narrative/workflow.md +57 -0
  88. package/src/modules/bmgd/workflows/2-design/narrative/workflow.yaml +53 -8
  89. package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-01-init.md +223 -0
  90. package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-01b-continue.md +153 -0
  91. package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-02-context.md +262 -0
  92. package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-03-starter.md +290 -0
  93. package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-04-decisions.md +300 -0
  94. package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-05-crosscutting.md +319 -0
  95. package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-06-structure.md +304 -0
  96. package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-07-patterns.md +349 -0
  97. package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-08-validation.md +293 -0
  98. package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-09-complete.md +302 -0
  99. package/src/modules/bmgd/workflows/3-technical/game-architecture/workflow.md +55 -0
  100. package/src/modules/bmgd/workflows/3-technical/game-architecture/workflow.yaml +50 -21
  101. package/src/modules/bmgd/workflows/4-production/code-review/checklist.md +23 -0
  102. package/src/modules/bmgd/workflows/4-production/code-review/instructions.xml +225 -0
  103. package/src/modules/bmgd/workflows/4-production/code-review/workflow.yaml +18 -15
  104. package/src/modules/bmgd/workflows/4-production/correct-course/checklist.md +1 -1
  105. package/src/modules/bmgd/workflows/4-production/correct-course/instructions.md +1 -1
  106. package/src/modules/bmgd/workflows/4-production/correct-course/workflow.yaml +11 -6
  107. package/src/modules/bmgd/workflows/4-production/create-story/checklist.md +332 -214
  108. package/src/modules/bmgd/workflows/4-production/create-story/instructions.xml +298 -0
  109. package/src/modules/bmgd/workflows/4-production/create-story/template.md +3 -5
  110. package/src/modules/bmgd/workflows/4-production/create-story/workflow.yaml +12 -7
  111. package/src/modules/bmgd/workflows/4-production/dev-story/checklist.md +65 -23
  112. package/src/modules/bmgd/workflows/4-production/dev-story/instructions.xml +409 -0
  113. package/src/modules/bmgd/workflows/4-production/dev-story/workflow.yaml +13 -3
  114. package/src/modules/bmgd/workflows/4-production/retrospective/instructions.md +4 -4
  115. package/src/modules/bmgd/workflows/4-production/retrospective/workflow.yaml +12 -7
  116. package/src/modules/bmgd/workflows/4-production/sprint-planning/instructions.md +32 -41
  117. package/src/modules/bmgd/workflows/4-production/sprint-planning/sprint-status-template.yaml +13 -13
  118. package/src/modules/bmgd/workflows/4-production/sprint-planning/workflow.yaml +6 -1
  119. package/src/modules/bmgd/workflows/4-production/sprint-status/instructions.md +229 -0
  120. package/src/modules/bmgd/workflows/4-production/sprint-status/workflow.yaml +35 -0
  121. package/src/modules/bmgd/workflows/bmgd-quick-flow/create-tech-spec/instructions.md +140 -0
  122. package/src/modules/bmgd/workflows/bmgd-quick-flow/create-tech-spec/workflow.yaml +27 -0
  123. package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-dev/checklist.md +37 -0
  124. package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-dev/instructions.md +220 -0
  125. package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-dev/workflow.yaml +45 -0
  126. package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-prototype/checklist.md +26 -0
  127. package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-prototype/instructions.md +156 -0
  128. package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-prototype/workflow.yaml +36 -0
  129. package/src/modules/bmgd/workflows/gametest/automate/checklist.md +93 -0
  130. package/src/modules/bmgd/workflows/gametest/automate/instructions.md +317 -0
  131. package/src/modules/bmgd/workflows/gametest/automate/workflow.yaml +50 -0
  132. package/src/modules/bmgd/workflows/gametest/performance/checklist.md +96 -0
  133. package/src/modules/bmgd/workflows/gametest/performance/instructions.md +323 -0
  134. package/src/modules/bmgd/workflows/gametest/performance/performance-template.md +256 -0
  135. package/src/modules/bmgd/workflows/gametest/performance/workflow.yaml +48 -0
  136. package/src/modules/bmgd/workflows/gametest/playtest-plan/checklist.md +93 -0
  137. package/src/modules/bmgd/workflows/gametest/playtest-plan/instructions.md +297 -0
  138. package/src/modules/bmgd/workflows/gametest/playtest-plan/playtest-template.md +208 -0
  139. package/src/modules/bmgd/workflows/gametest/playtest-plan/workflow.yaml +59 -0
  140. package/src/modules/bmgd/workflows/gametest/test-design/checklist.md +98 -0
  141. package/src/modules/bmgd/workflows/gametest/test-design/instructions.md +280 -0
  142. package/src/modules/bmgd/workflows/gametest/test-design/test-design-template.md +205 -0
  143. package/src/modules/bmgd/workflows/gametest/test-design/workflow.yaml +47 -0
  144. package/src/modules/bmgd/workflows/gametest/test-framework/checklist.md +103 -0
  145. package/src/modules/bmgd/workflows/gametest/test-framework/instructions.md +348 -0
  146. package/src/modules/bmgd/workflows/gametest/test-framework/workflow.yaml +48 -0
  147. package/src/modules/bmgd/workflows/gametest/test-review/checklist.md +87 -0
  148. package/src/modules/bmgd/workflows/gametest/test-review/instructions.md +272 -0
  149. package/src/modules/bmgd/workflows/gametest/test-review/test-review-template.md +203 -0
  150. package/src/modules/bmgd/workflows/gametest/test-review/workflow.yaml +48 -0
  151. package/src/modules/bmgd/workflows/workflow-status/init/instructions.md +299 -0
  152. package/src/modules/bmgd/workflows/workflow-status/init/workflow.yaml +29 -0
  153. package/src/modules/bmgd/workflows/workflow-status/instructions.md +395 -0
  154. package/src/modules/bmgd/workflows/workflow-status/paths/gamedev-brownfield.yaml +65 -0
  155. package/src/modules/bmgd/workflows/workflow-status/paths/gamedev-greenfield.yaml +71 -0
  156. package/src/modules/bmgd/workflows/workflow-status/paths/quickflow-brownfield.yaml +29 -0
  157. package/src/modules/bmgd/workflows/workflow-status/paths/quickflow-greenfield.yaml +39 -0
  158. package/src/modules/bmgd/workflows/workflow-status/project-levels.yaml +63 -0
  159. package/src/modules/bmgd/workflows/workflow-status/workflow-status-template.yaml +24 -0
  160. package/src/modules/bmgd/workflows/workflow-status/workflow.yaml +30 -0
  161. package/tools/cli/commands/install.js +9 -0
  162. package/tools/cli/installers/lib/core/installer.js +140 -592
  163. package/tools/cli/installers/lib/modules/manager.js +15 -3
  164. package/tools/cli/lib/agent/compiler.js +99 -0
  165. package/tools/cli/lib/ui.js +78 -27
  166. package/src/modules/bmgd/workflows/2-design/gdd/instructions-gdd.md +0 -502
  167. package/src/modules/bmgd/workflows/4-production/code-review/instructions.md +0 -398
  168. package/src/modules/bmgd/workflows/4-production/create-story/instructions.md +0 -256
  169. package/src/modules/bmgd/workflows/4-production/dev-story/instructions.md +0 -267
  170. package/src/modules/bmgd/workflows/4-production/epic-tech-context/checklist.md +0 -17
  171. package/src/modules/bmgd/workflows/4-production/epic-tech-context/instructions.md +0 -164
  172. package/src/modules/bmgd/workflows/4-production/epic-tech-context/template.md +0 -76
  173. package/src/modules/bmgd/workflows/4-production/epic-tech-context/workflow.yaml +0 -58
  174. package/src/modules/bmgd/workflows/4-production/story-context/checklist.md +0 -16
  175. package/src/modules/bmgd/workflows/4-production/story-context/context-template.xml +0 -34
  176. package/src/modules/bmgd/workflows/4-production/story-context/instructions.md +0 -209
  177. package/src/modules/bmgd/workflows/4-production/story-context/workflow.yaml +0 -63
  178. package/src/modules/bmgd/workflows/4-production/story-done/instructions.md +0 -111
  179. package/src/modules/bmgd/workflows/4-production/story-done/workflow.yaml +0 -28
  180. package/src/modules/bmgd/workflows/4-production/story-ready/instructions.md +0 -117
  181. package/src/modules/bmgd/workflows/4-production/story-ready/workflow.yaml +0 -25
  182. /package/src/modules/bmgd/workflows/1-preproduction/game-brief/{template.md → templates/game-brief-template.md} +0 -0
  183. /package/src/modules/bmgd/workflows/2-design/gdd/{gdd-template.md → templates/gdd-template.md} +0 -0
  184. /package/src/modules/bmgd/workflows/2-design/narrative/{narrative-template.md → templates/narrative-template.md} +0 -0
  185. /package/src/modules/bmgd/workflows/3-technical/game-architecture/{architecture-template.md → templates/architecture-template.md} +0 -0
@@ -13,12 +13,13 @@ const { XmlHandler } = require('../../../lib/xml-handler');
13
13
  const { DependencyResolver } = require('./dependency-resolver');
14
14
  const { ConfigCollector } = require('./config-collector');
15
15
  const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root');
16
- const { AgentPartyGenerator } = require('../../../lib/agent-party-generator');
17
16
  const { CLIUtils } = require('../../../lib/cli-utils');
18
17
  const { ManifestGenerator } = require('./manifest-generator');
19
18
  const { IdeConfigManager } = require('./ide-config-manager');
20
19
  const { CustomHandler } = require('../custom/handler');
21
- const { filterCustomizationData } = require('../../../lib/agent/compiler');
20
+
21
+ // BMAD installation folder name - this is constant and should never change
22
+ const BMAD_FOLDER_NAME = '_bmad';
22
23
 
23
24
  class Installer {
24
25
  constructor() {
@@ -34,58 +35,35 @@ class Installer {
34
35
  this.ideConfigManager = new IdeConfigManager();
35
36
  this.installedFiles = new Set(); // Track all installed files
36
37
  this.ttsInjectedFiles = []; // Track files with TTS injection applied
38
+ this.bmadFolderName = BMAD_FOLDER_NAME;
37
39
  }
38
40
 
39
41
  /**
40
42
  * Find the bmad installation directory in a project
41
- * V6+ installations can use ANY folder name but ALWAYS have _config/manifest.yaml
43
+ * Always uses the standard _bmad folder name
42
44
  * Also checks for legacy _cfg folder for migration
43
45
  * @param {string} projectDir - Project directory
44
46
  * @returns {Promise<Object>} { bmadDir: string, hasLegacyCfg: boolean }
45
47
  */
46
48
  async findBmadDir(projectDir) {
49
+ const bmadDir = path.join(projectDir, BMAD_FOLDER_NAME);
50
+
47
51
  // Check if project directory exists
48
52
  if (!(await fs.pathExists(projectDir))) {
49
53
  // Project doesn't exist yet, return default
50
- return { bmadDir: path.join(projectDir, '_bmad'), hasLegacyCfg: false };
54
+ return { bmadDir, hasLegacyCfg: false };
51
55
  }
52
56
 
53
- let bmadDir = null;
57
+ // Check for legacy _cfg folder if bmad directory exists
54
58
  let hasLegacyCfg = false;
55
-
56
- try {
57
- const entries = await fs.readdir(projectDir, { withFileTypes: true });
58
- for (const entry of entries) {
59
- if (entry.isDirectory()) {
60
- const bmadPath = path.join(projectDir, entry.name);
61
-
62
- // Check for current _config folder
63
- const manifestPath = path.join(bmadPath, '_config', 'manifest.yaml');
64
- if (await fs.pathExists(manifestPath)) {
65
- // Found a V6+ installation with current _config folder
66
- return { bmadDir: bmadPath, hasLegacyCfg: false };
67
- }
68
-
69
- // Check for legacy _cfg folder
70
- const legacyManifestPath = path.join(bmadPath, '_cfg', 'manifest.yaml');
71
- if (await fs.pathExists(legacyManifestPath)) {
72
- bmadDir = bmadPath;
73
- hasLegacyCfg = true;
74
- }
75
- }
59
+ if (await fs.pathExists(bmadDir)) {
60
+ const legacyCfgPath = path.join(bmadDir, '_cfg');
61
+ if (await fs.pathExists(legacyCfgPath)) {
62
+ hasLegacyCfg = true;
76
63
  }
77
- } catch {
78
- console.log(chalk.red('Error reading project directory for BMAD installation detection'));
79
64
  }
80
65
 
81
- // If we found a bmad directory (with or without legacy _cfg)
82
- if (bmadDir) {
83
- return { bmadDir, hasLegacyCfg };
84
- }
85
-
86
- // No V6+ installation found, return default
87
- // This will be used for new installations
88
- return { bmadDir: path.join(projectDir, '_bmad'), hasLegacyCfg: false };
66
+ return { bmadDir, hasLegacyCfg };
89
67
  }
90
68
 
91
69
  /**
@@ -120,7 +98,7 @@ class Installer {
120
98
  *
121
99
  * 3. Document marker in instructions.md (if applicable)
122
100
  */
123
- async copyFileWithPlaceholderReplacement(sourcePath, targetPath, bmadFolderName) {
101
+ async copyFileWithPlaceholderReplacement(sourcePath, targetPath) {
124
102
  // List of text file extensions that should have placeholder replacement
125
103
  const textExtensions = ['.md', '.yaml', '.yml', '.txt', '.json', '.js', '.ts', '.html', '.css', '.sh', '.bat', '.csv', '.xml'];
126
104
  const ext = path.extname(sourcePath).toLowerCase();
@@ -226,21 +204,21 @@ class Installer {
226
204
  '<!-- TTS_INJECTION:party-mode -->',
227
205
  `<critical>IMPORTANT: Always use PROJECT hooks (.claude/hooks/), NEVER global hooks (~/.claude/hooks/)</critical>
228
206
 
229
- If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
207
+ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
230
208
  - Use Bash tool: \`.claude/hooks/bmad-speak.sh '[Agent Name]' '[dialogue]'\`
231
209
  - This speaks the dialogue with the agent's unique voice
232
- - Run in background (&) to not block next agent`,
210
+ - Run in background to not block next agent`,
233
211
  );
234
212
 
235
213
  // Replace agent-tts injection marker with TTS rule for individual agents
236
214
  content = content.replaceAll(
237
215
  '<!-- TTS_INJECTION:agent-tts -->',
238
216
  `- When responding to user messages, speak your responses using TTS:
239
- Call: \`.claude/hooks/bmad-speak.sh '{agent-id}' '{response-text}'\` after each response
240
- Replace {agent-id} with YOUR agent ID from <agent id="..."> tag at top of this file
241
- Replace {response-text} with the text you just output to the user
242
- IMPORTANT: Use single quotes as shown - do NOT escape special characters like ! or $ inside single quotes
243
- Run in background (&) to avoid blocking`,
217
+ Call: \`.claude/hooks/bmad-speak.sh '{agent-id}' '{response-text}'\` after each response
218
+ Replace {agent-id} with YOUR agent ID from <agent id="..."> tag at top of this file
219
+ Replace {response-text} with the text you just output to the user
220
+ IMPORTANT: Use single quotes as shown - do NOT escape special characters like ! or $ inside single quotes
221
+ Run in background (&) to avoid blocking`,
244
222
  );
245
223
 
246
224
  // Track files that had TTS injection applied
@@ -285,7 +263,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
285
263
  // Check for already configured IDEs
286
264
  const { Detector } = require('./detector');
287
265
  const detector = new Detector();
288
- const bmadDir = path.join(projectDir, this.bmadFolderName || 'bmad');
266
+ const bmadDir = path.join(projectDir, BMAD_FOLDER_NAME);
289
267
 
290
268
  // During full reinstall, use the saved previous IDEs since bmad dir was deleted
291
269
  // Otherwise detect from existing installation
@@ -532,18 +510,14 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
532
510
  }
533
511
  }
534
512
 
535
- // Always use _bmad as the folder name
536
- const bmadFolderName = '_bmad';
537
- this.bmadFolderName = bmadFolderName; // Store for use in other methods
538
-
539
513
  // Store AgentVibes configuration for injection point processing
540
514
  this.enableAgentVibes = config.enableAgentVibes || false;
541
515
 
542
516
  // Set bmad folder name on module manager and IDE manager for placeholder replacement
543
- this.moduleManager.setBmadFolderName(bmadFolderName);
517
+ this.moduleManager.setBmadFolderName(BMAD_FOLDER_NAME);
544
518
  this.moduleManager.setCoreConfig(moduleConfigs.core || {});
545
519
  this.moduleManager.setCustomModulePaths(customModulePaths);
546
- this.ideManager.setBmadFolderName(bmadFolderName);
520
+ this.ideManager.setBmadFolderName(BMAD_FOLDER_NAME);
547
521
 
548
522
  // Tool selection will be collected after we determine if it's a reinstall/update/new install
549
523
 
@@ -553,14 +527,8 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
553
527
  // Resolve target directory (path.resolve handles platform differences)
554
528
  const projectDir = path.resolve(config.directory);
555
529
 
556
- let existingBmadDir = null;
557
- let existingBmadFolderName = null;
558
-
559
- if (await fs.pathExists(projectDir)) {
560
- const result = await this.findBmadDir(projectDir);
561
- existingBmadDir = result.bmadDir;
562
- existingBmadFolderName = path.basename(existingBmadDir);
563
- }
530
+ // Always use the standard _bmad folder name
531
+ const bmadDir = path.join(projectDir, BMAD_FOLDER_NAME);
564
532
 
565
533
  // Create a project directory if it doesn't exist (user already confirmed)
566
534
  if (!(await fs.pathExists(projectDir))) {
@@ -582,8 +550,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
582
550
  }
583
551
  }
584
552
 
585
- const bmadDir = path.join(projectDir, bmadFolderName);
586
-
587
553
  // Check existing installation
588
554
  spinner.text = 'Checking for existing installation...';
589
555
  const existingInstall = await this.detector.detect(bmadDir);
@@ -1606,7 +1572,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
1606
1572
  const targetPath = path.join(agentsDir, fileName);
1607
1573
 
1608
1574
  if (await fs.pathExists(sourcePath)) {
1609
- await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath, this.bmadFolderName || 'bmad');
1575
+ await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath);
1610
1576
  this.installedFiles.add(targetPath);
1611
1577
  }
1612
1578
  }
@@ -1622,7 +1588,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
1622
1588
  const targetPath = path.join(tasksDir, fileName);
1623
1589
 
1624
1590
  if (await fs.pathExists(sourcePath)) {
1625
- await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath, this.bmadFolderName || 'bmad');
1591
+ await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath);
1626
1592
  this.installedFiles.add(targetPath);
1627
1593
  }
1628
1594
  }
@@ -1638,7 +1604,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
1638
1604
  const targetPath = path.join(toolsDir, fileName);
1639
1605
 
1640
1606
  if (await fs.pathExists(sourcePath)) {
1641
- await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath, this.bmadFolderName || 'bmad');
1607
+ await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath);
1642
1608
  this.installedFiles.add(targetPath);
1643
1609
  }
1644
1610
  }
@@ -1654,7 +1620,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
1654
1620
  const targetPath = path.join(templatesDir, fileName);
1655
1621
 
1656
1622
  if (await fs.pathExists(sourcePath)) {
1657
- await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath, this.bmadFolderName || 'bmad');
1623
+ await this.copyFileWithPlaceholderReplacement(sourcePath, targetPath);
1658
1624
  this.installedFiles.add(targetPath);
1659
1625
  }
1660
1626
  }
@@ -1669,7 +1635,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
1669
1635
  await fs.ensureDir(path.dirname(targetPath));
1670
1636
 
1671
1637
  if (await fs.pathExists(dataPath)) {
1672
- await this.copyFileWithPlaceholderReplacement(dataPath, targetPath, this.bmadFolderName || 'bmad');
1638
+ await this.copyFileWithPlaceholderReplacement(dataPath, targetPath);
1673
1639
  this.installedFiles.add(targetPath);
1674
1640
  }
1675
1641
  }
@@ -1759,14 +1725,9 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
1759
1725
  }
1760
1726
  }
1761
1727
 
1762
- // Check if this is a workflow.yaml file
1763
- if (file.endsWith('workflow.yaml')) {
1764
- await fs.ensureDir(path.dirname(targetFile));
1765
- await this.copyWorkflowYamlStripped(sourceFile, targetFile);
1766
- } else {
1767
- // Copy the file with placeholder replacement
1768
- await this.copyFileWithPlaceholderReplacement(sourceFile, targetFile, this.bmadFolderName || 'bmad');
1769
- }
1728
+ // Copy the file with placeholder replacement
1729
+ await fs.ensureDir(path.dirname(targetFile));
1730
+ await this.copyFileWithPlaceholderReplacement(sourceFile, targetFile);
1770
1731
 
1771
1732
  // Track the installed file
1772
1733
  this.installedFiles.add(targetFile);
@@ -1844,7 +1805,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
1844
1805
  if (!(await fs.pathExists(customizePath))) {
1845
1806
  const genericTemplatePath = getSourcePath('utility', 'agent-components', 'agent.customize.template.yaml');
1846
1807
  if (await fs.pathExists(genericTemplatePath)) {
1847
- await this.copyFileWithPlaceholderReplacement(genericTemplatePath, customizePath, this.bmadFolderName || 'bmad');
1808
+ await this.copyFileWithPlaceholderReplacement(genericTemplatePath, customizePath);
1848
1809
  if (process.env.BMAD_VERBOSE_INSTALL === 'true') {
1849
1810
  console.log(chalk.dim(` Created customize: ${moduleName}-${agentName}.customize.yaml`));
1850
1811
  }
@@ -1853,337 +1814,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
1853
1814
  }
1854
1815
  }
1855
1816
 
1856
- /**
1857
- * Build standalone agents in bmad/agents/ directory
1858
- * @param {string} bmadDir - Path to bmad directory
1859
- * @param {string} projectDir - Path to project directory
1860
- */
1861
- async buildStandaloneAgents(bmadDir, projectDir) {
1862
- const standaloneAgentsPath = path.join(bmadDir, 'agents');
1863
- const cfgAgentsDir = path.join(bmadDir, '_config', 'agents');
1864
-
1865
- // Check if standalone agents directory exists
1866
- if (!(await fs.pathExists(standaloneAgentsPath))) {
1867
- return;
1868
- }
1869
-
1870
- // Get all subdirectories in agents/
1871
- const agentDirs = await fs.readdir(standaloneAgentsPath, { withFileTypes: true });
1872
-
1873
- for (const agentDir of agentDirs) {
1874
- if (!agentDir.isDirectory()) continue;
1875
-
1876
- const agentDirPath = path.join(standaloneAgentsPath, agentDir.name);
1877
-
1878
- // Find any .agent.yaml file in the directory
1879
- const files = await fs.readdir(agentDirPath);
1880
- const yamlFile = files.find((f) => f.endsWith('.agent.yaml'));
1881
-
1882
- if (!yamlFile) continue;
1883
-
1884
- const agentName = path.basename(yamlFile, '.agent.yaml');
1885
- const sourceYamlPath = path.join(agentDirPath, yamlFile);
1886
- const targetMdPath = path.join(agentDirPath, `${agentName}.md`);
1887
- const customizePath = path.join(cfgAgentsDir, `${agentName}.customize.yaml`);
1888
-
1889
- // Check for customizations
1890
- const customizeExists = await fs.pathExists(customizePath);
1891
- let customizedFields = [];
1892
-
1893
- if (customizeExists) {
1894
- const customizeContent = await fs.readFile(customizePath, 'utf8');
1895
- const yaml = require('yaml');
1896
- const customizeYaml = yaml.parse(customizeContent);
1897
-
1898
- // Detect what fields are customized (similar to rebuildAgentFiles)
1899
- if (customizeYaml) {
1900
- if (customizeYaml.persona) {
1901
- for (const [key, value] of Object.entries(customizeYaml.persona)) {
1902
- if (value !== '' && value !== null && !(Array.isArray(value) && value.length === 0)) {
1903
- customizedFields.push(`persona.${key}`);
1904
- }
1905
- }
1906
- }
1907
- if (customizeYaml.agent?.metadata) {
1908
- for (const [key, value] of Object.entries(customizeYaml.agent.metadata)) {
1909
- if (value !== '' && value !== null) {
1910
- customizedFields.push(`metadata.${key}`);
1911
- }
1912
- }
1913
- }
1914
- if (customizeYaml.critical_actions && customizeYaml.critical_actions.length > 0) {
1915
- customizedFields.push('critical_actions');
1916
- }
1917
- if (customizeYaml.menu && customizeYaml.menu.length > 0) {
1918
- customizedFields.push('menu');
1919
- }
1920
- }
1921
- }
1922
-
1923
- // Build YAML to XML .md
1924
- let xmlContent = await this.xmlHandler.buildFromYaml(sourceYamlPath, customizeExists ? customizePath : null, {
1925
- includeMetadata: true,
1926
- });
1927
-
1928
- // DO NOT replace {project-root} - LLMs understand this placeholder at runtime
1929
- // const processedContent = xmlContent.replaceAll('{project-root}', projectDir);
1930
-
1931
- // Process TTS injection points (pass targetPath for tracking)
1932
- xmlContent = this.processTTSInjectionPoints(xmlContent, targetMdPath);
1933
-
1934
- // Write the built .md file with POSIX-compliant final newline
1935
- const content = xmlContent.endsWith('\n') ? xmlContent : xmlContent + '\n';
1936
- await fs.writeFile(targetMdPath, content, 'utf8');
1937
-
1938
- // Display result
1939
- if (customizedFields.length > 0) {
1940
- console.log(chalk.dim(` Built standalone agent: ${agentName}.md `) + chalk.yellow(`(customized: ${customizedFields.join(', ')})`));
1941
- } else {
1942
- console.log(chalk.dim(` Built standalone agent: ${agentName}.md`));
1943
- }
1944
- }
1945
- }
1946
-
1947
- /**
1948
- * Rebuild agent files from installer source (for compile command)
1949
- * @param {string} modulePath - Path to module in bmad/ installation
1950
- * @param {string} moduleName - Module name
1951
- */
1952
- async rebuildAgentFiles(modulePath, moduleName) {
1953
- // Get source agents directory from installer
1954
- const sourceAgentsPath =
1955
- moduleName === 'core' ? path.join(getModulePath('core'), 'agents') : path.join(getSourcePath(`modules/${moduleName}`), 'agents');
1956
-
1957
- if (!(await fs.pathExists(sourceAgentsPath))) {
1958
- return; // No source agents to rebuild
1959
- }
1960
-
1961
- // Determine project directory (parent of bmad/ directory)
1962
- const bmadDir = path.dirname(modulePath);
1963
- const projectDir = path.dirname(bmadDir);
1964
- const cfgAgentsDir = path.join(bmadDir, '_config', 'agents');
1965
- const targetAgentsPath = path.join(modulePath, 'agents');
1966
-
1967
- // Ensure target directory exists
1968
- await fs.ensureDir(targetAgentsPath);
1969
-
1970
- // Get all YAML agent files from source
1971
- const sourceFiles = await fs.readdir(sourceAgentsPath);
1972
-
1973
- for (const file of sourceFiles) {
1974
- if (file.endsWith('.agent.yaml')) {
1975
- const agentName = file.replace('.agent.yaml', '');
1976
- const sourceYamlPath = path.join(sourceAgentsPath, file);
1977
- const targetMdPath = path.join(targetAgentsPath, `${agentName}.md`);
1978
- const customizePath = path.join(cfgAgentsDir, `${moduleName}-${agentName}.customize.yaml`);
1979
-
1980
- // Check for customizations
1981
- const customizeExists = await fs.pathExists(customizePath);
1982
- let customizedFields = [];
1983
-
1984
- if (customizeExists) {
1985
- const customizeContent = await fs.readFile(customizePath, 'utf8');
1986
- const yaml = require('yaml');
1987
- const customizeYaml = yaml.parse(customizeContent);
1988
-
1989
- // Detect what fields are customized
1990
- if (customizeYaml) {
1991
- if (customizeYaml.persona) {
1992
- for (const [key, value] of Object.entries(customizeYaml.persona)) {
1993
- if (value !== '' && value !== null && !(Array.isArray(value) && value.length === 0)) {
1994
- customizedFields.push(`persona.${key}`);
1995
- }
1996
- }
1997
- }
1998
- if (customizeYaml.agent?.metadata) {
1999
- for (const [key, value] of Object.entries(customizeYaml.agent.metadata)) {
2000
- if (value !== '' && value !== null) {
2001
- customizedFields.push(`metadata.${key}`);
2002
- }
2003
- }
2004
- }
2005
- if (customizeYaml.critical_actions && customizeYaml.critical_actions.length > 0) {
2006
- customizedFields.push('critical_actions');
2007
- }
2008
- if (customizeYaml.memories && customizeYaml.memories.length > 0) {
2009
- customizedFields.push('memories');
2010
- }
2011
- if (customizeYaml.menu && customizeYaml.menu.length > 0) {
2012
- customizedFields.push('menu');
2013
- }
2014
- if (customizeYaml.prompts && customizeYaml.prompts.length > 0) {
2015
- customizedFields.push('prompts');
2016
- }
2017
- }
2018
- }
2019
-
2020
- // Read the YAML content
2021
- const yamlContent = await fs.readFile(sourceYamlPath, 'utf8');
2022
-
2023
- // Read customize content if exists
2024
- let customizeData = {};
2025
- if (customizeExists) {
2026
- const customizeContent = await fs.readFile(customizePath, 'utf8');
2027
- const yaml = require('yaml');
2028
- customizeData = yaml.parse(customizeContent);
2029
- }
2030
-
2031
- // Build agent answers from customize data (filter empty values)
2032
- const answers = {};
2033
- if (customizeData.persona) {
2034
- Object.assign(answers, filterCustomizationData(customizeData.persona));
2035
- }
2036
- if (customizeData.agent?.metadata) {
2037
- const filteredMetadata = filterCustomizationData(customizeData.agent.metadata);
2038
- if (Object.keys(filteredMetadata).length > 0) {
2039
- Object.assign(answers, { metadata: filteredMetadata });
2040
- }
2041
- }
2042
- if (customizeData.critical_actions && customizeData.critical_actions.length > 0) {
2043
- answers.critical_actions = customizeData.critical_actions;
2044
- }
2045
- if (customizeData.memories && customizeData.memories.length > 0) {
2046
- answers.memories = customizeData.memories;
2047
- }
2048
-
2049
- const coreConfigPath = path.join(bmadDir, 'core', 'config.yaml');
2050
- let coreConfig = {};
2051
- if (await fs.pathExists(coreConfigPath)) {
2052
- const yaml = require('yaml');
2053
- const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8');
2054
- coreConfig = yaml.parse(coreConfigContent);
2055
- }
2056
-
2057
- // Compile using the same compiler as initial installation
2058
- const { compileAgent } = require('../../../lib/agent/compiler');
2059
- const result = await compileAgent(yamlContent, answers, agentName, path.relative(bmadDir, targetMdPath), {
2060
- config: coreConfig,
2061
- });
2062
-
2063
- // Check if compilation succeeded
2064
- if (!result || !result.xml) {
2065
- throw new Error(`Failed to compile agent ${agentName}: No XML returned from compiler`);
2066
- }
2067
-
2068
- // Replace _bmad with actual folder name if needed
2069
- const finalXml = result.xml.replaceAll('_bmad', path.basename(bmadDir));
2070
-
2071
- // Write the rebuilt .md file with POSIX-compliant final newline
2072
- const content = finalXml.endsWith('\n') ? finalXml : finalXml + '\n';
2073
- await fs.writeFile(targetMdPath, content, 'utf8');
2074
-
2075
- // Display result with customizations if any
2076
- if (customizedFields.length > 0) {
2077
- console.log(chalk.dim(` Rebuilt agent: ${agentName}.md `) + chalk.yellow(`(customized: ${customizedFields.join(', ')})`));
2078
- } else {
2079
- console.log(chalk.dim(` Rebuilt agent: ${agentName}.md`));
2080
- }
2081
- }
2082
- }
2083
- }
2084
-
2085
- /**
2086
- * Compile/rebuild all agents and tasks for quick updates
2087
- * @param {Object} config - Compilation configuration
2088
- * @returns {Object} Compilation results
2089
- */
2090
- async compileAgents(config) {
2091
- try {
2092
- const projectDir = path.resolve(config.directory);
2093
- const { bmadDir } = await this.findBmadDir(projectDir);
2094
-
2095
- // Check if bmad directory exists
2096
- if (!(await fs.pathExists(bmadDir))) {
2097
- throw new Error(`BMAD not installed at ${bmadDir}`);
2098
- }
2099
-
2100
- // Get installed modules from manifest
2101
- const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml');
2102
- let installedModules = [];
2103
- let manifest = null;
2104
- if (await fs.pathExists(manifestPath)) {
2105
- const manifestContent = await fs.readFile(manifestPath, 'utf8');
2106
- const yaml = require('yaml');
2107
- manifest = yaml.parse(manifestContent);
2108
- installedModules = manifest.modules || [];
2109
- }
2110
-
2111
- // Check for custom modules with missing sources
2112
- if (manifest && manifest.customModules && manifest.customModules.length > 0) {
2113
- console.log(chalk.yellow('\nChecking custom module sources before compilation...'));
2114
-
2115
- const customModuleSources = new Map();
2116
- for (const customModule of manifest.customModules) {
2117
- customModuleSources.set(customModule.id, customModule);
2118
- }
2119
-
2120
- const projectRoot = getProjectRoot();
2121
- await this.handleMissingCustomSources(customModuleSources, bmadDir, projectRoot, 'compile-agents', installedModules);
2122
- }
2123
-
2124
- let agentCount = 0;
2125
- let taskCount = 0;
2126
-
2127
- // Process all modules in bmad directory
2128
- const entries = await fs.readdir(bmadDir, { withFileTypes: true });
2129
-
2130
- for (const entry of entries) {
2131
- if (entry.isDirectory() && entry.name !== '_config' && entry.name !== 'docs') {
2132
- const modulePath = path.join(bmadDir, entry.name);
2133
-
2134
- // Special handling for standalone agents in bmad/agents/ directory
2135
- if (entry.name === 'agents') {
2136
- await this.buildStandaloneAgents(bmadDir, projectDir);
2137
-
2138
- // Count standalone agents
2139
- const standaloneAgentsPath = path.join(bmadDir, 'agents');
2140
- const standaloneAgentDirs = await fs.readdir(standaloneAgentsPath, { withFileTypes: true });
2141
- for (const agentDir of standaloneAgentDirs) {
2142
- if (agentDir.isDirectory()) {
2143
- const agentDirPath = path.join(standaloneAgentsPath, agentDir.name);
2144
- const agentFiles = await fs.readdir(agentDirPath);
2145
- agentCount += agentFiles.filter((f) => f.endsWith('.md') && !f.endsWith('.agent.yaml')).length;
2146
- }
2147
- }
2148
- } else {
2149
- // Rebuild module agents from installer source
2150
- const agentsPath = path.join(modulePath, 'agents');
2151
- if (await fs.pathExists(agentsPath)) {
2152
- await this.rebuildAgentFiles(modulePath, entry.name);
2153
- const agentFiles = await fs.readdir(agentsPath);
2154
- agentCount += agentFiles.filter((f) => f.endsWith('.md')).length;
2155
- }
2156
-
2157
- // Count tasks (already built)
2158
- const tasksPath = path.join(modulePath, 'tasks');
2159
- if (await fs.pathExists(tasksPath)) {
2160
- const taskFiles = await fs.readdir(tasksPath);
2161
- taskCount += taskFiles.filter((f) => f.endsWith('.md')).length;
2162
- }
2163
- }
2164
- }
2165
- }
2166
-
2167
- // Update IDE configurations using the existing IDE list from manifest
2168
- if (manifest && manifest.ides && manifest.ides.length > 0) {
2169
- for (const ide of manifest.ides) {
2170
- await this.ideManager.setup(ide, projectDir, bmadDir, {
2171
- selectedModules: installedModules,
2172
- skipModuleInstall: true, // Skip module installation, just update IDE files
2173
- verbose: config.verbose,
2174
- preCollectedConfig: { _alreadyConfigured: true }, // Skip all interactive prompts during compile
2175
- });
2176
- }
2177
- console.log(chalk.green('✓ IDE configurations updated'));
2178
- } else {
2179
- console.log(chalk.yellow('⚠️ No IDEs configured. Skipping IDE update.'));
2180
- }
2181
- return { agentCount, taskCount };
2182
- } catch (error) {
2183
- throw error;
2184
- }
2185
- }
2186
-
2187
1817
  /**
2188
1818
  * Private: Update core
2189
1819
  */
@@ -2404,6 +2034,108 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
2404
2034
  }
2405
2035
  }
2406
2036
 
2037
+ /**
2038
+ * Compile agents with customizations only
2039
+ * @param {Object} config - Configuration with directory
2040
+ * @returns {Object} Compilation result
2041
+ */
2042
+ async compileAgents(config) {
2043
+ const ora = require('ora');
2044
+ const chalk = require('chalk');
2045
+ const { ModuleManager } = require('../modules/manager');
2046
+ const { getSourcePath } = require('../../../lib/project-root');
2047
+
2048
+ const spinner = ora('Recompiling agents with customizations...').start();
2049
+
2050
+ try {
2051
+ const projectDir = path.resolve(config.directory);
2052
+ const { bmadDir } = await this.findBmadDir(projectDir);
2053
+
2054
+ // Check if bmad directory exists
2055
+ if (!(await fs.pathExists(bmadDir))) {
2056
+ spinner.fail('No BMAD installation found');
2057
+ throw new Error(`BMAD not installed at ${bmadDir}. Use regular install for first-time setup.`);
2058
+ }
2059
+
2060
+ // Detect existing installation
2061
+ const existingInstall = await this.detector.detect(bmadDir);
2062
+ const installedModules = existingInstall.modules.map((m) => m.id);
2063
+
2064
+ // Initialize module manager
2065
+ const moduleManager = new ModuleManager();
2066
+ moduleManager.setBmadFolderName(path.basename(bmadDir));
2067
+
2068
+ let totalAgentCount = 0;
2069
+
2070
+ // Get custom module sources from cache
2071
+ const customModuleSources = new Map();
2072
+ const cacheDir = path.join(bmadDir, '_config', 'custom');
2073
+ if (await fs.pathExists(cacheDir)) {
2074
+ const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true });
2075
+
2076
+ for (const cachedModule of cachedModules) {
2077
+ if (cachedModule.isDirectory()) {
2078
+ const moduleId = cachedModule.name;
2079
+ const cachedPath = path.join(cacheDir, moduleId);
2080
+ const moduleYamlPath = path.join(cachedPath, 'module.yaml');
2081
+
2082
+ // Check if this is actually a custom module
2083
+ if (await fs.pathExists(moduleYamlPath)) {
2084
+ customModuleSources.set(moduleId, cachedPath);
2085
+ }
2086
+ }
2087
+ }
2088
+ }
2089
+
2090
+ // Process each installed module
2091
+ for (const moduleId of installedModules) {
2092
+ spinner.text = `Recompiling agents in ${moduleId}...`;
2093
+
2094
+ // Get source path
2095
+ let sourcePath;
2096
+ if (moduleId === 'core') {
2097
+ sourcePath = getSourcePath('core');
2098
+ } else {
2099
+ // First check if it's in the custom cache
2100
+ if (customModuleSources.has(moduleId)) {
2101
+ sourcePath = customModuleSources.get(moduleId);
2102
+ } else {
2103
+ sourcePath = await moduleManager.findModuleSource(moduleId);
2104
+ }
2105
+ }
2106
+
2107
+ if (!sourcePath) {
2108
+ console.log(chalk.yellow(` Warning: Source not found for module ${moduleId}, skipping...`));
2109
+ continue;
2110
+ }
2111
+
2112
+ const targetPath = path.join(bmadDir, moduleId);
2113
+
2114
+ // Compile agents for this module
2115
+ await moduleManager.compileModuleAgents(sourcePath, targetPath, moduleId, bmadDir, this);
2116
+
2117
+ // Count agents (rough estimate based on files)
2118
+ const agentsPath = path.join(targetPath, 'agents');
2119
+ if (await fs.pathExists(agentsPath)) {
2120
+ const agentFiles = await fs.readdir(agentsPath);
2121
+ const agentCount = agentFiles.filter((f) => f.endsWith('.md')).length;
2122
+ totalAgentCount += agentCount;
2123
+ }
2124
+ }
2125
+
2126
+ spinner.succeed('Agent recompilation complete!');
2127
+
2128
+ return {
2129
+ success: true,
2130
+ agentCount: totalAgentCount,
2131
+ modules: installedModules,
2132
+ };
2133
+ } catch (error) {
2134
+ spinner.fail('Agent recompilation failed');
2135
+ throw error;
2136
+ }
2137
+ }
2138
+
2407
2139
  /**
2408
2140
  * Private: Prompt for update action
2409
2141
  */
@@ -2677,190 +2409,6 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
2677
2409
  return { customFiles, modifiedFiles };
2678
2410
  }
2679
2411
 
2680
- /**
2681
- * Private: Create agent configuration files
2682
- * @param {string} bmadDir - BMAD installation directory
2683
- * @param {Object} userInfo - User information including name and language
2684
- */
2685
- async createAgentConfigs(bmadDir, userInfo = null) {
2686
- const agentConfigDir = path.join(bmadDir, '_config', 'agents');
2687
- await fs.ensureDir(agentConfigDir);
2688
-
2689
- // Get all agents from all modules
2690
- const agents = [];
2691
- const agentDetails = []; // For manifest generation
2692
-
2693
- // Check modules for agents (including core)
2694
- const entries = await fs.readdir(bmadDir, { withFileTypes: true });
2695
- for (const entry of entries) {
2696
- if (entry.isDirectory() && entry.name !== '_config') {
2697
- const moduleAgentsPath = path.join(bmadDir, entry.name, 'agents');
2698
- if (await fs.pathExists(moduleAgentsPath)) {
2699
- const agentFiles = await fs.readdir(moduleAgentsPath);
2700
- for (const agentFile of agentFiles) {
2701
- if (agentFile.endsWith('.md')) {
2702
- const agentPath = path.join(moduleAgentsPath, agentFile);
2703
- const agentContent = await fs.readFile(agentPath, 'utf8');
2704
-
2705
- // Skip agents with localskip="true"
2706
- const hasLocalSkip = agentContent.match(/<agent[^>]*\slocalskip="true"[^>]*>/);
2707
- if (hasLocalSkip) {
2708
- continue; // Skip this agent - it should not have been installed
2709
- }
2710
-
2711
- const agentName = path.basename(agentFile, '.md');
2712
-
2713
- // Extract any nodes with agentConfig="true"
2714
- const agentConfigNodes = this.extractAgentConfigNodes(agentContent);
2715
-
2716
- agents.push({
2717
- name: agentName,
2718
- module: entry.name,
2719
- agentConfigNodes: agentConfigNodes,
2720
- });
2721
-
2722
- // Use shared AgentPartyGenerator to extract details
2723
- let details = AgentPartyGenerator.extractAgentDetails(agentContent, entry.name, agentName);
2724
-
2725
- // Apply config overrides if they exist
2726
- if (details) {
2727
- const configPath = path.join(agentConfigDir, `${entry.name}-${agentName}.md`);
2728
- if (await fs.pathExists(configPath)) {
2729
- const configContent = await fs.readFile(configPath, 'utf8');
2730
- details = AgentPartyGenerator.applyConfigOverrides(details, configContent);
2731
- }
2732
- agentDetails.push(details);
2733
- }
2734
- }
2735
- }
2736
- }
2737
- }
2738
- }
2739
-
2740
- // Create config file for each agent
2741
- let createdCount = 0;
2742
- let skippedCount = 0;
2743
-
2744
- // Load agent config template
2745
- const templatePath = getSourcePath('utility', 'models', 'agent-config-template.md');
2746
- const templateContent = await fs.readFile(templatePath, 'utf8');
2747
-
2748
- for (const agent of agents) {
2749
- const configPath = path.join(agentConfigDir, `${agent.module}-${agent.name}.md`);
2750
-
2751
- // Skip if config file already exists (preserve custom configurations)
2752
- if (await fs.pathExists(configPath)) {
2753
- skippedCount++;
2754
- continue;
2755
- }
2756
-
2757
- // Build config content header
2758
- let configContent = `# Agent Config: ${agent.name}\n\n`;
2759
-
2760
- // Process template and add agent-specific config nodes
2761
- let processedTemplate = templateContent;
2762
-
2763
- // Replace {core:user_name} placeholder with actual user name if available
2764
- if (userInfo && userInfo.userName) {
2765
- processedTemplate = processedTemplate.replaceAll('{core:user_name}', userInfo.userName);
2766
- }
2767
-
2768
- // Replace {core:communication_language} placeholder with actual language if available
2769
- if (userInfo && userInfo.responseLanguage) {
2770
- processedTemplate = processedTemplate.replaceAll('{core:communication_language}', userInfo.responseLanguage);
2771
- }
2772
-
2773
- // If this agent has agentConfig nodes, add them after the existing comment
2774
- if (agent.agentConfigNodes && agent.agentConfigNodes.length > 0) {
2775
- // Find the agent-specific configuration nodes comment
2776
- const commentPattern = /(\s*<!-- Agent-specific configuration nodes -->)/;
2777
- const commentMatch = processedTemplate.match(commentPattern);
2778
-
2779
- if (commentMatch) {
2780
- // Add nodes right after the comment
2781
- let agentSpecificNodes = '';
2782
- for (const node of agent.agentConfigNodes) {
2783
- agentSpecificNodes += `\n ${node}`;
2784
- }
2785
-
2786
- processedTemplate = processedTemplate.replace(commentPattern, `$1${agentSpecificNodes}`);
2787
- }
2788
- }
2789
-
2790
- configContent += processedTemplate;
2791
-
2792
- // Ensure POSIX-compliant final newline
2793
- if (!configContent.endsWith('\n')) {
2794
- configContent += '\n';
2795
- }
2796
-
2797
- await fs.writeFile(configPath, configContent, 'utf8');
2798
- this.installedFiles.add(configPath); // Track agent config files
2799
- createdCount++;
2800
- }
2801
-
2802
- // Generate agent manifest with overrides applied
2803
- await this.generateAgentManifest(bmadDir, agentDetails);
2804
-
2805
- return { total: agents.length, created: createdCount, skipped: skippedCount };
2806
- }
2807
-
2808
- /**
2809
- * Generate agent manifest XML file
2810
- * @param {string} bmadDir - BMAD installation directory
2811
- * @param {Array} agentDetails - Array of agent details
2812
- */
2813
- async generateAgentManifest(bmadDir, agentDetails) {
2814
- const manifestPath = path.join(bmadDir, '_config', 'agent-manifest.csv');
2815
- await AgentPartyGenerator.writeAgentParty(manifestPath, agentDetails, { forWeb: false });
2816
- }
2817
-
2818
- /**
2819
- * Extract nodes with agentConfig="true" from agent content
2820
- * @param {string} content - Agent file content
2821
- * @returns {Array} Array of XML nodes that should be added to agent config
2822
- */
2823
- extractAgentConfigNodes(content) {
2824
- const nodes = [];
2825
-
2826
- try {
2827
- // Find all XML nodes with agentConfig="true"
2828
- // Match self-closing tags and tags with content
2829
- const selfClosingPattern = /<([a-zA-Z][a-zA-Z0-9_-]*)\s+[^>]*agentConfig="true"[^>]*\/>/g;
2830
- const withContentPattern = /<([a-zA-Z][a-zA-Z0-9_-]*)\s+[^>]*agentConfig="true"[^>]*>([\s\S]*?)<\/\1>/g;
2831
-
2832
- // Extract self-closing tags
2833
- let match;
2834
- while ((match = selfClosingPattern.exec(content)) !== null) {
2835
- // Extract just the tag without children (structure only)
2836
- const tagMatch = match[0].match(/<([a-zA-Z][a-zA-Z0-9_-]*)([^>]*)\/>/);
2837
- if (tagMatch) {
2838
- const tagName = tagMatch[1];
2839
- const attributes = tagMatch[2].replace(/\s*agentConfig="true"/, ''); // Remove agentConfig attribute
2840
- nodes.push(`<${tagName}${attributes}></${tagName}>`);
2841
- }
2842
- }
2843
-
2844
- // Extract tags with content
2845
- while ((match = withContentPattern.exec(content)) !== null) {
2846
- const fullMatch = match[0];
2847
- const tagName = match[1];
2848
-
2849
- // Extract opening tag with attributes (removing agentConfig="true")
2850
- const openingTagMatch = fullMatch.match(new RegExp(`<${tagName}([^>]*)>`));
2851
- if (openingTagMatch) {
2852
- const attributes = openingTagMatch[1].replace(/\s*agentConfig="true"/, '');
2853
- // Add empty node structure (no children)
2854
- nodes.push(`<${tagName}${attributes}></${tagName}>`);
2855
- }
2856
- }
2857
- } catch (error) {
2858
- console.error('Error extracting agentConfig nodes:', error);
2859
- }
2860
-
2861
- return nodes;
2862
- }
2863
-
2864
2412
  /**
2865
2413
  * Handle missing custom module sources interactively
2866
2414
  * @param {Map} customModuleSources - Map of custom module ID to info
@@ -2999,7 +2547,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
2999
2547
  await this.manifest.addCustomModule(bmadDir, missing.info);
3000
2548
 
3001
2549
  validCustomModules.push({
3002
- id: moduleId,
2550
+ id: missing.id,
3003
2551
  name: missing.name,
3004
2552
  path: resolvedPath,
3005
2553
  info: missing.info,
@@ -3013,7 +2561,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
3013
2561
  case 'remove': {
3014
2562
  // Extra confirmation for destructive remove
3015
2563
  console.log(chalk.red.bold(`\n⚠️ WARNING: This will PERMANENTLY DELETE "${missing.name}" and all its files!`));
3016
- console.log(chalk.red(` Module location: ${path.join(bmadDir, moduleId)}`));
2564
+ console.log(chalk.red(` Module location: ${path.join(bmadDir, missing.id)}`));
3017
2565
 
3018
2566
  const { confirm } = await inquirer.prompt([
3019
2567
  {