bmad-method 6.2.1-next.36 → 6.2.1-next.37
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/package.json +1 -1
- package/src/bmm-skills/1-analysis/bmad-agent-analyst/bmad-skill-manifest.yaml +1 -1
- package/src/bmm-skills/1-analysis/bmad-agent-tech-writer/bmad-skill-manifest.yaml +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-agent-pm/bmad-skill-manifest.yaml +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/bmad-skill-manifest.yaml +1 -1
- package/src/bmm-skills/3-solutioning/bmad-agent-architect/bmad-skill-manifest.yaml +1 -1
- package/src/bmm-skills/4-implementation/bmad-agent-dev/bmad-skill-manifest.yaml +1 -1
- package/src/bmm-skills/4-implementation/bmad-agent-qa/bmad-skill-manifest.yaml +1 -1
- package/src/bmm-skills/4-implementation/bmad-agent-quick-flow-solo-dev/bmad-skill-manifest.yaml +1 -1
- package/src/bmm-skills/4-implementation/bmad-agent-sm/bmad-skill-manifest.yaml +1 -1
- package/tools/bmad-npx-wrapper.js +2 -2
- package/tools/cli/installers/lib/core/manifest-generator.js +65 -115
- package/tools/cli/installers/lib/ide/shared/bmad-artifacts.js +27 -0
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* This file ensures proper execution when run via npx from GitHub or npm registry
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const {
|
|
8
|
+
const { execFileSync } = require('node:child_process');
|
|
9
9
|
const path = require('node:path');
|
|
10
10
|
const fs = require('node:fs');
|
|
11
11
|
|
|
@@ -25,7 +25,7 @@ if (isNpxExecution) {
|
|
|
25
25
|
|
|
26
26
|
try {
|
|
27
27
|
// Execute CLI from user's working directory (process.cwd()), not npm cache
|
|
28
|
-
|
|
28
|
+
execFileSync('node', [bmadCliPath, ...args], {
|
|
29
29
|
stdio: 'inherit',
|
|
30
30
|
cwd: process.cwd(), // This preserves the user's working directory
|
|
31
31
|
});
|
|
@@ -268,153 +268,103 @@ class ManifestGenerator {
|
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
/**
|
|
271
|
-
* Collect all agents from
|
|
272
|
-
* Scans the INSTALLED bmad directory, not the source
|
|
271
|
+
* Collect all agents from selected modules by walking their directory trees.
|
|
273
272
|
*/
|
|
274
273
|
async collectAgents(selectedModules) {
|
|
275
274
|
this.agents = [];
|
|
275
|
+
const debug = process.env.BMAD_DEBUG_MANIFEST === 'true';
|
|
276
276
|
|
|
277
|
-
//
|
|
277
|
+
// Walk each module's full directory tree looking for type:agent manifests
|
|
278
278
|
for (const moduleName of this.updatedModules) {
|
|
279
|
-
const
|
|
279
|
+
const modulePath = path.join(this.bmadDir, moduleName);
|
|
280
|
+
if (!(await fs.pathExists(modulePath))) continue;
|
|
280
281
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
this.agents.push(...moduleAgents);
|
|
284
|
-
}
|
|
282
|
+
const moduleAgents = await this.getAgentsFromDirRecursive(modulePath, moduleName, '', debug);
|
|
283
|
+
this.agents.push(...moduleAgents);
|
|
285
284
|
}
|
|
286
285
|
|
|
287
286
|
// Get standalone agents from bmad/agents/ directory
|
|
288
287
|
const standaloneAgentsDir = path.join(this.bmadDir, 'agents');
|
|
289
288
|
if (await fs.pathExists(standaloneAgentsDir)) {
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
if (!agentDir.isDirectory()) continue;
|
|
289
|
+
const standaloneAgents = await this.getAgentsFromDirRecursive(standaloneAgentsDir, 'standalone', '', debug);
|
|
290
|
+
this.agents.push(...standaloneAgents);
|
|
291
|
+
}
|
|
294
292
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
this.agents.push(...standaloneAgents);
|
|
298
|
-
}
|
|
293
|
+
if (debug) {
|
|
294
|
+
console.log(`[DEBUG] collectAgents: total agents found: ${this.agents.length}`);
|
|
299
295
|
}
|
|
300
296
|
}
|
|
301
297
|
|
|
302
298
|
/**
|
|
303
|
-
*
|
|
304
|
-
*
|
|
299
|
+
* Recursively walk a directory tree collecting agents.
|
|
300
|
+
* Discovers agents via directory with bmad-skill-manifest.yaml containing type: agent
|
|
301
|
+
*
|
|
302
|
+
* @param {string} dirPath - Current directory being scanned
|
|
303
|
+
* @param {string} moduleName - Module this directory belongs to
|
|
304
|
+
* @param {string} relativePath - Path relative to the module root (for install path construction)
|
|
305
|
+
* @param {boolean} debug - Emit debug messages
|
|
305
306
|
*/
|
|
306
|
-
async
|
|
307
|
-
// Skip directories claimed by collectSkills
|
|
308
|
-
if (this.skillClaimedDirs && this.skillClaimedDirs.has(dirPath)) return [];
|
|
307
|
+
async getAgentsFromDirRecursive(dirPath, moduleName, relativePath = '', debug = false) {
|
|
309
308
|
const agents = [];
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
309
|
+
let entries;
|
|
310
|
+
try {
|
|
311
|
+
entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
312
|
+
} catch {
|
|
313
|
+
return agents;
|
|
314
|
+
}
|
|
313
315
|
|
|
314
316
|
for (const entry of entries) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if (entry.isDirectory()) {
|
|
318
|
-
// Check for new-format agent: bmad-skill-manifest.yaml with type: agent
|
|
319
|
-
// Note: type:agent dirs may also be claimed by collectSkills for IDE installation,
|
|
320
|
-
// but we still need to process them here for agent-manifest.csv
|
|
321
|
-
const dirManifest = await this.loadSkillManifest(fullPath);
|
|
322
|
-
if (dirManifest && dirManifest.__single && dirManifest.__single.type === 'agent') {
|
|
323
|
-
const m = dirManifest.__single;
|
|
324
|
-
const dirRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
325
|
-
const installPath =
|
|
326
|
-
moduleName === 'core'
|
|
327
|
-
? `${this.bmadFolderName}/core/agents/${dirRelativePath}`
|
|
328
|
-
: `${this.bmadFolderName}/${moduleName}/agents/${dirRelativePath}`;
|
|
329
|
-
|
|
330
|
-
agents.push({
|
|
331
|
-
name: m.name || entry.name,
|
|
332
|
-
displayName: m.displayName || m.name || entry.name,
|
|
333
|
-
title: m.title || '',
|
|
334
|
-
icon: m.icon || '',
|
|
335
|
-
capabilities: m.capabilities ? this.cleanForCSV(m.capabilities) : '',
|
|
336
|
-
role: m.role ? this.cleanForCSV(m.role) : '',
|
|
337
|
-
identity: m.identity ? this.cleanForCSV(m.identity) : '',
|
|
338
|
-
communicationStyle: m.communicationStyle ? this.cleanForCSV(m.communicationStyle) : '',
|
|
339
|
-
principles: m.principles ? this.cleanForCSV(m.principles) : '',
|
|
340
|
-
module: m.module || moduleName,
|
|
341
|
-
path: installPath,
|
|
342
|
-
canonicalId: m.canonicalId || '',
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
this.files.push({
|
|
346
|
-
type: 'agent',
|
|
347
|
-
name: m.name || entry.name,
|
|
348
|
-
module: moduleName,
|
|
349
|
-
path: installPath,
|
|
350
|
-
});
|
|
351
|
-
continue;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Skip directories claimed by collectSkills (non-agent type skills)
|
|
355
|
-
if (this.skillClaimedDirs && this.skillClaimedDirs.has(fullPath)) continue;
|
|
356
|
-
|
|
357
|
-
// Recurse into subdirectories
|
|
358
|
-
const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
359
|
-
const subDirAgents = await this.getAgentsFromDir(fullPath, moduleName, newRelativePath);
|
|
360
|
-
agents.push(...subDirAgents);
|
|
361
|
-
} else if (entry.name.endsWith('.md') && entry.name.toLowerCase() !== 'readme.md') {
|
|
362
|
-
const content = await fs.readFile(fullPath, 'utf8');
|
|
363
|
-
|
|
364
|
-
// Skip files that don't contain <agent> tag (e.g., README files)
|
|
365
|
-
if (!content.includes('<agent')) {
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// Skip web-only agents
|
|
370
|
-
if (content.includes('localskip="true"')) {
|
|
371
|
-
continue;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// Extract agent metadata from the XML structure
|
|
375
|
-
const nameMatch = content.match(/name="([^"]+)"/);
|
|
376
|
-
const titleMatch = content.match(/title="([^"]+)"/);
|
|
377
|
-
const iconMatch = content.match(/icon="([^"]+)"/);
|
|
378
|
-
const capabilitiesMatch = content.match(/capabilities="([^"]+)"/);
|
|
379
|
-
|
|
380
|
-
// Extract persona fields
|
|
381
|
-
const roleMatch = content.match(/<role>([^<]+)<\/role>/);
|
|
382
|
-
const identityMatch = content.match(/<identity>([\s\S]*?)<\/identity>/);
|
|
383
|
-
const styleMatch = content.match(/<communication_style>([\s\S]*?)<\/communication_style>/);
|
|
384
|
-
const principlesMatch = content.match(/<principles>([\s\S]*?)<\/principles>/);
|
|
317
|
+
if (!entry.isDirectory()) continue;
|
|
318
|
+
if (entry.name.startsWith('.') || entry.name.startsWith('_')) continue;
|
|
385
319
|
|
|
386
|
-
|
|
387
|
-
const fileRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
388
|
-
const installPath =
|
|
389
|
-
moduleName === 'core'
|
|
390
|
-
? `${this.bmadFolderName}/core/agents/${fileRelativePath}`
|
|
391
|
-
: `${this.bmadFolderName}/${moduleName}/agents/${fileRelativePath}`;
|
|
320
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
392
321
|
|
|
393
|
-
|
|
322
|
+
// Check for type:agent manifest BEFORE checking skillClaimedDirs —
|
|
323
|
+
// agent dirs may be claimed by collectSkills for IDE installation,
|
|
324
|
+
// but we still need them in agent-manifest.csv.
|
|
325
|
+
const dirManifest = await this.loadSkillManifest(fullPath);
|
|
326
|
+
if (dirManifest && dirManifest.__single && dirManifest.__single.type === 'agent') {
|
|
327
|
+
const m = dirManifest.__single;
|
|
328
|
+
const dirRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
329
|
+
const agentModule = m.module || moduleName;
|
|
330
|
+
const installPath = `${this.bmadFolderName}/${agentModule}/${dirRelativePath}`;
|
|
394
331
|
|
|
395
332
|
agents.push({
|
|
396
|
-
name:
|
|
397
|
-
displayName:
|
|
398
|
-
title:
|
|
399
|
-
icon:
|
|
400
|
-
capabilities:
|
|
401
|
-
role:
|
|
402
|
-
identity:
|
|
403
|
-
communicationStyle:
|
|
404
|
-
principles:
|
|
405
|
-
module:
|
|
333
|
+
name: m.name || entry.name,
|
|
334
|
+
displayName: m.displayName || m.name || entry.name,
|
|
335
|
+
title: m.title || '',
|
|
336
|
+
icon: m.icon || '',
|
|
337
|
+
capabilities: m.capabilities ? this.cleanForCSV(m.capabilities) : '',
|
|
338
|
+
role: m.role ? this.cleanForCSV(m.role) : '',
|
|
339
|
+
identity: m.identity ? this.cleanForCSV(m.identity) : '',
|
|
340
|
+
communicationStyle: m.communicationStyle ? this.cleanForCSV(m.communicationStyle) : '',
|
|
341
|
+
principles: m.principles ? this.cleanForCSV(m.principles) : '',
|
|
342
|
+
module: agentModule,
|
|
406
343
|
path: installPath,
|
|
407
|
-
canonicalId:
|
|
344
|
+
canonicalId: m.canonicalId || '',
|
|
408
345
|
});
|
|
409
346
|
|
|
410
|
-
// Add to files list
|
|
411
347
|
this.files.push({
|
|
412
348
|
type: 'agent',
|
|
413
|
-
name:
|
|
414
|
-
module:
|
|
349
|
+
name: m.name || entry.name,
|
|
350
|
+
module: agentModule,
|
|
415
351
|
path: installPath,
|
|
416
352
|
});
|
|
353
|
+
|
|
354
|
+
if (debug) {
|
|
355
|
+
console.log(`[DEBUG] collectAgents: found type:agent "${m.name || entry.name}" at ${fullPath}`);
|
|
356
|
+
}
|
|
357
|
+
continue;
|
|
417
358
|
}
|
|
359
|
+
|
|
360
|
+
// Skip directories claimed by collectSkills (non-agent type skills) —
|
|
361
|
+
// avoids recursing into skill trees that can't contain agents.
|
|
362
|
+
if (this.skillClaimedDirs && this.skillClaimedDirs.has(fullPath)) continue;
|
|
363
|
+
|
|
364
|
+
// Recurse into subdirectories
|
|
365
|
+
const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
366
|
+
const subDirAgents = await this.getAgentsFromDirRecursive(fullPath, moduleName, newRelativePath, debug);
|
|
367
|
+
agents.push(...subDirAgents);
|
|
418
368
|
}
|
|
419
369
|
|
|
420
370
|
return agents;
|
|
@@ -5,6 +5,33 @@ const { loadSkillManifest, getCanonicalId } = require('./skill-manifest');
|
|
|
5
5
|
/**
|
|
6
6
|
* Helpers for gathering BMAD agents/tasks from the installed tree.
|
|
7
7
|
* Shared by installers that need Claude-style exports.
|
|
8
|
+
*
|
|
9
|
+
* TODO: Dead code cleanup — compiled XML agents are retired.
|
|
10
|
+
*
|
|
11
|
+
* All agents now use the SKILL.md directory format with bmad-skill-manifest.yaml
|
|
12
|
+
* (type: agent). The legacy pipeline below only discovers compiled .md files
|
|
13
|
+
* containing <agent> XML tags, which no longer exist. The following are dead:
|
|
14
|
+
*
|
|
15
|
+
* - getAgentsFromBmad() — scans {module}/agents/ for .md files with <agent> tags
|
|
16
|
+
* - getAgentsFromDir() — recursive helper for the above
|
|
17
|
+
* - AgentCommandGenerator — (agent-command-generator.js) generates launcher .md files
|
|
18
|
+
* that tell the LLM to load a compiled agent .md file
|
|
19
|
+
* - agent-command-template.md — (templates/) the launcher template with hardcoded
|
|
20
|
+
* {module}/agents/{{path}} reference
|
|
21
|
+
*
|
|
22
|
+
* Agent metadata for agent-manifest.csv is now handled entirely by
|
|
23
|
+
* ManifestGenerator.getAgentsFromDirRecursive() in manifest-generator.js,
|
|
24
|
+
* which walks the full module tree and finds type:agent directories.
|
|
25
|
+
*
|
|
26
|
+
* IDE installation of agents is handled by the native skill pipeline —
|
|
27
|
+
* each agent's SKILL.md directory is installed directly to the IDE's
|
|
28
|
+
* skills path, so no launcher intermediary is needed.
|
|
29
|
+
*
|
|
30
|
+
* Cleanup: remove getAgentsFromBmad, getAgentsFromDir, their exports,
|
|
31
|
+
* AgentCommandGenerator, agent-command-template.md, and all call sites
|
|
32
|
+
* in IDE installers that invoke collectAgentArtifacts / writeAgentLaunchers /
|
|
33
|
+
* writeColonArtifacts / writeDashArtifacts.
|
|
34
|
+
* getTasksFromBmad and getTasksFromDir may still be live — verify before removing.
|
|
8
35
|
*/
|
|
9
36
|
async function getAgentsFromBmad(bmadDir, selectedModules = []) {
|
|
10
37
|
const agents = [];
|