bmad-method 6.0.0-Beta.1 → 6.0.0-Beta.3

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 (162) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/README.md +41 -9
  3. package/docs/how-to/customize-bmad.md +1 -1
  4. package/docs/reference/workflow-map.md +3 -0
  5. package/package.json +1 -1
  6. package/src/bmm/agents/quinn.agent.yaml +57 -0
  7. package/src/bmm/module-help.csv +31 -31
  8. package/src/bmm/teams/default-party.csv +0 -1
  9. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +1 -1
  10. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01b-legacy-conversion.md +1 -1
  11. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +1 -1
  12. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-03-edit.md +1 -1
  13. package/src/bmm/workflows/4-implementation/create-story/instructions.xml +1 -1
  14. package/src/bmm/workflows/4-implementation/dev-story/instructions.xml +1 -1
  15. package/src/bmm/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +1 -1
  16. package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +1 -0
  17. package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-01-understand.md +1 -1
  18. package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +1 -1
  19. package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +1 -1
  20. package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +1 -1
  21. package/src/bmm/workflows/qa/automate/checklist.md +33 -0
  22. package/src/bmm/workflows/qa/automate/instructions.md +110 -0
  23. package/src/bmm/workflows/qa/automate/workflow.yaml +49 -0
  24. package/src/core/module-help.csv +8 -8
  25. package/test/test-installation-components.js +9 -11
  26. package/tools/cli/external-official-modules.yaml +10 -0
  27. package/tools/cli/installers/lib/core/installer.js +26 -40
  28. package/tools/cli/installers/lib/ide/_config-driven.js +450 -0
  29. package/tools/cli/installers/lib/ide/codex.js +40 -12
  30. package/tools/cli/installers/lib/ide/manager.js +65 -38
  31. package/tools/cli/installers/lib/ide/platform-codes.js +100 -0
  32. package/tools/cli/installers/lib/ide/platform-codes.yaml +227 -0
  33. package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +21 -5
  34. package/tools/cli/installers/lib/ide/shared/bmad-artifacts.js +5 -0
  35. package/tools/cli/installers/lib/ide/shared/path-utils.js +177 -50
  36. package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +7 -5
  37. package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +29 -3
  38. package/tools/cli/installers/lib/ide/templates/combined/antigravity.md +8 -0
  39. package/tools/cli/installers/lib/ide/templates/combined/default-agent.md +15 -0
  40. package/tools/cli/installers/lib/ide/templates/combined/default-workflow-yaml.md +14 -0
  41. package/tools/cli/installers/lib/ide/templates/combined/default-workflow.md +6 -0
  42. package/tools/cli/installers/lib/ide/templates/combined/gemini-agent.toml +14 -0
  43. package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml +16 -0
  44. package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml +14 -0
  45. package/tools/cli/installers/lib/ide/templates/combined/rovodev.md +9 -0
  46. package/tools/cli/installers/lib/ide/templates/combined/trae.md +9 -0
  47. package/tools/cli/installers/lib/ide/templates/combined/windsurf-workflow.md +10 -0
  48. package/tools/cli/installers/lib/ide/templates/split/opencode/body.md +10 -0
  49. package/tools/cli/installers/lib/ide/templates/split/opencode/header.md +4 -0
  50. package/tools/cli/lib/ui.js +19 -75
  51. package/docs/tea/explanation/engagement-models.md +0 -710
  52. package/docs/tea/explanation/fixture-architecture.md +0 -457
  53. package/docs/tea/explanation/knowledge-base-system.md +0 -554
  54. package/docs/tea/explanation/network-first-patterns.md +0 -853
  55. package/docs/tea/explanation/risk-based-testing.md +0 -586
  56. package/docs/tea/explanation/tea-overview.md +0 -410
  57. package/docs/tea/explanation/test-quality-standards.md +0 -907
  58. package/docs/tea/explanation/testing-as-engineering.md +0 -112
  59. package/docs/tea/glossary/index.md +0 -159
  60. package/docs/tea/how-to/brownfield/use-tea-for-enterprise.md +0 -525
  61. package/docs/tea/how-to/brownfield/use-tea-with-existing-tests.md +0 -577
  62. package/docs/tea/how-to/customization/enable-tea-mcp-enhancements.md +0 -424
  63. package/docs/tea/how-to/customization/integrate-playwright-utils.md +0 -813
  64. package/docs/tea/how-to/workflows/run-atdd.md +0 -436
  65. package/docs/tea/how-to/workflows/run-automate.md +0 -653
  66. package/docs/tea/how-to/workflows/run-nfr-assess.md +0 -679
  67. package/docs/tea/how-to/workflows/run-test-design.md +0 -135
  68. package/docs/tea/how-to/workflows/run-test-review.md +0 -605
  69. package/docs/tea/how-to/workflows/run-trace.md +0 -883
  70. package/docs/tea/how-to/workflows/setup-ci.md +0 -712
  71. package/docs/tea/how-to/workflows/setup-test-framework.md +0 -98
  72. package/docs/tea/reference/commands.md +0 -276
  73. package/docs/tea/reference/configuration.md +0 -678
  74. package/docs/tea/reference/knowledge-base.md +0 -340
  75. package/docs/tea/tutorials/tea-lite-quickstart.md +0 -444
  76. package/src/bmm/agents/tea.agent.yaml +0 -63
  77. package/src/bmm/testarch/knowledge/adr-quality-readiness-checklist.md +0 -350
  78. package/src/bmm/testarch/knowledge/api-request.md +0 -442
  79. package/src/bmm/testarch/knowledge/api-testing-patterns.md +0 -843
  80. package/src/bmm/testarch/knowledge/auth-session.md +0 -552
  81. package/src/bmm/testarch/knowledge/burn-in.md +0 -273
  82. package/src/bmm/testarch/knowledge/ci-burn-in.md +0 -675
  83. package/src/bmm/testarch/knowledge/component-tdd.md +0 -486
  84. package/src/bmm/testarch/knowledge/contract-testing.md +0 -957
  85. package/src/bmm/testarch/knowledge/data-factories.md +0 -500
  86. package/src/bmm/testarch/knowledge/email-auth.md +0 -721
  87. package/src/bmm/testarch/knowledge/error-handling.md +0 -725
  88. package/src/bmm/testarch/knowledge/feature-flags.md +0 -750
  89. package/src/bmm/testarch/knowledge/file-utils.md +0 -463
  90. package/src/bmm/testarch/knowledge/fixture-architecture.md +0 -401
  91. package/src/bmm/testarch/knowledge/fixtures-composition.md +0 -382
  92. package/src/bmm/testarch/knowledge/intercept-network-call.md +0 -430
  93. package/src/bmm/testarch/knowledge/log.md +0 -429
  94. package/src/bmm/testarch/knowledge/network-error-monitor.md +0 -405
  95. package/src/bmm/testarch/knowledge/network-first.md +0 -486
  96. package/src/bmm/testarch/knowledge/network-recorder.md +0 -527
  97. package/src/bmm/testarch/knowledge/nfr-criteria.md +0 -670
  98. package/src/bmm/testarch/knowledge/overview.md +0 -286
  99. package/src/bmm/testarch/knowledge/playwright-config.md +0 -730
  100. package/src/bmm/testarch/knowledge/probability-impact.md +0 -601
  101. package/src/bmm/testarch/knowledge/recurse.md +0 -421
  102. package/src/bmm/testarch/knowledge/risk-governance.md +0 -615
  103. package/src/bmm/testarch/knowledge/selective-testing.md +0 -732
  104. package/src/bmm/testarch/knowledge/selector-resilience.md +0 -527
  105. package/src/bmm/testarch/knowledge/test-healing-patterns.md +0 -644
  106. package/src/bmm/testarch/knowledge/test-levels-framework.md +0 -473
  107. package/src/bmm/testarch/knowledge/test-priorities-matrix.md +0 -373
  108. package/src/bmm/testarch/knowledge/test-quality.md +0 -664
  109. package/src/bmm/testarch/knowledge/timing-debugging.md +0 -372
  110. package/src/bmm/testarch/knowledge/visual-debugging.md +0 -524
  111. package/src/bmm/testarch/tea-index.csv +0 -35
  112. package/src/bmm/workflows/testarch/atdd/atdd-checklist-template.md +0 -363
  113. package/src/bmm/workflows/testarch/atdd/checklist.md +0 -374
  114. package/src/bmm/workflows/testarch/atdd/instructions.md +0 -806
  115. package/src/bmm/workflows/testarch/atdd/workflow.yaml +0 -47
  116. package/src/bmm/workflows/testarch/automate/checklist.md +0 -582
  117. package/src/bmm/workflows/testarch/automate/instructions.md +0 -1324
  118. package/src/bmm/workflows/testarch/automate/workflow.yaml +0 -54
  119. package/src/bmm/workflows/testarch/ci/checklist.md +0 -247
  120. package/src/bmm/workflows/testarch/ci/github-actions-template.yaml +0 -198
  121. package/src/bmm/workflows/testarch/ci/gitlab-ci-template.yaml +0 -149
  122. package/src/bmm/workflows/testarch/ci/instructions.md +0 -536
  123. package/src/bmm/workflows/testarch/ci/workflow.yaml +0 -47
  124. package/src/bmm/workflows/testarch/framework/checklist.md +0 -320
  125. package/src/bmm/workflows/testarch/framework/instructions.md +0 -481
  126. package/src/bmm/workflows/testarch/framework/workflow.yaml +0 -49
  127. package/src/bmm/workflows/testarch/nfr-assess/checklist.md +0 -407
  128. package/src/bmm/workflows/testarch/nfr-assess/instructions.md +0 -726
  129. package/src/bmm/workflows/testarch/nfr-assess/nfr-report-template.md +0 -461
  130. package/src/bmm/workflows/testarch/nfr-assess/workflow.yaml +0 -49
  131. package/src/bmm/workflows/testarch/test-design/checklist.md +0 -407
  132. package/src/bmm/workflows/testarch/test-design/instructions.md +0 -1158
  133. package/src/bmm/workflows/testarch/test-design/test-design-architecture-template.md +0 -213
  134. package/src/bmm/workflows/testarch/test-design/test-design-qa-template.md +0 -286
  135. package/src/bmm/workflows/testarch/test-design/test-design-template.md +0 -294
  136. package/src/bmm/workflows/testarch/test-design/workflow.yaml +0 -71
  137. package/src/bmm/workflows/testarch/test-review/checklist.md +0 -472
  138. package/src/bmm/workflows/testarch/test-review/instructions.md +0 -628
  139. package/src/bmm/workflows/testarch/test-review/test-review-template.md +0 -390
  140. package/src/bmm/workflows/testarch/test-review/workflow.yaml +0 -48
  141. package/src/bmm/workflows/testarch/trace/checklist.md +0 -642
  142. package/src/bmm/workflows/testarch/trace/instructions.md +0 -1030
  143. package/src/bmm/workflows/testarch/trace/trace-template.md +0 -675
  144. package/src/bmm/workflows/testarch/trace/workflow.yaml +0 -57
  145. package/tools/cli/installers/lib/ide/STANDARDIZATION_PLAN.md +0 -208
  146. package/tools/cli/installers/lib/ide/antigravity.js +0 -474
  147. package/tools/cli/installers/lib/ide/auggie.js +0 -244
  148. package/tools/cli/installers/lib/ide/claude-code.js +0 -506
  149. package/tools/cli/installers/lib/ide/cline.js +0 -272
  150. package/tools/cli/installers/lib/ide/crush.js +0 -149
  151. package/tools/cli/installers/lib/ide/cursor.js +0 -160
  152. package/tools/cli/installers/lib/ide/gemini.js +0 -301
  153. package/tools/cli/installers/lib/ide/github-copilot.js +0 -383
  154. package/tools/cli/installers/lib/ide/iflow.js +0 -191
  155. package/tools/cli/installers/lib/ide/opencode.js +0 -257
  156. package/tools/cli/installers/lib/ide/qwen.js +0 -372
  157. package/tools/cli/installers/lib/ide/roo.js +0 -273
  158. package/tools/cli/installers/lib/ide/rovo-dev.js +0 -290
  159. package/tools/cli/installers/lib/ide/templates/gemini-agent-command.toml +0 -14
  160. package/tools/cli/installers/lib/ide/templates/gemini-task-command.toml +0 -12
  161. package/tools/cli/installers/lib/ide/trae.js +0 -313
  162. package/tools/cli/installers/lib/ide/windsurf.js +0 -258
@@ -0,0 +1,49 @@
1
+ # Quinn QA workflow: Automate
2
+ name: qa-automate
3
+ description: "Generate tests quickly for existing features using standard test patterns"
4
+ author: "BMad"
5
+
6
+ # Critical variables from config
7
+ config_source: "{project-root}/_bmad/bmm/config.yaml"
8
+ output_folder: "{config_source}:output_folder"
9
+ implementation_artifacts: "{config_source}:implementation_artifacts"
10
+ user_name: "{config_source}:user_name"
11
+ communication_language: "{config_source}:communication_language"
12
+ document_output_language: "{config_source}:document_output_language"
13
+ date: system-generated
14
+
15
+ # Workflow components
16
+ installed_path: "{project-root}/_bmad/bmm/workflows/qa/automate"
17
+ instructions: "{installed_path}/instructions.md"
18
+ validation: "{installed_path}/checklist.md"
19
+ template: false
20
+
21
+ # Variables and inputs
22
+ variables:
23
+ # Directory paths
24
+ test_dir: "{project-root}/tests" # Root test directory
25
+ source_dir: "{project-root}" # Source code directory
26
+
27
+ # Output configuration
28
+ default_output_file: "{implementation_artifacts}/tests/test-summary.md"
29
+
30
+ # Required tools
31
+ required_tools:
32
+ - read_file # Read source code and existing tests
33
+ - write_file # Create test files
34
+ - create_directory # Create test directories
35
+ - list_files # Discover features
36
+ - search_repo # Find patterns
37
+ - glob # Find files
38
+
39
+ tags:
40
+ - qa
41
+ - automation
42
+ - testing
43
+
44
+ execution_hints:
45
+ interactive: false
46
+ autonomous: true
47
+ iterative: false
48
+
49
+ web_bundle: false
@@ -1,9 +1,9 @@
1
1
  module,phase,name,code,sequence,workflow-file,command,required,agent,options,description,output-location,outputs
2
- core,,Brainstorming,BS,20,_bmad/core/workflows/brainstorming/workflow.md,bmad_brainstorming,false,analyst,,Facilitate interactive brainstorming sessions using diverse creative techniques and ideation methods,{output_folder}/brainstorming/brainstorming-session-{{date}}.md,,
3
- core,,Party Mode,PM,30,_bmad/core/workflows/party-mode/workflow.md,bmad_party-mode,false,party-mode facilitator,,Orchestrates group discussions between all installed BMAD agents enabling natural multi-agent conversations,,
4
- core,,bmad-help,BH,40,_bmad/core/tasks/help.md,bmad_help,false,system,,Get unstuck by showing what workflow steps come next or answering questions about what to do in the BMad Method,,
5
- core,,Index Docs,ID,50,_bmad/core/tasks/index-docs.xml,bmad_index-docs,false,llm,,Generates or updates an index.md of all documents in the specified directory,,
6
- core,,Shard Document,SD,70,_bmad/core/tasks/shard-doc.xml,bmad_shard-doc,false,llm,,Splits large markdown documents into smaller organized files based on level 2 sections,,
7
- core,,Editorial Review - Prose,EP,80,_bmad/core/tasks/editorial-review-prose.xml,bmad_editorial-review-prose,false,llm,reader_type,Clinical copy-editor that reviews text for communication issues,,"three-column markdown table with suggested fixes",
8
- core,,Editorial Review - Structure,ES,90,_bmad/core/tasks/editorial-review-structure.xml,bmad_editorial-review-structure,false,llm,,Structural editor that proposes cuts reorganization and simplification while preserving comprehension,,
9
- core,,Adversarial Review (General),AR,100,_bmad/core/tasks/review-adversarial-general.xml,bmad_review-adversarial-general,false,llm,,Cynically review content and produce findings,,
2
+ core,,Brainstorming,BS,20,_bmad/core/workflows/brainstorming/workflow.md,bmad-brainstorming,false,analyst,,Facilitate interactive brainstorming sessions using diverse creative techniques and ideation methods,{output_folder}/brainstorming/brainstorming-session-{{date}}.md,,
3
+ core,,Party Mode,PM,30,_bmad/core/workflows/party-mode/workflow.md,bmad-party-mode,false,party-mode facilitator,,Orchestrates group discussions between all installed BMAD agents enabling natural multi-agent conversations,,
4
+ core,,bmad-help,BH,40,_bmad/core/tasks/help.md,bmad-help,false,,,Get unstuck by showing what workflow steps come next or answering questions about what to do in the BMad Method,,
5
+ core,,Index Docs,ID,50,_bmad/core/tasks/index-docs.xml,bmad-index-docs,false,,,Generates or updates an index.md of all documents in the specified directory,,
6
+ core,,Shard Document,SD,70,_bmad/core/tasks/shard-doc.xml,bmad-shard-doc,false,,,Splits large markdown documents into smaller organized files based on level 2 sections,,
7
+ core,,Editorial Review - Prose,EP,80,_bmad/core/tasks/editorial-review-prose.xml,bmad-editorial-review-prose,false,,,Clinical copy-editor that reviews text for communication issues,,"three-column markdown table with suggested fixes",
8
+ core,,Editorial Review - Structure,ES,90,_bmad/core/tasks/editorial-review-structure.xml,bmad-editorial-review-structure,false,,,Structural editor that proposes cuts reorganization and simplification while preserving comprehension,,
9
+ core,,Adversarial Review (General),AR,100,_bmad/core/tasks/review-adversarial-general.xml,bmad-review-adversarial-general,false,,,Cynically review content and produce findings,,
@@ -158,32 +158,30 @@ async function runTests() {
158
158
  console.log('');
159
159
 
160
160
  // ============================================================
161
- // Test 5: TEA Agent Special Handling
161
+ // Test 5: QA Agent Compilation
162
162
  // ============================================================
163
- console.log(`${colors.yellow}Test Suite 5: TEA Agent Compilation${colors.reset}\n`);
163
+ console.log(`${colors.yellow}Test Suite 5: QA Agent Compilation${colors.reset}\n`);
164
164
 
165
165
  try {
166
166
  const builder = new YamlXmlBuilder();
167
- const teaAgentPath = path.join(projectRoot, 'src/bmm/agents/tea.agent.yaml');
168
- const tempOutput = path.join(__dirname, 'temp-tea-agent.md');
167
+ const qaAgentPath = path.join(projectRoot, 'src/bmm/agents/quinn.agent.yaml');
168
+ const tempOutput = path.join(__dirname, 'temp-qa-agent.md');
169
169
 
170
170
  try {
171
- const result = await builder.buildAgent(teaAgentPath, null, tempOutput, { includeMetadata: true });
171
+ const result = await builder.buildAgent(qaAgentPath, null, tempOutput, { includeMetadata: true });
172
172
  const compiled = await fs.readFile(tempOutput, 'utf8');
173
173
 
174
- assert(compiled.includes('tea-index.csv'), 'TEA agent compilation includes critical_actions with tea-index.csv reference');
174
+ assert(compiled.includes('QA Engineer'), 'QA agent compilation includes agent title');
175
175
 
176
- assert(compiled.includes('testarch/knowledge'), 'TEA agent compilation includes knowledge base path');
177
-
178
- assert(compiled.includes('test-design'), 'TEA agent menu includes test-design workflow');
176
+ assert(compiled.includes('qa/automate'), 'QA agent menu includes automate workflow');
179
177
 
180
178
  // Cleanup
181
179
  await fs.remove(tempOutput);
182
180
  } catch (error) {
183
- assert(false, 'TEA agent compiles successfully', error.message);
181
+ assert(false, 'QA agent compiles successfully', error.message);
184
182
  }
185
183
  } catch (error) {
186
- assert(false, 'TEA compilation test setup', error.message);
184
+ assert(false, 'QA compilation test setup', error.message);
187
185
  }
188
186
 
189
187
  console.log('');
@@ -32,6 +32,16 @@ modules:
32
32
  type: bmad-org
33
33
  npmPackage: bmad-game-dev-studio
34
34
 
35
+ bmad-method-test-architecture-enterprise:
36
+ url: https://github.com/bmad-code-org/bmad-method-test-architecture-enterprise
37
+ module-definition: src/module.yaml
38
+ code: tea
39
+ name: "Test Architect"
40
+ description: "Master Test Architect for quality strategy, test automation, and release gates"
41
+ defaultSelected: false
42
+ type: bmad-org
43
+ npmPackage: bmad-method-test-architecture-enterprise
44
+
35
45
  # TODO: Enable once fixes applied:
36
46
 
37
47
  # whiteport-design-system:
@@ -161,56 +161,39 @@ class Installer {
161
161
  }
162
162
 
163
163
  if (!toolConfig.skipIde && toolConfig.ides && toolConfig.ides.length > 0) {
164
+ // Ensure IDE manager is initialized
165
+ await this.ideManager.ensureInitialized();
166
+
164
167
  // Determine which IDEs are newly selected (not previously configured)
165
168
  const newlySelectedIdes = toolConfig.ides.filter((ide) => !previouslyConfiguredIdes.includes(ide));
166
169
 
167
170
  if (newlySelectedIdes.length > 0) {
168
171
  console.log('\n'); // Add spacing before IDE questions
169
172
 
173
+ // Collect configuration for IDEs that support it
170
174
  for (const ide of newlySelectedIdes) {
171
- // List of IDEs that have interactive prompts
172
- //TODO: Why is this here, hardcoding this list here is bad, fix me!
173
- const needsPrompts = ['claude-code', 'github-copilot', 'roo', 'cline', 'auggie', 'codex', 'qwen', 'gemini', 'rovo-dev'].includes(
174
- ide,
175
- );
176
-
177
- if (needsPrompts) {
178
- // Get IDE handler and collect configuration
179
- try {
180
- // Dynamically load the IDE setup module
181
- const ideModule = require(`../ide/${ide}`);
182
-
183
- // Get the setup class (handle different export formats)
184
- let SetupClass;
185
- const className =
186
- ide
187
- .split('-')
188
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
189
- .join('') + 'Setup';
190
-
191
- if (ideModule[className]) {
192
- SetupClass = ideModule[className];
193
- } else if (ideModule.default) {
194
- SetupClass = ideModule.default;
195
- } else {
196
- continue;
197
- }
175
+ try {
176
+ const handler = this.ideManager.handlers.get(ide);
198
177
 
199
- const ideSetup = new SetupClass();
178
+ if (!handler) {
179
+ console.warn(chalk.yellow(`Warning: IDE '${ide}' handler not found`));
180
+ continue;
181
+ }
200
182
 
201
- // Check if this IDE has a collectConfiguration method
202
- if (typeof ideSetup.collectConfiguration === 'function') {
203
- console.log(chalk.cyan(`\nConfiguring ${ide}...`));
204
- ideConfigurations[ide] = await ideSetup.collectConfiguration({
205
- selectedModules: selectedModules || [],
206
- projectDir,
207
- bmadDir,
208
- });
209
- }
210
- } catch {
211
- // IDE doesn't have a setup file or collectConfiguration method
212
- console.warn(chalk.yellow(`Warning: Could not load configuration for ${ide}`));
183
+ // Check if this IDE handler has a collectConfiguration method
184
+ // (custom installers like Codex, Kilo, Kiro-cli may have this)
185
+ if (typeof handler.collectConfiguration === 'function') {
186
+ console.log(chalk.cyan(`\nConfiguring ${ide}...`));
187
+ ideConfigurations[ide] = await handler.collectConfiguration({
188
+ selectedModules: selectedModules || [],
189
+ projectDir,
190
+ bmadDir,
191
+ });
213
192
  }
193
+ // Most config-driven IDEs don't need configuration - silently skip
194
+ } catch (error) {
195
+ // IDE doesn't support configuration or has an error
196
+ console.warn(chalk.yellow(`Warning: Could not load configuration for ${ide}: ${error.message}`));
214
197
  }
215
198
  }
216
199
  }
@@ -1016,6 +999,9 @@ class Installer {
1016
999
 
1017
1000
  // Configure IDEs and copy documentation
1018
1001
  if (!config.skipIde && config.ides && config.ides.length > 0) {
1002
+ // Ensure IDE manager is initialized (handlers may not be loaded in quick update flow)
1003
+ await this.ideManager.ensureInitialized();
1004
+
1019
1005
  // Filter out any undefined/null values from the IDE list
1020
1006
  const validIdes = config.ides.filter((ide) => ide && typeof ide === 'string');
1021
1007
 
@@ -0,0 +1,450 @@
1
+ const path = require('node:path');
2
+ const fs = require('fs-extra');
3
+ const chalk = require('chalk');
4
+ const { BaseIdeSetup } = require('./_base-ide');
5
+ const { AgentCommandGenerator } = require('./shared/agent-command-generator');
6
+ const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
7
+ const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator');
8
+
9
+ /**
10
+ * Config-driven IDE setup handler
11
+ *
12
+ * This class provides a standardized way to install BMAD artifacts to IDEs
13
+ * based on configuration in platform-codes.yaml. It eliminates the need for
14
+ * individual installer files for each IDE.
15
+ *
16
+ * Features:
17
+ * - Config-driven from platform-codes.yaml
18
+ * - Template-based content generation
19
+ * - Multi-target installation support (e.g., GitHub Copilot)
20
+ * - Artifact type filtering (agents, workflows, tasks, tools)
21
+ */
22
+ class ConfigDrivenIdeSetup extends BaseIdeSetup {
23
+ constructor(platformCode, platformConfig) {
24
+ super(platformCode, platformConfig.name, platformConfig.preferred);
25
+ this.platformConfig = platformConfig;
26
+ this.installerConfig = platformConfig.installer || null;
27
+ }
28
+
29
+ /**
30
+ * Main setup method - called by IdeManager
31
+ * @param {string} projectDir - Project directory
32
+ * @param {string} bmadDir - BMAD installation directory
33
+ * @param {Object} options - Setup options
34
+ * @returns {Promise<Object>} Setup result
35
+ */
36
+ async setup(projectDir, bmadDir, options = {}) {
37
+ console.log(chalk.cyan(`Setting up ${this.name}...`));
38
+
39
+ // Clean up any old BMAD installation first
40
+ await this.cleanup(projectDir);
41
+
42
+ if (!this.installerConfig) {
43
+ return { success: false, reason: 'no-config' };
44
+ }
45
+
46
+ // Handle multi-target installations (e.g., GitHub Copilot)
47
+ if (this.installerConfig.targets) {
48
+ return this.installToMultipleTargets(projectDir, bmadDir, this.installerConfig.targets, options);
49
+ }
50
+
51
+ // Handle single-target installations
52
+ if (this.installerConfig.target_dir) {
53
+ return this.installToTarget(projectDir, bmadDir, this.installerConfig, options);
54
+ }
55
+
56
+ return { success: false, reason: 'invalid-config' };
57
+ }
58
+
59
+ /**
60
+ * Install to a single target directory
61
+ * @param {string} projectDir - Project directory
62
+ * @param {string} bmadDir - BMAD installation directory
63
+ * @param {Object} config - Installation configuration
64
+ * @param {Object} options - Setup options
65
+ * @returns {Promise<Object>} Installation result
66
+ */
67
+ async installToTarget(projectDir, bmadDir, config, options) {
68
+ const { target_dir, template_type, artifact_types } = config;
69
+ const targetPath = path.join(projectDir, target_dir);
70
+ await this.ensureDir(targetPath);
71
+
72
+ const selectedModules = options.selectedModules || [];
73
+ const results = { agents: 0, workflows: 0, tasks: 0, tools: 0 };
74
+
75
+ // Install agents
76
+ if (!artifact_types || artifact_types.includes('agents')) {
77
+ const agentGen = new AgentCommandGenerator(this.bmadFolderName);
78
+ const { artifacts } = await agentGen.collectAgentArtifacts(bmadDir, selectedModules);
79
+ results.agents = await this.writeAgentArtifacts(targetPath, artifacts, template_type, config);
80
+ }
81
+
82
+ // Install workflows
83
+ if (!artifact_types || artifact_types.includes('workflows')) {
84
+ const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
85
+ const { artifacts } = await workflowGen.collectWorkflowArtifacts(bmadDir);
86
+ results.workflows = await this.writeWorkflowArtifacts(targetPath, artifacts, template_type, config);
87
+ }
88
+
89
+ // Install tasks and tools
90
+ if (!artifact_types || artifact_types.includes('tasks') || artifact_types.includes('tools')) {
91
+ const taskToolGen = new TaskToolCommandGenerator();
92
+ const taskToolResult = await taskToolGen.generateDashTaskToolCommands(projectDir, bmadDir, targetPath);
93
+ results.tasks = taskToolResult.tasks || 0;
94
+ results.tools = taskToolResult.tools || 0;
95
+ }
96
+
97
+ this.printSummary(results, target_dir);
98
+ return { success: true, results };
99
+ }
100
+
101
+ /**
102
+ * Install to multiple target directories
103
+ * @param {string} projectDir - Project directory
104
+ * @param {string} bmadDir - BMAD installation directory
105
+ * @param {Array} targets - Array of target configurations
106
+ * @param {Object} options - Setup options
107
+ * @returns {Promise<Object>} Installation result
108
+ */
109
+ async installToMultipleTargets(projectDir, bmadDir, targets, options) {
110
+ const allResults = { agents: 0, workflows: 0, tasks: 0, tools: 0 };
111
+
112
+ for (const target of targets) {
113
+ const result = await this.installToTarget(projectDir, bmadDir, target, options);
114
+ if (result.success) {
115
+ allResults.agents += result.results.agents || 0;
116
+ allResults.workflows += result.results.workflows || 0;
117
+ allResults.tasks += result.results.tasks || 0;
118
+ allResults.tools += result.results.tools || 0;
119
+ }
120
+ }
121
+
122
+ return { success: true, results: allResults };
123
+ }
124
+
125
+ /**
126
+ * Write agent artifacts to target directory
127
+ * @param {string} targetPath - Target directory path
128
+ * @param {Array} artifacts - Agent artifacts
129
+ * @param {string} templateType - Template type to use
130
+ * @param {Object} config - Installation configuration
131
+ * @returns {Promise<number>} Count of artifacts written
132
+ */
133
+ async writeAgentArtifacts(targetPath, artifacts, templateType, config = {}) {
134
+ // Try to load platform-specific template, fall back to default-agent
135
+ const { content: template, extension } = await this.loadTemplate(templateType, 'agent', config, 'default-agent');
136
+ let count = 0;
137
+
138
+ for (const artifact of artifacts) {
139
+ const content = this.renderTemplate(template, artifact);
140
+ const filename = this.generateFilename(artifact, 'agent', extension);
141
+ const filePath = path.join(targetPath, filename);
142
+ await this.writeFile(filePath, content);
143
+ count++;
144
+ }
145
+
146
+ return count;
147
+ }
148
+
149
+ /**
150
+ * Write workflow artifacts to target directory
151
+ * @param {string} targetPath - Target directory path
152
+ * @param {Array} artifacts - Workflow artifacts
153
+ * @param {string} templateType - Template type to use
154
+ * @param {Object} config - Installation configuration
155
+ * @returns {Promise<number>} Count of artifacts written
156
+ */
157
+ async writeWorkflowArtifacts(targetPath, artifacts, templateType, config = {}) {
158
+ let count = 0;
159
+
160
+ for (const artifact of artifacts) {
161
+ if (artifact.type === 'workflow-command') {
162
+ // Use different template based on workflow type (YAML vs MD)
163
+ // Default to 'default' template type, but allow override via config
164
+ const workflowTemplateType = artifact.isYamlWorkflow
165
+ ? config.yaml_workflow_template || `${templateType}-workflow-yaml`
166
+ : config.md_workflow_template || `${templateType}-workflow`;
167
+
168
+ // Fall back to default templates if specific ones don't exist
169
+ const finalTemplateType = artifact.isYamlWorkflow ? 'default-workflow-yaml' : 'default-workflow';
170
+ // workflowTemplateType already contains full name (e.g., 'gemini-workflow-yaml'), so pass empty artifactType
171
+ const { content: template, extension } = await this.loadTemplate(workflowTemplateType, '', config, finalTemplateType);
172
+ const content = this.renderTemplate(template, artifact);
173
+ const filename = this.generateFilename(artifact, 'workflow', extension);
174
+ const filePath = path.join(targetPath, filename);
175
+ await this.writeFile(filePath, content);
176
+ count++;
177
+ }
178
+ }
179
+
180
+ return count;
181
+ }
182
+
183
+ /**
184
+ * Load template based on type and configuration
185
+ * @param {string} templateType - Template type (claude, windsurf, etc.)
186
+ * @param {string} artifactType - Artifact type (agent, workflow, task, tool)
187
+ * @param {Object} config - Installation configuration
188
+ * @param {string} fallbackTemplateType - Fallback template type if requested template not found
189
+ * @returns {Promise<{content: string, extension: string}>} Template content and extension
190
+ */
191
+ async loadTemplate(templateType, artifactType, config = {}, fallbackTemplateType = null) {
192
+ const { header_template, body_template } = config;
193
+
194
+ // Check for separate header/body templates
195
+ if (header_template || body_template) {
196
+ const content = await this.loadSplitTemplates(templateType, artifactType, header_template, body_template);
197
+ // Allow config to override extension, default to .md
198
+ const ext = config.extension || '.md';
199
+ const normalizedExt = ext.startsWith('.') ? ext : `.${ext}`;
200
+ return { content, extension: normalizedExt };
201
+ }
202
+
203
+ // Load combined template - try multiple extensions
204
+ // If artifactType is empty, templateType already contains full name (e.g., 'gemini-workflow-yaml')
205
+ const templateBaseName = artifactType ? `${templateType}-${artifactType}` : templateType;
206
+ const templateDir = path.join(__dirname, 'templates', 'combined');
207
+ const extensions = ['.md', '.toml', '.yaml', '.yml'];
208
+
209
+ for (const ext of extensions) {
210
+ const templatePath = path.join(templateDir, templateBaseName + ext);
211
+ if (await fs.pathExists(templatePath)) {
212
+ const content = await fs.readFile(templatePath, 'utf8');
213
+ return { content, extension: ext };
214
+ }
215
+ }
216
+
217
+ // Fall back to default template (if provided)
218
+ if (fallbackTemplateType) {
219
+ for (const ext of extensions) {
220
+ const fallbackPath = path.join(templateDir, `${fallbackTemplateType}${ext}`);
221
+ if (await fs.pathExists(fallbackPath)) {
222
+ const content = await fs.readFile(fallbackPath, 'utf8');
223
+ return { content, extension: ext };
224
+ }
225
+ }
226
+ }
227
+
228
+ // Ultimate fallback - minimal template
229
+ return { content: this.getDefaultTemplate(artifactType), extension: '.md' };
230
+ }
231
+
232
+ /**
233
+ * Load split templates (header + body)
234
+ * @param {string} templateType - Template type
235
+ * @param {string} artifactType - Artifact type
236
+ * @param {string} headerTpl - Header template name
237
+ * @param {string} bodyTpl - Body template name
238
+ * @returns {Promise<string>} Combined template content
239
+ */
240
+ async loadSplitTemplates(templateType, artifactType, headerTpl, bodyTpl) {
241
+ let header = '';
242
+ let body = '';
243
+
244
+ // Load header template
245
+ if (headerTpl) {
246
+ const headerPath = path.join(__dirname, 'templates', 'split', headerTpl);
247
+ if (await fs.pathExists(headerPath)) {
248
+ header = await fs.readFile(headerPath, 'utf8');
249
+ }
250
+ } else {
251
+ // Use default header for template type
252
+ const defaultHeaderPath = path.join(__dirname, 'templates', 'split', templateType, 'header.md');
253
+ if (await fs.pathExists(defaultHeaderPath)) {
254
+ header = await fs.readFile(defaultHeaderPath, 'utf8');
255
+ }
256
+ }
257
+
258
+ // Load body template
259
+ if (bodyTpl) {
260
+ const bodyPath = path.join(__dirname, 'templates', 'split', bodyTpl);
261
+ if (await fs.pathExists(bodyPath)) {
262
+ body = await fs.readFile(bodyPath, 'utf8');
263
+ }
264
+ } else {
265
+ // Use default body for template type
266
+ const defaultBodyPath = path.join(__dirname, 'templates', 'split', templateType, 'body.md');
267
+ if (await fs.pathExists(defaultBodyPath)) {
268
+ body = await fs.readFile(defaultBodyPath, 'utf8');
269
+ }
270
+ }
271
+
272
+ // Combine header and body
273
+ return `${header}\n${body}`;
274
+ }
275
+
276
+ /**
277
+ * Get default minimal template
278
+ * @param {string} artifactType - Artifact type
279
+ * @returns {string} Default template
280
+ */
281
+ getDefaultTemplate(artifactType) {
282
+ if (artifactType === 'agent') {
283
+ return `---
284
+ name: '{{name}}'
285
+ description: '{{description}}'
286
+ ---
287
+
288
+ You must fully embody this agent's persona and follow all activation instructions exactly as specified.
289
+
290
+ <agent-activation CRITICAL="TRUE">
291
+ 1. LOAD the FULL agent file from {project-root}/{{bmadFolderName}}/{{path}}
292
+ 2. READ its entire contents - this contains the complete agent persona, menu, and instructions
293
+ 3. FOLLOW every step in the <activation> section precisely
294
+ </agent-activation>
295
+ `;
296
+ }
297
+ return `---
298
+ name: '{{name}}'
299
+ description: '{{description}}'
300
+ ---
301
+
302
+ # {{name}}
303
+
304
+ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
305
+ `;
306
+ }
307
+
308
+ /**
309
+ * Render template with artifact data
310
+ * @param {string} template - Template content
311
+ * @param {Object} artifact - Artifact data
312
+ * @returns {string} Rendered content
313
+ */
314
+ renderTemplate(template, artifact) {
315
+ // Use the appropriate path property based on artifact type
316
+ let pathToUse = artifact.relativePath || '';
317
+ if (artifact.type === 'agent-launcher') {
318
+ pathToUse = artifact.agentPath || artifact.relativePath || '';
319
+ } else if (artifact.type === 'workflow-command') {
320
+ pathToUse = artifact.workflowPath || artifact.relativePath || '';
321
+ }
322
+
323
+ let rendered = template
324
+ .replaceAll('{{name}}', artifact.name || '')
325
+ .replaceAll('{{module}}', artifact.module || 'core')
326
+ .replaceAll('{{path}}', pathToUse)
327
+ .replaceAll('{{description}}', artifact.description || `${artifact.name} ${artifact.type || ''}`)
328
+ .replaceAll('{{workflow_path}}', pathToUse);
329
+
330
+ // Replace _bmad placeholder with actual folder name
331
+ rendered = rendered.replaceAll('_bmad', this.bmadFolderName);
332
+
333
+ // Replace {{bmadFolderName}} placeholder if present
334
+ rendered = rendered.replaceAll('{{bmadFolderName}}', this.bmadFolderName);
335
+
336
+ return rendered;
337
+ }
338
+
339
+ /**
340
+ * Generate filename for artifact
341
+ * @param {Object} artifact - Artifact data
342
+ * @param {string} artifactType - Artifact type (agent, workflow, task, tool)
343
+ * @param {string} extension - File extension to use (e.g., '.md', '.toml')
344
+ * @returns {string} Generated filename
345
+ */
346
+ generateFilename(artifact, artifactType, extension = '.md') {
347
+ const { toDashPath } = require('./shared/path-utils');
348
+
349
+ // Reuse central logic to ensure consistent naming conventions
350
+ const standardName = toDashPath(artifact.relativePath);
351
+
352
+ // Clean up potential double extensions from source files (e.g. .yaml.md -> .md)
353
+ const baseName = standardName.replace(/\.(yaml|yml)\.md$/, '.md');
354
+
355
+ // If using default markdown, preserve the bmad-agent- prefix for agents
356
+ if (extension === '.md') {
357
+ return baseName;
358
+ }
359
+
360
+ // For other extensions (e.g., .toml), replace .md extension
361
+ // Note: agent prefix is preserved even with non-markdown extensions
362
+ return baseName.replace(/\.md$/, extension);
363
+ }
364
+
365
+ /**
366
+ * Print installation summary
367
+ * @param {Object} results - Installation results
368
+ * @param {string} targetDir - Target directory (relative)
369
+ */
370
+ printSummary(results, targetDir) {
371
+ console.log(chalk.green(`\n✓ ${this.name} configured:`));
372
+ if (results.agents > 0) {
373
+ console.log(chalk.dim(` - ${results.agents} agents installed`));
374
+ }
375
+ if (results.workflows > 0) {
376
+ console.log(chalk.dim(` - ${results.workflows} workflow commands generated`));
377
+ }
378
+ if (results.tasks > 0 || results.tools > 0) {
379
+ console.log(chalk.dim(` - ${results.tasks + results.tools} task/tool commands generated`));
380
+ }
381
+ console.log(chalk.dim(` - Destination: ${targetDir}`));
382
+ }
383
+
384
+ /**
385
+ * Cleanup IDE configuration
386
+ * @param {string} projectDir - Project directory
387
+ */
388
+ async cleanup(projectDir) {
389
+ // Clean all target directories
390
+ if (this.installerConfig?.targets) {
391
+ for (const target of this.installerConfig.targets) {
392
+ await this.cleanupTarget(projectDir, target.target_dir);
393
+ }
394
+ } else if (this.installerConfig?.target_dir) {
395
+ await this.cleanupTarget(projectDir, this.installerConfig.target_dir);
396
+ }
397
+ }
398
+
399
+ /**
400
+ * Cleanup a specific target directory
401
+ * @param {string} projectDir - Project directory
402
+ * @param {string} targetDir - Target directory to clean
403
+ */
404
+ async cleanupTarget(projectDir, targetDir) {
405
+ const targetPath = path.join(projectDir, targetDir);
406
+
407
+ if (!(await fs.pathExists(targetPath))) {
408
+ return;
409
+ }
410
+
411
+ // Remove all bmad* files
412
+ let entries;
413
+ try {
414
+ entries = await fs.readdir(targetPath);
415
+ } catch {
416
+ // Directory exists but can't be read - skip cleanup
417
+ return;
418
+ }
419
+
420
+ if (!entries || !Array.isArray(entries)) {
421
+ return;
422
+ }
423
+
424
+ let removedCount = 0;
425
+
426
+ for (const entry of entries) {
427
+ // Skip non-strings or undefined entries
428
+ if (!entry || typeof entry !== 'string') {
429
+ continue;
430
+ }
431
+ if (entry.startsWith('bmad')) {
432
+ const entryPath = path.join(targetPath, entry);
433
+ const stat = await fs.stat(entryPath);
434
+ if (stat.isFile()) {
435
+ await fs.remove(entryPath);
436
+ removedCount++;
437
+ } else if (stat.isDirectory()) {
438
+ await fs.remove(entryPath);
439
+ removedCount++;
440
+ }
441
+ }
442
+ }
443
+
444
+ if (removedCount > 0) {
445
+ console.log(chalk.dim(` Cleaned ${removedCount} BMAD files from ${targetDir}`));
446
+ }
447
+ }
448
+ }
449
+
450
+ module.exports = { ConfigDrivenIdeSetup };