bmad-method 4.6.0 → 4.6.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.
- package/CHANGELOG.md +7 -0
- package/bmad-core/templates/architecture-tmpl.md +2 -0
- package/bmad-core/templates/brownfield-architecture-tmpl.md +2 -0
- package/bmad-core/templates/brownfield-prd-tmpl.md +2 -0
- package/bmad-core/templates/competitor-analysis-tmpl.md +2 -0
- package/bmad-core/templates/front-end-architecture-tmpl.md +2 -0
- package/bmad-core/templates/front-end-spec-tmpl.md +2 -0
- package/bmad-core/templates/fullstack-architecture-tmpl.md +2 -0
- package/bmad-core/templates/market-research-tmpl.md +2 -0
- package/bmad-core/templates/prd-tmpl.md +2 -0
- package/bmad-core/templates/project-brief-tmpl.md +2 -0
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +481 -0
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.txt +100 -0
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.txt +100 -0
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +4703 -2876
- package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +35 -0
- package/dist/expansion-packs/expansion-creator/agents/bmad-the-creator.txt +399 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/agent-teams/phaser-2d-nodejs-game-team.yml +1 -0
- package/package.json +1 -1
- package/tools/builders/web-builder.js +189 -20
- package/tools/installer/package.json +1 -1
|
@@ -12,6 +12,11 @@ class WebBuilder {
|
|
|
12
12
|
this.templatePath = path.join(this.rootDir, 'bmad-core', 'templates', 'web-agent-startup-instructions-template.md');
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
parseYaml(content) {
|
|
16
|
+
const yaml = require('js-yaml');
|
|
17
|
+
return yaml.load(content);
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
async cleanOutputDirs() {
|
|
16
21
|
for (const dir of this.outputDirs) {
|
|
17
22
|
try {
|
|
@@ -232,7 +237,7 @@ class WebBuilder {
|
|
|
232
237
|
const agentContent = await fs.readFile(agentPath, 'utf8');
|
|
233
238
|
sections.push(this.formatSection(`agents#${agentName}`, agentContent));
|
|
234
239
|
|
|
235
|
-
// Resolve and add agent dependencies
|
|
240
|
+
// Resolve and add agent dependencies
|
|
236
241
|
const agentYaml = agentContent.match(/```yaml\n([\s\S]*?)\n```/);
|
|
237
242
|
if (agentYaml) {
|
|
238
243
|
try {
|
|
@@ -240,16 +245,43 @@ class WebBuilder {
|
|
|
240
245
|
const agentConfig = yaml.load(agentYaml[1]);
|
|
241
246
|
|
|
242
247
|
if (agentConfig.dependencies) {
|
|
243
|
-
// Add resources
|
|
248
|
+
// Add resources, first try expansion pack, then core
|
|
244
249
|
for (const [resourceType, resources] of Object.entries(agentConfig.dependencies)) {
|
|
245
250
|
if (Array.isArray(resources)) {
|
|
246
251
|
for (const resourceName of resources) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
252
|
+
let found = false;
|
|
253
|
+
const extensions = ['.md', '.yml', '.yaml'];
|
|
254
|
+
|
|
255
|
+
// Try expansion pack first
|
|
256
|
+
for (const ext of extensions) {
|
|
257
|
+
const resourcePath = path.join(packDir, resourceType, `${resourceName}${ext}`);
|
|
258
|
+
try {
|
|
259
|
+
const resourceContent = await fs.readFile(resourcePath, 'utf8');
|
|
260
|
+
sections.push(this.formatSection(`${resourceType}#${resourceName}`, resourceContent));
|
|
261
|
+
found = true;
|
|
262
|
+
break;
|
|
263
|
+
} catch (error) {
|
|
264
|
+
// Not in expansion pack, continue
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// If not found in expansion pack, try core
|
|
269
|
+
if (!found) {
|
|
270
|
+
for (const ext of extensions) {
|
|
271
|
+
const corePath = path.join(this.rootDir, 'bmad-core', resourceType, `${resourceName}${ext}`);
|
|
272
|
+
try {
|
|
273
|
+
const coreContent = await fs.readFile(corePath, 'utf8');
|
|
274
|
+
sections.push(this.formatSection(`${resourceType}#${resourceName}`, coreContent));
|
|
275
|
+
found = true;
|
|
276
|
+
break;
|
|
277
|
+
} catch (error) {
|
|
278
|
+
// Not in core either, continue
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (!found) {
|
|
284
|
+
console.warn(` ⚠ Dependency ${resourceType}#${resourceName} not found in expansion pack or core`);
|
|
253
285
|
}
|
|
254
286
|
}
|
|
255
287
|
}
|
|
@@ -268,32 +300,164 @@ class WebBuilder {
|
|
|
268
300
|
|
|
269
301
|
const sections = [template];
|
|
270
302
|
|
|
271
|
-
// Add team configuration
|
|
303
|
+
// Add team configuration and parse to get agent list
|
|
272
304
|
const teamContent = await fs.readFile(teamConfigPath, 'utf8');
|
|
273
305
|
const teamFileName = path.basename(teamConfigPath, '.yml');
|
|
306
|
+
const teamConfig = this.parseYaml(teamContent);
|
|
274
307
|
sections.push(this.formatSection(`agent-teams#${teamFileName}`, teamContent));
|
|
275
308
|
|
|
276
|
-
//
|
|
277
|
-
const
|
|
278
|
-
const orchestratorContent = await fs.readFile(orchestratorPath, 'utf8');
|
|
279
|
-
sections.push(this.formatSection('agents#bmad-orchestrator', orchestratorContent));
|
|
280
|
-
|
|
281
|
-
// Add expansion pack agents
|
|
309
|
+
// Get list of expansion pack agents
|
|
310
|
+
const expansionAgents = new Set();
|
|
282
311
|
const agentsDir = path.join(packDir, 'agents');
|
|
283
312
|
try {
|
|
284
313
|
const agentFiles = await fs.readdir(agentsDir);
|
|
285
314
|
for (const agentFile of agentFiles.filter(f => f.endsWith('.md'))) {
|
|
286
|
-
const agentPath = path.join(agentsDir, agentFile);
|
|
287
|
-
const agentContent = await fs.readFile(agentPath, 'utf8');
|
|
288
315
|
const agentName = agentFile.replace('.md', '');
|
|
289
|
-
|
|
316
|
+
expansionAgents.add(agentName);
|
|
290
317
|
}
|
|
291
318
|
} catch (error) {
|
|
292
319
|
console.warn(` ⚠ No agents directory found in ${packName}`);
|
|
293
320
|
}
|
|
294
321
|
|
|
295
|
-
//
|
|
322
|
+
// Build a map of all available expansion pack resources for override checking
|
|
323
|
+
const expansionResources = new Map();
|
|
296
324
|
const resourceDirs = ['templates', 'tasks', 'checklists', 'workflows', 'data'];
|
|
325
|
+
for (const resourceDir of resourceDirs) {
|
|
326
|
+
const resourcePath = path.join(packDir, resourceDir);
|
|
327
|
+
try {
|
|
328
|
+
const resourceFiles = await fs.readdir(resourcePath);
|
|
329
|
+
for (const resourceFile of resourceFiles.filter(f => f.endsWith('.md') || f.endsWith('.yml'))) {
|
|
330
|
+
const fileName = resourceFile.replace(/\.(md|yml)$/, '');
|
|
331
|
+
expansionResources.set(`${resourceDir}#${fileName}`, true);
|
|
332
|
+
}
|
|
333
|
+
} catch (error) {
|
|
334
|
+
// Directory might not exist, that's fine
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Process all agents listed in team configuration
|
|
339
|
+
const agentsToProcess = teamConfig.agents || [];
|
|
340
|
+
|
|
341
|
+
// Ensure bmad-orchestrator is always included for teams
|
|
342
|
+
if (!agentsToProcess.includes('bmad-orchestrator')) {
|
|
343
|
+
console.warn(` ⚠ Team ${teamFileName} missing bmad-orchestrator, adding automatically`);
|
|
344
|
+
agentsToProcess.unshift('bmad-orchestrator');
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Track all dependencies from all agents (deduplicated)
|
|
348
|
+
const allDependencies = new Map();
|
|
349
|
+
|
|
350
|
+
for (const agentId of agentsToProcess) {
|
|
351
|
+
|
|
352
|
+
if (expansionAgents.has(agentId)) {
|
|
353
|
+
// Use expansion pack version (override)
|
|
354
|
+
const agentPath = path.join(agentsDir, `${agentId}.md`);
|
|
355
|
+
const agentContent = await fs.readFile(agentPath, 'utf8');
|
|
356
|
+
sections.push(this.formatSection(`agents#${agentId}`, agentContent));
|
|
357
|
+
|
|
358
|
+
// Parse and collect dependencies from expansion agent
|
|
359
|
+
const agentYaml = agentContent.match(/```yaml\n([\s\S]*?)\n```/);
|
|
360
|
+
if (agentYaml) {
|
|
361
|
+
try {
|
|
362
|
+
const agentConfig = this.parseYaml(agentYaml[1]);
|
|
363
|
+
if (agentConfig.dependencies) {
|
|
364
|
+
for (const [resourceType, resources] of Object.entries(agentConfig.dependencies)) {
|
|
365
|
+
if (Array.isArray(resources)) {
|
|
366
|
+
for (const resourceName of resources) {
|
|
367
|
+
const key = `${resourceType}#${resourceName}`;
|
|
368
|
+
if (!allDependencies.has(key)) {
|
|
369
|
+
allDependencies.set(key, { type: resourceType, name: resourceName });
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
} catch (error) {
|
|
376
|
+
console.debug(`Failed to parse agent YAML for ${agentId}:`, error.message);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
// Use core BMAD version
|
|
381
|
+
try {
|
|
382
|
+
const coreAgentPath = path.join(this.rootDir, 'bmad-core', 'agents', `${agentId}.md`);
|
|
383
|
+
const coreAgentContent = await fs.readFile(coreAgentPath, 'utf8');
|
|
384
|
+
sections.push(this.formatSection(`agents#${agentId}`, coreAgentContent));
|
|
385
|
+
|
|
386
|
+
// Parse and collect dependencies from core agent
|
|
387
|
+
const agentYaml = coreAgentContent.match(/```yaml\n([\s\S]*?)\n```/);
|
|
388
|
+
if (agentYaml) {
|
|
389
|
+
try {
|
|
390
|
+
// Clean up the YAML to handle command descriptions after dashes
|
|
391
|
+
let yamlContent = agentYaml[1];
|
|
392
|
+
yamlContent = yamlContent.replace(/^(\s*-)(\s*"[^"]+")(\s*-\s*.*)$/gm, '$1$2');
|
|
393
|
+
|
|
394
|
+
const agentConfig = this.parseYaml(yamlContent);
|
|
395
|
+
if (agentConfig.dependencies) {
|
|
396
|
+
for (const [resourceType, resources] of Object.entries(agentConfig.dependencies)) {
|
|
397
|
+
if (Array.isArray(resources)) {
|
|
398
|
+
for (const resourceName of resources) {
|
|
399
|
+
const key = `${resourceType}#${resourceName}`;
|
|
400
|
+
if (!allDependencies.has(key)) {
|
|
401
|
+
allDependencies.set(key, { type: resourceType, name: resourceName });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
} catch (error) {
|
|
408
|
+
console.debug(`Failed to parse agent YAML for ${agentId}:`, error.message);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
} catch (error) {
|
|
412
|
+
console.warn(` ⚠ Agent ${agentId} not found in core or expansion pack`);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Add all collected dependencies from agents
|
|
418
|
+
// Always prefer expansion pack versions if they exist
|
|
419
|
+
for (const [key, dep] of allDependencies) {
|
|
420
|
+
let found = false;
|
|
421
|
+
const extensions = ['.md', '.yml', '.yaml'];
|
|
422
|
+
|
|
423
|
+
// Always check expansion pack first, even if the dependency came from a core agent
|
|
424
|
+
if (expansionResources.has(key)) {
|
|
425
|
+
// We know it exists in expansion pack, find and load it
|
|
426
|
+
for (const ext of extensions) {
|
|
427
|
+
const expansionPath = path.join(packDir, dep.type, `${dep.name}${ext}`);
|
|
428
|
+
try {
|
|
429
|
+
const content = await fs.readFile(expansionPath, 'utf8');
|
|
430
|
+
sections.push(this.formatSection(key, content));
|
|
431
|
+
console.log(` ✓ Using expansion override for ${key}`);
|
|
432
|
+
found = true;
|
|
433
|
+
break;
|
|
434
|
+
} catch (error) {
|
|
435
|
+
// Try next extension
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// If not found in expansion pack (or doesn't exist there), try core
|
|
441
|
+
if (!found) {
|
|
442
|
+
for (const ext of extensions) {
|
|
443
|
+
const corePath = path.join(this.rootDir, 'bmad-core', dep.type, `${dep.name}${ext}`);
|
|
444
|
+
try {
|
|
445
|
+
const content = await fs.readFile(corePath, 'utf8');
|
|
446
|
+
sections.push(this.formatSection(key, content));
|
|
447
|
+
found = true;
|
|
448
|
+
break;
|
|
449
|
+
} catch (error) {
|
|
450
|
+
// Not in core either, continue
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (!found) {
|
|
456
|
+
console.warn(` ⚠ Dependency ${key} not found in expansion pack or core`);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Add remaining expansion pack resources not already included as dependencies
|
|
297
461
|
for (const resourceDir of resourceDirs) {
|
|
298
462
|
const resourcePath = path.join(packDir, resourceDir);
|
|
299
463
|
try {
|
|
@@ -302,7 +466,12 @@ class WebBuilder {
|
|
|
302
466
|
const filePath = path.join(resourcePath, resourceFile);
|
|
303
467
|
const fileContent = await fs.readFile(filePath, 'utf8');
|
|
304
468
|
const fileName = resourceFile.replace(/\.(md|yml)$/, '');
|
|
305
|
-
|
|
469
|
+
|
|
470
|
+
// Only add if not already included as a dependency
|
|
471
|
+
const resourceKey = `${resourceDir}#${fileName}`;
|
|
472
|
+
if (!allDependencies.has(resourceKey)) {
|
|
473
|
+
sections.push(this.formatSection(resourceKey, fileContent));
|
|
474
|
+
}
|
|
306
475
|
}
|
|
307
476
|
} catch (error) {
|
|
308
477
|
// Directory might not exist, that's fine
|