bmad-method 4.23.0 → 4.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/.vscode/settings.json +11 -5
  2. package/CHANGELOG.md +22 -1
  3. package/README.md +2 -2
  4. package/bmad-core/agents/bmad-master.md +15 -2
  5. package/bmad-core/agents/bmad-orchestrator.md +14 -0
  6. package/bmad-core/agents/dev.md +2 -2
  7. package/bmad-core/agents/pm.md +1 -1
  8. package/bmad-core/agents/po.md +1 -1
  9. package/bmad-core/{core-config.yml → core-config.yaml} +5 -0
  10. package/bmad-core/data/bmad-kb.md +4 -4
  11. package/bmad-core/tasks/create-brownfield-story.md +355 -0
  12. package/bmad-core/tasks/create-next-story.md +29 -4
  13. package/bmad-core/tasks/create-workflow-plan.md +289 -0
  14. package/bmad-core/tasks/shard-doc.md +3 -3
  15. package/bmad-core/tasks/update-workflow-plan.md +248 -0
  16. package/bmad-core/templates/architecture-tmpl.md +1 -1
  17. package/bmad-core/templates/brownfield-prd-tmpl.md +52 -28
  18. package/bmad-core/templates/fullstack-architecture-tmpl.md +3 -3
  19. package/bmad-core/utils/plan-management.md +223 -0
  20. package/bmad-core/workflows/brownfield-fullstack.yaml +297 -0
  21. package/bmad-core/workflows/brownfield-service.yaml +187 -0
  22. package/bmad-core/workflows/{brownfield-ui.yml → brownfield-ui.yaml} +110 -36
  23. package/bmad-core/workflows/{greenfield-fullstack.yml → greenfield-fullstack.yaml} +110 -36
  24. package/bmad-core/workflows/{greenfield-service.yml → greenfield-service.yaml} +110 -36
  25. package/bmad-core/workflows/{greenfield-ui.yml → greenfield-ui.yaml} +110 -36
  26. package/common/tasks/create-doc.md +21 -1
  27. package/docs/agentic-tools/roo-code-guide.md +1 -1
  28. package/docs/core-architecture.md +12 -12
  29. package/docs/user-guide.md +6 -6
  30. package/expansion-packs/bmad-creator-tools/tasks/generate-expansion-pack.md +9 -9
  31. package/expansion-packs/bmad-creator-tools/templates/agent-teams-tmpl.md +1 -1
  32. package/expansion-packs/bmad-creator-tools/templates/agent-tmpl.md +1 -1
  33. package/expansion-packs/bmad-infrastructure-devops/README.md +3 -3
  34. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.md +0 -0
  35. package/package.json +1 -1
  36. package/tools/builders/web-builder.js +19 -20
  37. package/tools/bump-all-versions.js +2 -2
  38. package/tools/bump-core-version.js +1 -1
  39. package/tools/bump-expansion-version.js +1 -1
  40. package/tools/installer/README.md +1 -1
  41. package/tools/installer/bin/bmad.js +2 -2
  42. package/tools/installer/lib/config-loader.js +13 -12
  43. package/tools/installer/lib/file-manager.js +5 -5
  44. package/tools/installer/lib/ide-setup.js +14 -13
  45. package/tools/installer/lib/installer.js +26 -38
  46. package/tools/installer/package.json +1 -1
  47. package/tools/lib/dependency-resolver.js +9 -13
  48. package/tools/lib/yaml-utils.js +29 -0
  49. package/tools/update-expansion-version.js +3 -3
  50. package/tools/yaml-format.js +1 -1
  51. package/bmad-core/workflows/brownfield-fullstack.yml +0 -112
  52. package/bmad-core/workflows/brownfield-service.yml +0 -113
  53. package/dist/agents/analyst.txt +0 -2709
  54. package/dist/agents/architect.txt +0 -3903
  55. package/dist/agents/bmad-master.txt +0 -9173
  56. package/dist/agents/bmad-orchestrator.txt +0 -1257
  57. package/dist/agents/dev.txt +0 -298
  58. package/dist/agents/pm.txt +0 -2205
  59. package/dist/agents/po.txt +0 -1511
  60. package/dist/agents/qa.txt +0 -262
  61. package/dist/agents/sm.txt +0 -701
  62. package/dist/agents/ux-expert.txt +0 -1081
  63. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +0 -2358
  64. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.txt +0 -1584
  65. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.txt +0 -809
  66. package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +0 -6672
  67. package/dist/expansion-packs/bmad-creator-tools/agents/bmad-the-creator.txt +0 -1960
  68. package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +0 -2053
  69. package/dist/teams/team-all.txt +0 -10543
  70. package/dist/teams/team-fullstack.txt +0 -9731
  71. package/dist/teams/team-ide-minimal.txt +0 -3535
  72. package/dist/teams/team-no-ui.txt +0 -8619
  73. /package/.github/{FUNDING.yml → FUNDING.yaml} +0 -0
  74. /package/.github/workflows/{release.yml → release.yaml} +0 -0
  75. /package/bmad-core/agent-teams/{team-all.yml → team-all.yaml} +0 -0
  76. /package/bmad-core/agent-teams/{team-fullstack.yml → team-fullstack.yaml} +0 -0
  77. /package/bmad-core/agent-teams/{team-ide-minimal.yml → team-ide-minimal.yaml} +0 -0
  78. /package/bmad-core/agent-teams/{team-no-ui.yml → team-no-ui.yaml} +0 -0
  79. /package/expansion-packs/bmad-2d-phaser-game-dev/agent-teams/{phaser-2d-nodejs-game-team.yml → phaser-2d-nodejs-game-team.yaml} +0 -0
  80. /package/expansion-packs/bmad-2d-phaser-game-dev/{config.yml → config.yaml} +0 -0
  81. /package/expansion-packs/bmad-2d-phaser-game-dev/workflows/{game-dev-greenfield.yml → game-dev-greenfield.yaml} +0 -0
  82. /package/expansion-packs/bmad-2d-phaser-game-dev/workflows/{game-prototype.yml → game-prototype.yaml} +0 -0
  83. /package/expansion-packs/bmad-creator-tools/{config.yml → config.yaml} +0 -0
  84. /package/expansion-packs/bmad-infrastructure-devops/{config.yml → config.yaml} +0 -0
  85. /package/tools/installer/config/{ide-agent-config.yml → ide-agent-config.yaml} +0 -0
  86. /package/tools/installer/config/{install.config.yml → install.config.yaml} +0 -0
@@ -1,10 +1,11 @@
1
1
  const fs = require('fs-extra');
2
2
  const path = require('path');
3
3
  const yaml = require('js-yaml');
4
+ const { extractYamlFromAgent } = require('../../lib/yaml-utils');
4
5
 
5
6
  class ConfigLoader {
6
7
  constructor() {
7
- this.configPath = path.join(__dirname, '..', 'config', 'install.config.yml');
8
+ this.configPath = path.join(__dirname, '..', 'config', 'install.config.yaml');
8
9
  this.config = null;
9
10
  }
10
11
 
@@ -41,9 +42,9 @@ class ConfigLoader {
41
42
  const agentContent = await fs.readFile(agentPath, 'utf8');
42
43
 
43
44
  // Extract YAML block from agent file
44
- const yamlMatch = agentContent.match(/```yml\n([\s\S]*?)\n```/);
45
- if (yamlMatch) {
46
- const yamlContent = yaml.load(yamlMatch[1]);
45
+ const yamlContentText = extractYamlFromAgent(agentContent);
46
+ if (yamlContentText) {
47
+ const yamlContent = yaml.load(yamlContentText);
47
48
  const agentConfig = yamlContent.agent || {};
48
49
 
49
50
  agents.push({
@@ -79,10 +80,10 @@ class ConfigLoader {
79
80
  for (const entry of entries) {
80
81
  if (entry.isDirectory() && !entry.name.startsWith('.')) {
81
82
  const packPath = path.join(expansionPacksDir, entry.name);
82
- const configPath = path.join(packPath, 'config.yml');
83
+ const configPath = path.join(packPath, 'config.yaml');
83
84
 
84
85
  try {
85
- // Read config.yml
86
+ // Read config.yaml
86
87
  const configContent = await fs.readFile(configPath, 'utf8');
87
88
  const config = yaml.load(configContent);
88
89
 
@@ -97,7 +98,7 @@ class ConfigLoader {
97
98
  dependencies: config.dependencies?.agents || []
98
99
  });
99
100
  } catch (error) {
100
- // Fallback if config.yml doesn't exist or can't be read
101
+ // Fallback if config.yaml doesn't exist or can't be read
101
102
  console.warn(`Failed to read config for expansion pack ${entry.name}: ${error.message}`);
102
103
 
103
104
  // Try to derive info from directory name as fallback
@@ -180,7 +181,7 @@ class ConfigLoader {
180
181
  const teams = [];
181
182
 
182
183
  for (const entry of entries) {
183
- if (entry.isFile() && entry.name.endsWith('.yml')) {
184
+ if (entry.isFile() && entry.name.endsWith('.yaml')) {
184
185
  const teamPath = path.join(teamsDir, entry.name);
185
186
 
186
187
  try {
@@ -189,7 +190,7 @@ class ConfigLoader {
189
190
 
190
191
  if (teamConfig.bundle) {
191
192
  teams.push({
192
- id: path.basename(entry.name, '.yml'),
193
+ id: path.basename(entry.name, '.yaml'),
193
194
  name: teamConfig.bundle.name || entry.name,
194
195
  description: teamConfig.bundle.description || 'Team configuration',
195
196
  icon: teamConfig.bundle.icon || '📋'
@@ -209,7 +210,7 @@ class ConfigLoader {
209
210
  }
210
211
 
211
212
  getTeamPath(teamId) {
212
- return path.join(this.getBmadCorePath(), 'agent-teams', `${teamId}.yml`);
213
+ return path.join(this.getBmadCorePath(), 'agent-teams', `${teamId}.yaml`);
213
214
  }
214
215
 
215
216
  async getTeamDependencies(teamId) {
@@ -224,7 +225,7 @@ class ConfigLoader {
224
225
  const depPaths = [];
225
226
 
226
227
  // Add team config file
227
- depPaths.push(`.bmad-core/agent-teams/${teamId}.yml`);
228
+ depPaths.push(`.bmad-core/agent-teams/${teamId}.yaml`);
228
229
 
229
230
  // Add all agents
230
231
  for (const agent of teamDeps.agents) {
@@ -236,7 +237,7 @@ class ConfigLoader {
236
237
 
237
238
  // Add all resolved resources
238
239
  for (const resource of teamDeps.resources) {
239
- const filePath = `.bmad-core/${resource.type}/${resource.id}.${resource.type === 'workflows' ? 'yml' : 'md'}`;
240
+ const filePath = `.bmad-core/${resource.type}/${resource.id}.${resource.type === 'workflows' ? 'yaml' : 'md'}`;
240
241
  if (!depPaths.includes(filePath)) {
241
242
  depPaths.push(filePath);
242
243
  }
@@ -17,7 +17,7 @@ async function initializeModules() {
17
17
  class FileManager {
18
18
  constructor() {
19
19
  this.manifestDir = ".bmad-core";
20
- this.manifestFile = "install-manifest.yml";
20
+ this.manifestFile = "install-manifest.yaml";
21
21
  }
22
22
 
23
23
  async copyFile(source, destination) {
@@ -83,15 +83,15 @@ class FileManager {
83
83
  this.manifestFile
84
84
  );
85
85
 
86
- // Read version from core-config.yml
87
- const coreConfigPath = path.join(__dirname, "../../../bmad-core/core-config.yml");
86
+ // Read version from core-config.yaml
87
+ const coreConfigPath = path.join(__dirname, "../../../bmad-core/core-config.yaml");
88
88
  let coreVersion = "unknown";
89
89
  try {
90
90
  const coreConfigContent = await fs.readFile(coreConfigPath, "utf8");
91
91
  const coreConfig = yaml.load(coreConfigContent);
92
92
  coreVersion = coreConfig.version || "unknown";
93
93
  } catch (error) {
94
- console.warn("Could not read version from core-config.yml, using 'unknown'");
94
+ console.warn("Could not read version from core-config.yaml, using 'unknown'");
95
95
  }
96
96
 
97
97
  const manifest = {
@@ -178,7 +178,7 @@ class FileManager {
178
178
  const filePath = path.join(installDir, file.path);
179
179
 
180
180
  // Skip checking the manifest file itself - it will always be different due to timestamps
181
- if (file.path.endsWith('install-manifest.yml')) {
181
+ if (file.path.endsWith('install-manifest.yaml')) {
182
182
  continue;
183
183
  }
184
184
 
@@ -3,6 +3,7 @@ const fs = require("fs-extra");
3
3
  const yaml = require("js-yaml");
4
4
  const fileManager = require("./file-manager");
5
5
  const configLoader = require("./config-loader");
6
+ const { extractYamlFromAgent } = require("../../lib/yaml-utils");
6
7
 
7
8
  // Dynamic import for ES module
8
9
  let chalk;
@@ -27,7 +28,7 @@ class IdeSetup {
27
28
  if (this.ideAgentConfig) return this.ideAgentConfig;
28
29
 
29
30
  try {
30
- const configPath = path.join(__dirname, '..', 'config', 'ide-agent-config.yml');
31
+ const configPath = path.join(__dirname, '..', 'config', 'ide-agent-config.yaml');
31
32
  const configContent = await fs.readFile(configPath, 'utf8');
32
33
  this.ideAgentConfig = yaml.load(configContent);
33
34
  return this.ideAgentConfig;
@@ -98,11 +99,11 @@ class IdeSetup {
98
99
  mdcContent += "## Agent Activation\n\n";
99
100
  mdcContent +=
100
101
  "CRITICAL: Read the full YML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n";
101
- mdcContent += "```yml\n";
102
+ mdcContent += "```yaml\n";
102
103
  // Extract just the YAML content from the agent file
103
- const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
104
- if (yamlMatch) {
105
- mdcContent += yamlMatch[1].trim();
104
+ const yamlContent = extractYamlFromAgent(agentContent);
105
+ if (yamlContent) {
106
+ mdcContent += yamlContent;
106
107
  } else {
107
108
  // If no YAML found, include the whole content minus the header
108
109
  mdcContent += agentContent.replace(/^#.*$/m, "").trim();
@@ -180,11 +181,11 @@ class IdeSetup {
180
181
  mdContent += "## Agent Activation\n\n";
181
182
  mdContent +=
182
183
  "CRITICAL: Read the full YML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n";
183
- mdContent += "```yml\n";
184
+ mdContent += "```yaml\n";
184
185
  // Extract just the YAML content from the agent file
185
- const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
186
- if (yamlMatch) {
187
- mdContent += yamlMatch[1].trim();
186
+ const yamlContent = extractYamlFromAgent(agentContent);
187
+ if (yamlContent) {
188
+ mdContent += yamlContent;
188
189
  } else {
189
190
  // If no YAML found, include the whole content minus the header
190
191
  mdContent += agentContent.replace(/^#.*$/m, "").trim();
@@ -428,11 +429,11 @@ class IdeSetup {
428
429
  mdContent += "## Role Definition\n\n";
429
430
  mdContent +=
430
431
  "When the user types `@" + agentId + "`, adopt this persona and follow these guidelines:\n\n";
431
- mdContent += "```yml\n";
432
+ mdContent += "```yaml\n";
432
433
  // Extract just the YAML content from the agent file
433
- const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
434
- if (yamlMatch) {
435
- mdContent += yamlMatch[1].trim();
434
+ const yamlContent = extractYamlFromAgent(agentContent);
435
+ if (yamlContent) {
436
+ mdContent += yamlContent;
436
437
  } else {
437
438
  // If no YAML found, include the whole content minus the header
438
439
  mdContent += agentContent.replace(/^#.*$/m, "").trim();
@@ -2,6 +2,7 @@ const path = require("node:path");
2
2
  const fileManager = require("./file-manager");
3
3
  const configLoader = require("./config-loader");
4
4
  const ideSetup = require("./ide-setup");
5
+ const { extractYamlFromAgent } = require("../../lib/yaml-utils");
5
6
 
6
7
  // Dynamic imports for ES modules
7
8
  let chalk, ora, inquirer;
@@ -19,13 +20,13 @@ class Installer {
19
20
  async getCoreVersion() {
20
21
  const yaml = require("js-yaml");
21
22
  const fs = require("fs-extra");
22
- const coreConfigPath = path.join(__dirname, "../../../bmad-core/core-config.yml");
23
+ const coreConfigPath = path.join(__dirname, "../../../bmad-core/core-config.yaml");
23
24
  try {
24
25
  const coreConfigContent = await fs.readFile(coreConfigPath, "utf8");
25
26
  const coreConfig = yaml.load(coreConfigContent);
26
27
  return coreConfig.version || "unknown";
27
28
  } catch (error) {
28
- console.warn("Could not read version from core-config.yml, using 'unknown'");
29
+ console.warn("Could not read version from core-config.yaml, using 'unknown'");
29
30
  return "unknown";
30
31
  }
31
32
  }
@@ -185,7 +186,7 @@ class Installer {
185
186
 
186
187
  // Check for V4 installation (has .bmad-core with manifest)
187
188
  const bmadCorePath = path.join(installDir, ".bmad-core");
188
- const manifestPath = path.join(bmadCorePath, "install-manifest.yml");
189
+ const manifestPath = path.join(bmadCorePath, "install-manifest.yaml");
189
190
 
190
191
  if (await fileManager.pathExists(manifestPath)) {
191
192
  state.type = "v4_existing";
@@ -713,7 +714,7 @@ class Installer {
713
714
 
714
715
  for (const file of filesToRestore) {
715
716
  // Skip the manifest file itself
716
- if (file.endsWith('install-manifest.yml')) continue;
717
+ if (file.endsWith('install-manifest.yaml')) continue;
717
718
 
718
719
  const relativePath = file.replace('.bmad-core/', '');
719
720
  const destPath = path.join(installDir, file);
@@ -757,12 +758,7 @@ class Installer {
757
758
  const ides = manifest.ides_setup || [];
758
759
  if (ides.includes('cursor')) {
759
760
  console.log(chalk.yellow.bold("\n⚠️ IMPORTANT: Cursor Custom Modes Update Required"));
760
- console.log(chalk.yellow("Since agent files have been repaired, you need to manually update your Cursor custom modes:"));
761
- console.log(chalk.yellow("1. Open Cursor Settings (Cmd/Ctrl + ,)"));
762
- console.log(chalk.yellow("2. Go to: Features > Cursor Tab > Custom Modes"));
763
- console.log(chalk.yellow("3. Update each custom mode with the latest agent templates from:"));
764
- console.log(chalk.yellow(` ${path.join(installDir, '.bmad-core', 'agents')}`));
765
- console.log(chalk.yellow("4. Copy the full content of each agent file into the corresponding custom mode"));
761
+ console.log(chalk.yellow("Since agent files have been repaired, you need to update any custom agent modes configured in the Cursor custom agent GUI per the Cursor docs."));
766
762
  }
767
763
 
768
764
  } catch (error) {
@@ -861,12 +857,7 @@ class Installer {
861
857
  // Warning for Cursor custom modes if agents were updated
862
858
  if (options.isUpdate && ides.includes('cursor')) {
863
859
  console.log(chalk.yellow.bold("\n⚠️ IMPORTANT: Cursor Custom Modes Update Required"));
864
- console.log(chalk.yellow("Since agents have been updated, you need to manually update your Cursor custom modes:"));
865
- console.log(chalk.yellow("1. Open Cursor Settings (Cmd/Ctrl + ,)"));
866
- console.log(chalk.yellow("2. Go to: Features > Cursor Tab > Custom Modes"));
867
- console.log(chalk.yellow("3. Update each custom mode with the latest agent templates from:"));
868
- console.log(chalk.yellow(` ${path.join(installDir, '.bmad-core', 'agents')}`));
869
- console.log(chalk.yellow("4. Copy the full content of each agent file into the corresponding custom mode"));
860
+ console.log(chalk.yellow("Since agents have been updated, you need to update any custom agent modes configured in the Cursor custom agent GUI per the Cursor docs."));
870
861
  }
871
862
  }
872
863
 
@@ -1019,7 +1010,7 @@ class Installer {
1019
1010
 
1020
1011
  // Check if expansion pack already exists
1021
1012
  let expansionDotFolder = path.join(installDir, `.${packId}`);
1022
- const existingManifestPath = path.join(expansionDotFolder, 'install-manifest.yml');
1013
+ const existingManifestPath = path.join(expansionDotFolder, 'install-manifest.yaml');
1023
1014
 
1024
1015
  if (await fileManager.pathExists(existingManifestPath)) {
1025
1016
  spinner.stop();
@@ -1161,12 +1152,12 @@ class Installer {
1161
1152
  }
1162
1153
  }
1163
1154
 
1164
- // Copy config.yml
1165
- const configPath = path.join(expansionPackDir, 'config.yml');
1155
+ // Copy config.yaml
1156
+ const configPath = path.join(expansionPackDir, 'config.yaml');
1166
1157
  if (await fileManager.pathExists(configPath)) {
1167
- const configDestPath = path.join(expansionDotFolder, 'config.yml');
1158
+ const configDestPath = path.join(expansionDotFolder, 'config.yaml');
1168
1159
  if (await fileManager.copyFile(configPath, configDestPath)) {
1169
- installedFiles.push(path.join(`.${packId}`, 'config.yml'));
1160
+ installedFiles.push(path.join(`.${packId}`, 'config.yaml'));
1170
1161
  }
1171
1162
  }
1172
1163
 
@@ -1232,10 +1223,10 @@ class Installer {
1232
1223
  const agentContent = await fs.readFile(agentPath, 'utf8');
1233
1224
 
1234
1225
  // Extract YAML frontmatter to check dependencies
1235
- const yamlMatch = agentContent.match(/```yaml\n([\s\S]*?)```/);
1236
- if (yamlMatch) {
1226
+ const yamlContent = extractYamlFromAgent(agentContent);
1227
+ if (yamlContent) {
1237
1228
  try {
1238
- const agentConfig = yaml.parse(yamlMatch[1]);
1229
+ const agentConfig = yaml.parse(yamlContent);
1239
1230
  const dependencies = agentConfig.dependencies || {};
1240
1231
 
1241
1232
  // Check for core dependencies (those that don't exist in the expansion pack)
@@ -1278,7 +1269,7 @@ class Installer {
1278
1269
  const fs = require('fs').promises;
1279
1270
 
1280
1271
  // Find all team files in the expansion pack
1281
- const teamFiles = glob.sync('agent-teams/*.yml', {
1272
+ const teamFiles = glob.sync('agent-teams/*.yaml', {
1282
1273
  cwd: expansionDotFolder
1283
1274
  });
1284
1275
 
@@ -1324,13 +1315,10 @@ class Installer {
1324
1315
 
1325
1316
  // Now resolve this agent's dependencies too
1326
1317
  const agentContent = await fs.readFile(coreAgentPath, 'utf8');
1327
- const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
1318
+ const yamlContent = extractYamlFromAgent(agentContent, true);
1328
1319
 
1329
- if (yamlMatch) {
1320
+ if (yamlContent) {
1330
1321
  try {
1331
- // Clean up the YAML to handle command descriptions
1332
- let yamlContent = yamlMatch[1];
1333
- yamlContent = yamlContent.replace(/^(\s*-)(\s*"[^"]+")(\s*-\s*.*)$/gm, '$1$2');
1334
1322
 
1335
1323
  const agentConfig = yaml.parse(yamlContent);
1336
1324
  const dependencies = agentConfig.dependencies || {};
@@ -1340,7 +1328,7 @@ class Installer {
1340
1328
  const deps = dependencies[depType] || [];
1341
1329
 
1342
1330
  for (const dep of deps) {
1343
- const depFileName = dep.endsWith('.md') || dep.endsWith('.yml') ? dep : `${dep}.md`;
1331
+ const depFileName = dep.endsWith('.md') || dep.endsWith('.yaml') ? dep : `${dep}.md`;
1344
1332
  const expansionDepPath = path.join(expansionDotFolder, depType, depFileName);
1345
1333
 
1346
1334
  // Check if dependency exists in expansion pack
@@ -1370,7 +1358,7 @@ class Installer {
1370
1358
  }
1371
1359
  }
1372
1360
  } else {
1373
- console.warn(chalk.yellow(` Warning: Core agent ${agentId} not found for team ${path.basename(teamFile, '.yml')}`));
1361
+ console.warn(chalk.yellow(` Warning: Core agent ${agentId} not found for team ${path.basename(teamFile, '.yaml')}`));
1374
1362
  }
1375
1363
  }
1376
1364
  }
@@ -1538,7 +1526,7 @@ class Installer {
1538
1526
 
1539
1527
  if (stats) {
1540
1528
  // Check if it has a manifest
1541
- const manifestPath = path.join(folderPath, "install-manifest.yml");
1529
+ const manifestPath = path.join(folderPath, "install-manifest.yaml");
1542
1530
  if (await fileManager.pathExists(manifestPath)) {
1543
1531
  const manifest = await fileManager.readExpansionPackManifest(installDir, folder.substring(1));
1544
1532
  if (manifest) {
@@ -1549,8 +1537,8 @@ class Installer {
1549
1537
  };
1550
1538
  }
1551
1539
  } else {
1552
- // Check if it has a config.yml (expansion pack without manifest)
1553
- const configPath = path.join(folderPath, "config.yml");
1540
+ // Check if it has a config.yaml (expansion pack without manifest)
1541
+ const configPath = path.join(folderPath, "config.yaml");
1554
1542
  if (await fileManager.pathExists(configPath)) {
1555
1543
  expansionPacks[folder.substring(1)] = {
1556
1544
  path: folderPath,
@@ -1589,7 +1577,7 @@ class Installer {
1589
1577
 
1590
1578
  for (const file of filesToRestore) {
1591
1579
  // Skip the manifest file itself
1592
- if (file.endsWith('install-manifest.yml')) continue;
1580
+ if (file.endsWith('install-manifest.yaml')) continue;
1593
1581
 
1594
1582
  const relativePath = file.replace(`.${packId}/`, '');
1595
1583
  const sourcePath = path.join(pack.packPath, relativePath);
@@ -1655,7 +1643,7 @@ class Installer {
1655
1643
 
1656
1644
  while (currentDir !== path.dirname(currentDir)) {
1657
1645
  const bmadDir = path.join(currentDir, ".bmad-core");
1658
- const manifestPath = path.join(bmadDir, "install-manifest.yml");
1646
+ const manifestPath = path.join(bmadDir, "install-manifest.yaml");
1659
1647
 
1660
1648
  if (await fileManager.pathExists(manifestPath)) {
1661
1649
  return bmadDir;
@@ -1666,7 +1654,7 @@ class Installer {
1666
1654
 
1667
1655
  // Also check if we're inside a .bmad-core directory
1668
1656
  if (path.basename(process.cwd()) === ".bmad-core") {
1669
- const manifestPath = path.join(process.cwd(), "install-manifest.yml");
1657
+ const manifestPath = path.join(process.cwd(), "install-manifest.yaml");
1670
1658
  if (await fileManager.pathExists(manifestPath)) {
1671
1659
  return process.cwd();
1672
1660
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bmad-method",
3
- "version": "4.23.0",
3
+ "version": "4.24.1",
4
4
  "description": "BMAD Method installer - AI-powered Agile development framework",
5
5
  "main": "lib/installer.js",
6
6
  "bin": {
@@ -1,6 +1,7 @@
1
1
  const fs = require('fs').promises;
2
2
  const path = require('path');
3
3
  const yaml = require('js-yaml');
4
+ const { extractYamlFromAgent } = require('./yaml-utils');
4
5
 
5
6
  class DependencyResolver {
6
7
  constructor(rootDir) {
@@ -14,17 +15,12 @@ class DependencyResolver {
14
15
  const agentPath = path.join(this.bmadCore, 'agents', `${agentId}.md`);
15
16
  const agentContent = await fs.readFile(agentPath, 'utf8');
16
17
 
17
- // Extract YAML from markdown content
18
- const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)\n```/);
19
- if (!yamlMatch) {
18
+ // Extract YAML from markdown content with command cleaning
19
+ const yamlContent = extractYamlFromAgent(agentContent, true);
20
+ if (!yamlContent) {
20
21
  throw new Error(`No YAML configuration found in agent ${agentId}`);
21
22
  }
22
23
 
23
- // Clean up the YAML to handle command descriptions after dashes
24
- let yamlContent = yamlMatch[1];
25
- // Fix commands section: convert "- command - description" to just "- command"
26
- yamlContent = yamlContent.replace(/^(\s*-)(\s*"[^"]+")(\s*-\s*.*)$/gm, '$1$2');
27
-
28
24
  const agentConfig = yaml.load(yamlContent);
29
25
 
30
26
  const dependencies = {
@@ -53,7 +49,7 @@ class DependencyResolver {
53
49
  }
54
50
 
55
51
  async resolveTeamDependencies(teamId) {
56
- const teamPath = path.join(this.bmadCore, 'agent-teams', `${teamId}.yml`);
52
+ const teamPath = path.join(this.bmadCore, 'agent-teams', `${teamId}.yaml`);
57
53
  const teamContent = await fs.readFile(teamPath, 'utf8');
58
54
  const teamConfig = yaml.load(teamContent);
59
55
 
@@ -120,7 +116,7 @@ class DependencyResolver {
120
116
  }
121
117
 
122
118
  try {
123
- const extensions = ['.md', '.yml', '.yaml'];
119
+ const extensions = ['.md', '.yaml'];
124
120
  let content = null;
125
121
  let filePath = null;
126
122
 
@@ -183,12 +179,12 @@ class DependencyResolver {
183
179
  try {
184
180
  const files = await fs.readdir(path.join(this.bmadCore, 'agent-teams'));
185
181
  return files
186
- .filter(f => f.endsWith('.yml'))
187
- .map(f => f.replace('.yml', ''));
182
+ .filter(f => f.endsWith('.yaml'))
183
+ .map(f => f.replace('.yaml', ''));
188
184
  } catch (error) {
189
185
  return [];
190
186
  }
191
187
  }
192
188
  }
193
189
 
194
- module.exports = DependencyResolver;
190
+ module.exports = DependencyResolver;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Utility functions for YAML extraction from agent files
3
+ */
4
+
5
+ /**
6
+ * Extract YAML content from agent markdown files
7
+ * @param {string} agentContent - The full content of the agent file
8
+ * @param {boolean} cleanCommands - Whether to clean command descriptions (default: false)
9
+ * @returns {string|null} - The extracted YAML content or null if not found
10
+ */
11
+ function extractYamlFromAgent(agentContent, cleanCommands = false) {
12
+ // Remove carriage returns and match YAML block
13
+ const yamlMatch = agentContent.replace(/\r/g, "").match(/```ya?ml\n([\s\S]*?)\n```/);
14
+ if (!yamlMatch) return null;
15
+
16
+ let yamlContent = yamlMatch[1].trim();
17
+
18
+ // Clean up command descriptions if requested
19
+ // Converts "- command - description" to just "- command"
20
+ if (cleanCommands) {
21
+ yamlContent = yamlContent.replace(/^(\s*-)(\s*"[^"]+")(\s*-\s*.*)$/gm, '$1$2');
22
+ }
23
+
24
+ return yamlContent;
25
+ }
26
+
27
+ module.exports = {
28
+ extractYamlFromAgent
29
+ };
@@ -22,8 +22,8 @@ if (!/^\d+\.\d+\.\d+$/.test(newVersion)) {
22
22
 
23
23
  async function updateVersion() {
24
24
  try {
25
- // Update in config.yml
26
- const configPath = path.join(__dirname, '..', 'expansion-packs', packId, 'config.yml');
25
+ // Update in config.yaml
26
+ const configPath = path.join(__dirname, '..', 'expansion-packs', packId, 'config.yaml');
27
27
 
28
28
  if (!fs.existsSync(configPath)) {
29
29
  console.error(`Error: Expansion pack '${packId}' not found`);
@@ -39,7 +39,7 @@ async function updateVersion() {
39
39
  const updatedYaml = yaml.dump(config, { indent: 2 });
40
40
  fs.writeFileSync(configPath, updatedYaml);
41
41
 
42
- console.log(`✓ Updated ${packId}/config.yml: ${oldVersion} → ${newVersion}`);
42
+ console.log(`✓ Updated ${packId}/config.yaml: ${oldVersion} → ${newVersion}`);
43
43
  console.log(`\n✓ Successfully updated ${packId} to version ${newVersion}`);
44
44
  console.log('\nNext steps:');
45
45
  console.log('1. Test the changes');
@@ -197,7 +197,7 @@ async function main() {
197
197
  let changed = false;
198
198
  if (ext === '.md') {
199
199
  changed = await processMarkdownFile(filePath);
200
- } else if (ext === '.yml' || ext === '.yaml' || basename.includes('roomodes') || basename.includes('.yml') || basename.includes('.yaml')) {
200
+ } else if (ext === '.yaml' || ext === '.yml' || basename.includes('roomodes') || basename.includes('.yaml') || basename.includes('.yml')) {
201
201
  // Handle YAML files and special cases like .roomodes
202
202
  changed = await processYamlFile(filePath);
203
203
 
@@ -1,112 +0,0 @@
1
- workflow:
2
- id: brownfield-fullstack
3
- name: Brownfield Full-Stack Enhancement
4
- description: >-
5
- Agent workflow for enhancing existing full-stack applications with new features,
6
- modernization, or significant changes. Handles existing system analysis and safe integration.
7
- type: brownfield
8
- project_types:
9
- - feature-addition
10
- - refactoring
11
- - modernization
12
- - integration-enhancement
13
-
14
- sequence:
15
- - step: project_analysis
16
- agent: architect
17
- action: analyze existing project and use task document-project
18
- creates: multiple documents per the document-project template
19
- notes: "Review existing documentation, codebase structure, and identify integration points. Document current system understanding before proceeding."
20
-
21
- - agent: pm
22
- creates: prd.md
23
- uses: brownfield-prd-tmpl
24
- requires: existing_project_analysis
25
- notes: "Creates comprehensive PRD with existing system analysis and enhancement planning. SAVE OUTPUT: Copy final prd.md to your project's docs/ folder."
26
-
27
- - agent: architect
28
- creates: architecture.md
29
- uses: brownfield-architecture-tmpl
30
- requires: prd.md
31
- notes: "Creates architecture with integration strategy and existing system constraints. SAVE OUTPUT: Copy final architecture.md to your project's docs/ folder."
32
-
33
- - agent: po
34
- validates: all_artifacts
35
- uses: po-master-checklist
36
- notes: "Validates all documents for integration safety and completeness. May require updates to any document."
37
-
38
- - agent: various
39
- updates: any_flagged_documents
40
- condition: po_checklist_issues
41
- notes: "If PO finds issues, return to relevant agent to fix and re-export updated documents to docs/ folder."
42
-
43
- - workflow_end:
44
- action: move_to_ide
45
- notes: |
46
- Planning phase complete! Now transition to IDE Development:
47
-
48
- 1. ENSURE DOCUMENTS ARE IN PROJECT:
49
- - Copy final prd.md to project's docs/prd.md
50
- - Copy final architecture.md to project's docs/architecture.md
51
- - All documents must be in the project before proceeding
52
-
53
- 2. SHARD DOCUMENTS (in IDE):
54
- - Option A: Use PO agent to shard: @po then ask to shard docs/prd.md
55
- - Option B: Manual: Drag shard-doc task + docs/prd.md into chat
56
- - This creates docs/prd/ and docs/architecture/ folders with sharded content
57
-
58
- 3. START DEVELOPMENT CYCLE:
59
- a. SM Agent (New Chat): @sm → *create
60
- - Creates next story from sharded docs
61
- - Review and approve story (Draft → Approved)
62
-
63
- b. Dev Agent (New Chat): @dev
64
- - Implements approved story
65
- - Updates File List with all changes
66
- - Marks story as "Review" when complete
67
-
68
- c. QA Agent (New Chat): @qa → review-story
69
- - Senior dev review with refactoring ability
70
- - Fixes small issues directly
71
- - Leaves checklist for remaining items
72
- - Updates story status (Review → Done or stays Review)
73
-
74
- d. If QA left unchecked items:
75
- - Dev Agent (New Chat): Address remaining items
76
- - Return to QA for final approval
77
-
78
- 4. REPEAT: Continue cycle for all epic stories
79
-
80
- Reference: data#bmad-kb:IDE Development Workflow
81
-
82
- flow_diagram: |
83
- ```mermaid
84
- graph TD
85
- A[Start: Brownfield Enhancement] --> B[analyst: analyze existing project]
86
- B --> C[pm: prd.md]
87
- C --> D[architect: architecture.md]
88
- D --> E[po: validate with po-master-checklist]
89
- E --> F{PO finds issues?}
90
- F -->|Yes| G[Return to relevant agent for fixes]
91
- F -->|No| H[Move to IDE Environment]
92
- G --> E
93
-
94
- style H fill:#90EE90
95
- style C fill:#FFE4B5
96
- style D fill:#FFE4B5
97
- ```
98
-
99
- decision_guidance:
100
- when_to_use:
101
- - Enhancement requires coordinated stories
102
- - Architectural changes are needed
103
- - Significant integration work required
104
- - Risk assessment and mitigation planning necessary
105
- - Multiple team members will work on related changes
106
-
107
- handoff_prompts:
108
- analyst_to_pm: "Existing project analysis complete. Create comprehensive PRD with integration strategy."
109
- pm_to_architect: "PRD ready. Save it as docs/prd.md, then create the integration architecture."
110
- architect_to_po: "Architecture complete. Save it as docs/architecture.md. Please validate all artifacts for integration safety."
111
- po_issues: "PO found issues with [document]. Please return to [agent] to fix and re-save the updated document."
112
- complete: "All planning artifacts validated and saved in docs/ folder. Move to IDE environment to begin development."