bmad-method 6.2.1-next.35 → 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/config-collector.js +110 -23
- 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
|
});
|
|
@@ -954,29 +954,121 @@ class ConfigCollector {
|
|
|
954
954
|
return match;
|
|
955
955
|
}
|
|
956
956
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
957
|
+
const configValue = this.resolveConfigValue(configKey, currentModule, moduleConfig);
|
|
958
|
+
|
|
959
|
+
return configValue || match;
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Clean a stored path-like value for prompt display/input reuse.
|
|
965
|
+
* @param {*} value - Stored value
|
|
966
|
+
* @returns {*} Cleaned value
|
|
967
|
+
*/
|
|
968
|
+
cleanPromptValue(value) {
|
|
969
|
+
if (typeof value === 'string' && value.startsWith('{project-root}/')) {
|
|
970
|
+
return value.replace('{project-root}/', '');
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
return value;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* Resolve a config key from answers, collected config, existing config, or schema defaults.
|
|
978
|
+
* @param {string} configKey - Config key to resolve
|
|
979
|
+
* @param {string} currentModule - Current module name
|
|
980
|
+
* @param {Object} moduleConfig - Current module config schema
|
|
981
|
+
* @returns {*} Resolved value
|
|
982
|
+
*/
|
|
983
|
+
resolveConfigValue(configKey, currentModule = null, moduleConfig = null) {
|
|
984
|
+
// Look for the config value in allAnswers (already answered questions)
|
|
985
|
+
let configValue = this.allAnswers?.[configKey] || this.allAnswers?.[`core_${configKey}`];
|
|
986
|
+
|
|
987
|
+
if (!configValue && this.allAnswers) {
|
|
988
|
+
for (const [answerKey, answerValue] of Object.entries(this.allAnswers)) {
|
|
989
|
+
if (answerKey.endsWith(`_${configKey}`)) {
|
|
990
|
+
configValue = answerValue;
|
|
991
|
+
break;
|
|
967
992
|
}
|
|
968
993
|
}
|
|
994
|
+
}
|
|
969
995
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
996
|
+
// Prefer the current module's persisted value when re-prompting an existing install
|
|
997
|
+
if (!configValue && currentModule && this.existingConfig?.[currentModule]?.[configKey] !== undefined) {
|
|
998
|
+
configValue = this.existingConfig[currentModule][configKey];
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// Check in already collected config
|
|
1002
|
+
if (!configValue) {
|
|
1003
|
+
for (const mod of Object.keys(this.collectedConfig)) {
|
|
1004
|
+
if (mod !== '_meta' && this.collectedConfig[mod] && this.collectedConfig[mod][configKey]) {
|
|
1005
|
+
configValue = this.collectedConfig[mod][configKey];
|
|
1006
|
+
break;
|
|
975
1007
|
}
|
|
976
1008
|
}
|
|
1009
|
+
}
|
|
977
1010
|
|
|
978
|
-
|
|
979
|
-
|
|
1011
|
+
// Fall back to other existing module config values
|
|
1012
|
+
if (!configValue && this.existingConfig) {
|
|
1013
|
+
for (const mod of Object.keys(this.existingConfig)) {
|
|
1014
|
+
if (mod !== '_meta' && this.existingConfig[mod] && this.existingConfig[mod][configKey]) {
|
|
1015
|
+
configValue = this.existingConfig[mod][configKey];
|
|
1016
|
+
break;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// If still not found and we're in the same module, use the default from the config schema
|
|
1022
|
+
if (!configValue && currentModule && moduleConfig && moduleConfig[configKey]) {
|
|
1023
|
+
const referencedItem = moduleConfig[configKey];
|
|
1024
|
+
if (referencedItem && referencedItem.default !== undefined) {
|
|
1025
|
+
configValue = referencedItem.default;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
return this.cleanPromptValue(configValue);
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
/**
|
|
1033
|
+
* Convert an existing stored value back into the prompt-facing value for templated fields.
|
|
1034
|
+
* For example, "{test_artifacts}/{value}" + "_bmad-output/test-artifacts/test-design"
|
|
1035
|
+
* becomes "test-design" so the template is not applied twice on modify.
|
|
1036
|
+
* @param {*} existingValue - Stored config value
|
|
1037
|
+
* @param {string} moduleName - Module name
|
|
1038
|
+
* @param {Object} item - Config item definition
|
|
1039
|
+
* @param {Object} moduleConfig - Current module config schema
|
|
1040
|
+
* @returns {*} Prompt-facing default value
|
|
1041
|
+
*/
|
|
1042
|
+
normalizeExistingValueForPrompt(existingValue, moduleName, item, moduleConfig = null) {
|
|
1043
|
+
const cleanedValue = this.cleanPromptValue(existingValue);
|
|
1044
|
+
|
|
1045
|
+
if (typeof cleanedValue !== 'string' || typeof item?.result !== 'string' || !item.result.includes('{value}')) {
|
|
1046
|
+
return cleanedValue;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
const [prefixTemplate = '', suffixTemplate = ''] = item.result.split('{value}');
|
|
1050
|
+
const prefix = this.cleanPromptValue(this.replacePlaceholders(prefixTemplate, moduleName, moduleConfig));
|
|
1051
|
+
const suffix = this.cleanPromptValue(this.replacePlaceholders(suffixTemplate, moduleName, moduleConfig));
|
|
1052
|
+
|
|
1053
|
+
if ((prefix && !cleanedValue.startsWith(prefix)) || (suffix && !cleanedValue.endsWith(suffix))) {
|
|
1054
|
+
return cleanedValue;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
const startIndex = prefix.length;
|
|
1058
|
+
const endIndex = suffix ? cleanedValue.length - suffix.length : cleanedValue.length;
|
|
1059
|
+
if (endIndex < startIndex) {
|
|
1060
|
+
return cleanedValue;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
let promptValue = cleanedValue.slice(startIndex, endIndex);
|
|
1064
|
+
if (promptValue.startsWith('/')) {
|
|
1065
|
+
promptValue = promptValue.slice(1);
|
|
1066
|
+
}
|
|
1067
|
+
if (promptValue.endsWith('/')) {
|
|
1068
|
+
promptValue = promptValue.slice(0, -1);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
return promptValue || cleanedValue;
|
|
980
1072
|
}
|
|
981
1073
|
|
|
982
1074
|
/**
|
|
@@ -993,12 +1085,7 @@ class ConfigCollector {
|
|
|
993
1085
|
let existingValue = null;
|
|
994
1086
|
if (this.existingConfig && this.existingConfig[moduleName]) {
|
|
995
1087
|
existingValue = this.existingConfig[moduleName][key];
|
|
996
|
-
|
|
997
|
-
// Clean up existing value - remove {project-root}/ prefix if present
|
|
998
|
-
// This prevents duplication when the result template adds it back
|
|
999
|
-
if (typeof existingValue === 'string' && existingValue.startsWith('{project-root}/')) {
|
|
1000
|
-
existingValue = existingValue.replace('{project-root}/', '');
|
|
1001
|
-
}
|
|
1088
|
+
existingValue = this.normalizeExistingValueForPrompt(existingValue, moduleName, item, moduleConfig);
|
|
1002
1089
|
}
|
|
1003
1090
|
|
|
1004
1091
|
// Special handling for user_name: default to system user
|
|
@@ -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 = [];
|