bmad-method 4.24.0 → 4.24.2

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 (78) hide show
  1. package/.vscode/settings.json +11 -5
  2. package/CHANGELOG.md +17 -1
  3. package/README.md +1 -1
  4. package/bmad-core/agents/bmad-master.md +1 -1
  5. package/bmad-core/agents/dev.md +2 -2
  6. package/bmad-core/agents/pm.md +1 -1
  7. package/bmad-core/agents/po.md +1 -1
  8. package/bmad-core/{core-config.yml → core-config.yaml} +1 -1
  9. package/bmad-core/data/bmad-kb.md +4 -4
  10. package/bmad-core/tasks/create-brownfield-story.md +1 -1
  11. package/bmad-core/tasks/create-next-story.md +4 -4
  12. package/bmad-core/tasks/shard-doc.md +3 -3
  13. package/bmad-core/tasks/update-workflow-plan.md +1 -1
  14. package/bmad-core/templates/architecture-tmpl.md +1 -1
  15. package/bmad-core/templates/fullstack-architecture-tmpl.md +3 -3
  16. package/bmad-core/utils/plan-management.md +1 -1
  17. package/common/tasks/create-doc.md +1 -1
  18. package/dist/agents/analyst.txt +5 -5
  19. package/dist/agents/architect.txt +5 -5
  20. package/dist/agents/bmad-master.txt +18 -18
  21. package/dist/agents/bmad-orchestrator.txt +7 -7
  22. package/dist/agents/dev.txt +1 -1
  23. package/dist/agents/pm.txt +4 -4
  24. package/dist/agents/po.txt +3 -3
  25. package/dist/agents/sm.txt +4 -4
  26. package/dist/agents/ux-expert.txt +1 -1
  27. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +1 -1
  28. package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +3 -3
  29. package/dist/expansion-packs/bmad-creator-tools/agents/bmad-the-creator.txt +10 -10
  30. package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +2 -2
  31. package/dist/teams/team-all.txt +19 -19
  32. package/dist/teams/team-fullstack.txt +14 -14
  33. package/dist/teams/team-ide-minimal.txt +15 -15
  34. package/dist/teams/team-no-ui.txt +14 -14
  35. package/docs/agentic-tools/roo-code-guide.md +1 -1
  36. package/docs/core-architecture.md +12 -12
  37. package/docs/user-guide.md +6 -6
  38. package/expansion-packs/bmad-2d-phaser-game-dev/{config.yml → config.yaml} +1 -1
  39. package/expansion-packs/bmad-creator-tools/{config.yml → config.yaml} +1 -1
  40. package/expansion-packs/bmad-creator-tools/tasks/generate-expansion-pack.md +9 -9
  41. package/expansion-packs/bmad-creator-tools/templates/agent-teams-tmpl.md +1 -1
  42. package/expansion-packs/bmad-creator-tools/templates/agent-tmpl.md +1 -1
  43. package/expansion-packs/bmad-infrastructure-devops/README.md +3 -3
  44. package/expansion-packs/bmad-infrastructure-devops/{config.yml → config.yaml} +1 -1
  45. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.md +0 -0
  46. package/package.json +1 -1
  47. package/tools/builders/web-builder.js +19 -20
  48. package/tools/bump-all-versions.js +2 -2
  49. package/tools/bump-core-version.js +1 -1
  50. package/tools/bump-expansion-version.js +1 -1
  51. package/tools/installer/README.md +1 -1
  52. package/tools/installer/bin/bmad.js +2 -2
  53. package/tools/installer/lib/config-loader.js +13 -12
  54. package/tools/installer/lib/file-manager.js +5 -5
  55. package/tools/installer/lib/ide-setup.js +14 -13
  56. package/tools/installer/lib/installer.js +24 -26
  57. package/tools/installer/package.json +1 -1
  58. package/tools/lib/dependency-resolver.js +8 -12
  59. package/tools/lib/yaml-utils.js +29 -0
  60. package/tools/update-expansion-version.js +3 -3
  61. package/tools/yaml-format.js +1 -1
  62. /package/.github/{FUNDING.yml → FUNDING.yaml} +0 -0
  63. /package/.github/workflows/{release.yml → release.yaml} +0 -0
  64. /package/bmad-core/agent-teams/{team-all.yml → team-all.yaml} +0 -0
  65. /package/bmad-core/agent-teams/{team-fullstack.yml → team-fullstack.yaml} +0 -0
  66. /package/bmad-core/agent-teams/{team-ide-minimal.yml → team-ide-minimal.yaml} +0 -0
  67. /package/bmad-core/agent-teams/{team-no-ui.yml → team-no-ui.yaml} +0 -0
  68. /package/bmad-core/workflows/{brownfield-fullstack.yml → brownfield-fullstack.yaml} +0 -0
  69. /package/bmad-core/workflows/{brownfield-service.yml → brownfield-service.yaml} +0 -0
  70. /package/bmad-core/workflows/{brownfield-ui.yml → brownfield-ui.yaml} +0 -0
  71. /package/bmad-core/workflows/{greenfield-fullstack.yml → greenfield-fullstack.yaml} +0 -0
  72. /package/bmad-core/workflows/{greenfield-service.yml → greenfield-service.yaml} +0 -0
  73. /package/bmad-core/workflows/{greenfield-ui.yml → greenfield-ui.yaml} +0 -0
  74. /package/expansion-packs/bmad-2d-phaser-game-dev/agent-teams/{phaser-2d-nodejs-game-team.yml → phaser-2d-nodejs-game-team.yaml} +0 -0
  75. /package/expansion-packs/bmad-2d-phaser-game-dev/workflows/{game-dev-greenfield.yml → game-dev-greenfield.yaml} +0 -0
  76. /package/expansion-packs/bmad-2d-phaser-game-dev/workflows/{game-prototype.yml → game-prototype.yaml} +0 -0
  77. /package/tools/installer/config/{ide-agent-config.yml → ide-agent-config.yaml} +0 -0
  78. /package/tools/installer/config/{install.config.yml → install.config.yaml} +0 -0
@@ -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);
@@ -1009,7 +1010,7 @@ class Installer {
1009
1010
 
1010
1011
  // Check if expansion pack already exists
1011
1012
  let expansionDotFolder = path.join(installDir, `.${packId}`);
1012
- const existingManifestPath = path.join(expansionDotFolder, 'install-manifest.yml');
1013
+ const existingManifestPath = path.join(expansionDotFolder, 'install-manifest.yaml');
1013
1014
 
1014
1015
  if (await fileManager.pathExists(existingManifestPath)) {
1015
1016
  spinner.stop();
@@ -1151,12 +1152,12 @@ class Installer {
1151
1152
  }
1152
1153
  }
1153
1154
 
1154
- // Copy config.yml
1155
- const configPath = path.join(expansionPackDir, 'config.yml');
1155
+ // Copy config.yaml
1156
+ const configPath = path.join(expansionPackDir, 'config.yaml');
1156
1157
  if (await fileManager.pathExists(configPath)) {
1157
- const configDestPath = path.join(expansionDotFolder, 'config.yml');
1158
+ const configDestPath = path.join(expansionDotFolder, 'config.yaml');
1158
1159
  if (await fileManager.copyFile(configPath, configDestPath)) {
1159
- installedFiles.push(path.join(`.${packId}`, 'config.yml'));
1160
+ installedFiles.push(path.join(`.${packId}`, 'config.yaml'));
1160
1161
  }
1161
1162
  }
1162
1163
 
@@ -1222,10 +1223,10 @@ class Installer {
1222
1223
  const agentContent = await fs.readFile(agentPath, 'utf8');
1223
1224
 
1224
1225
  // Extract YAML frontmatter to check dependencies
1225
- const yamlMatch = agentContent.match(/```yaml\n([\s\S]*?)```/);
1226
- if (yamlMatch) {
1226
+ const yamlContent = extractYamlFromAgent(agentContent);
1227
+ if (yamlContent) {
1227
1228
  try {
1228
- const agentConfig = yaml.parse(yamlMatch[1]);
1229
+ const agentConfig = yaml.parse(yamlContent);
1229
1230
  const dependencies = agentConfig.dependencies || {};
1230
1231
 
1231
1232
  // Check for core dependencies (those that don't exist in the expansion pack)
@@ -1268,7 +1269,7 @@ class Installer {
1268
1269
  const fs = require('fs').promises;
1269
1270
 
1270
1271
  // Find all team files in the expansion pack
1271
- const teamFiles = glob.sync('agent-teams/*.yml', {
1272
+ const teamFiles = glob.sync('agent-teams/*.yaml', {
1272
1273
  cwd: expansionDotFolder
1273
1274
  });
1274
1275
 
@@ -1314,13 +1315,10 @@ class Installer {
1314
1315
 
1315
1316
  // Now resolve this agent's dependencies too
1316
1317
  const agentContent = await fs.readFile(coreAgentPath, 'utf8');
1317
- const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
1318
+ const yamlContent = extractYamlFromAgent(agentContent, true);
1318
1319
 
1319
- if (yamlMatch) {
1320
+ if (yamlContent) {
1320
1321
  try {
1321
- // Clean up the YAML to handle command descriptions
1322
- let yamlContent = yamlMatch[1];
1323
- yamlContent = yamlContent.replace(/^(\s*-)(\s*"[^"]+")(\s*-\s*.*)$/gm, '$1$2');
1324
1322
 
1325
1323
  const agentConfig = yaml.parse(yamlContent);
1326
1324
  const dependencies = agentConfig.dependencies || {};
@@ -1330,7 +1328,7 @@ class Installer {
1330
1328
  const deps = dependencies[depType] || [];
1331
1329
 
1332
1330
  for (const dep of deps) {
1333
- const depFileName = dep.endsWith('.md') || dep.endsWith('.yml') ? dep : `${dep}.md`;
1331
+ const depFileName = dep.endsWith('.md') || dep.endsWith('.yaml') ? dep : `${dep}.md`;
1334
1332
  const expansionDepPath = path.join(expansionDotFolder, depType, depFileName);
1335
1333
 
1336
1334
  // Check if dependency exists in expansion pack
@@ -1360,7 +1358,7 @@ class Installer {
1360
1358
  }
1361
1359
  }
1362
1360
  } else {
1363
- 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')}`));
1364
1362
  }
1365
1363
  }
1366
1364
  }
@@ -1528,7 +1526,7 @@ class Installer {
1528
1526
 
1529
1527
  if (stats) {
1530
1528
  // Check if it has a manifest
1531
- const manifestPath = path.join(folderPath, "install-manifest.yml");
1529
+ const manifestPath = path.join(folderPath, "install-manifest.yaml");
1532
1530
  if (await fileManager.pathExists(manifestPath)) {
1533
1531
  const manifest = await fileManager.readExpansionPackManifest(installDir, folder.substring(1));
1534
1532
  if (manifest) {
@@ -1539,8 +1537,8 @@ class Installer {
1539
1537
  };
1540
1538
  }
1541
1539
  } else {
1542
- // Check if it has a config.yml (expansion pack without manifest)
1543
- 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");
1544
1542
  if (await fileManager.pathExists(configPath)) {
1545
1543
  expansionPacks[folder.substring(1)] = {
1546
1544
  path: folderPath,
@@ -1579,7 +1577,7 @@ class Installer {
1579
1577
 
1580
1578
  for (const file of filesToRestore) {
1581
1579
  // Skip the manifest file itself
1582
- if (file.endsWith('install-manifest.yml')) continue;
1580
+ if (file.endsWith('install-manifest.yaml')) continue;
1583
1581
 
1584
1582
  const relativePath = file.replace(`.${packId}/`, '');
1585
1583
  const sourcePath = path.join(pack.packPath, relativePath);
@@ -1645,7 +1643,7 @@ class Installer {
1645
1643
 
1646
1644
  while (currentDir !== path.dirname(currentDir)) {
1647
1645
  const bmadDir = path.join(currentDir, ".bmad-core");
1648
- const manifestPath = path.join(bmadDir, "install-manifest.yml");
1646
+ const manifestPath = path.join(bmadDir, "install-manifest.yaml");
1649
1647
 
1650
1648
  if (await fileManager.pathExists(manifestPath)) {
1651
1649
  return bmadDir;
@@ -1656,7 +1654,7 @@ class Installer {
1656
1654
 
1657
1655
  // Also check if we're inside a .bmad-core directory
1658
1656
  if (path.basename(process.cwd()) === ".bmad-core") {
1659
- const manifestPath = path.join(process.cwd(), "install-manifest.yml");
1657
+ const manifestPath = path.join(process.cwd(), "install-manifest.yaml");
1660
1658
  if (await fileManager.pathExists(manifestPath)) {
1661
1659
  return process.cwd();
1662
1660
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bmad-method",
3
- "version": "4.24.0",
3
+ "version": "4.24.2",
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.replace(/\r/g, "").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,8 +179,8 @@ 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
  }
@@ -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
 
File without changes
File without changes