From 86e2daabba84a6c69fd35c261ddff0e7e9b7b7ae Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Sat, 6 Dec 2025 16:31:32 -0600 Subject: [PATCH] fix: ManifestGenerator now recursively scans for agents - Updated getAgentsFromDir to search subdirectories for .md files - Fixed installPath construction to include nested directory structure - This ensures agents in subdirectories (like cbt-coach/cbt-coach.md) get added to agent-manifest.csv - All agents now get proper CLI slash commands regardless of nesting depth --- .../installers/lib/core/manifest-generator.js | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/tools/cli/installers/lib/core/manifest-generator.js b/tools/cli/installers/lib/core/manifest-generator.js index a4bcb5c4..a3930468 100644 --- a/tools/cli/installers/lib/core/manifest-generator.js +++ b/tools/cli/installers/lib/core/manifest-generator.js @@ -220,18 +220,23 @@ class ManifestGenerator { } /** - * Get agents from a directory + * Get agents from a directory recursively * Only includes compiled .md files (not .agent.yaml source files) */ - async getAgentsFromDir(dirPath, moduleName) { + async getAgentsFromDir(dirPath, moduleName, relativePath = '') { const agents = []; - const files = await fs.readdir(dirPath); + const entries = await fs.readdir(dirPath, { withFileTypes: true }); - for (const file of files) { - // Only include .md files, skip .agent.yaml source files and README.md - if (file.endsWith('.md') && !file.endsWith('.agent.yaml') && file.toLowerCase() !== 'readme.md') { - const filePath = path.join(dirPath, file); - const content = await fs.readFile(filePath, 'utf8'); + for (const entry of entries) { + const fullPath = path.join(dirPath, entry.name); + + if (entry.isDirectory()) { + // Recurse into subdirectories + const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name; + const subDirAgents = await this.getAgentsFromDir(fullPath, moduleName, newRelativePath); + agents.push(...subDirAgents); + } else if (entry.name.endsWith('.md') && !entry.name.endsWith('.agent.yaml') && entry.name.toLowerCase() !== 'readme.md') { + const content = await fs.readFile(fullPath, 'utf8'); // Skip files that don't contain tag (e.g., README files) if (!content.includes('([\s\S]*?)<\/principles>/); // Build relative path for installation + const fileRelativePath = relativePath ? `${relativePath}/${file}` : file; const installPath = - moduleName === 'core' ? `${this.bmadFolderName}/core/agents/${file}` : `${this.bmadFolderName}/${moduleName}/agents/${file}`; + moduleName === 'core' + ? `${this.bmadFolderName}/core/agents/${fileRelativePath}` + : `${this.bmadFolderName}/${moduleName}/agents/${fileRelativePath}`; const agentName = file.replace('.md', '');