Skip to content

Commit e0ea6a0

Browse files
authored
fix: support skills/ folder as module source location (#2149)
The installer now finds module.yaml in both skills/ and src/ directories, including one level deep in subfolders. Updates bmb module-definition to skills/module.yaml to match its actual structure.
1 parent c91db0d commit e0ea6a0

2 files changed

Lines changed: 35 additions & 4 deletions

File tree

tools/installer/external-official-modules.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
modules:
55
bmad-builder:
66
url: https://github.com/bmad-code-org/bmad-builder
7-
module-definition: src/module.yaml
7+
module-definition: skills/module.yaml
88
code: bmb
99
name: "BMad Builder"
1010
description: "Agent and Builder"

tools/installer/modules/external-manager.js

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,10 +313,41 @@ class ExternalModuleManager {
313313

314314
// The module-definition specifies the path to module.yaml relative to repo root
315315
// We need to return the directory containing module.yaml
316-
const moduleDefinitionPath = moduleInfo.moduleDefinition; // e.g., 'src/module.yaml'
317-
const moduleDir = path.dirname(path.join(cloneDir, moduleDefinitionPath));
316+
const moduleDefinitionPath = moduleInfo.moduleDefinition; // e.g., 'skills/module.yaml'
317+
const configuredPath = path.join(cloneDir, moduleDefinitionPath);
318318

319-
return moduleDir;
319+
if (await fs.pathExists(configuredPath)) {
320+
return path.dirname(configuredPath);
321+
}
322+
323+
// Fallback: search skills/ and src/ (root level and one level deep for subfolders)
324+
for (const dir of ['skills', 'src']) {
325+
const rootCandidate = path.join(cloneDir, dir, 'module.yaml');
326+
if (await fs.pathExists(rootCandidate)) {
327+
return path.dirname(rootCandidate);
328+
}
329+
const dirPath = path.join(cloneDir, dir);
330+
if (await fs.pathExists(dirPath)) {
331+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
332+
for (const entry of entries) {
333+
if (entry.isDirectory()) {
334+
const subCandidate = path.join(dirPath, entry.name, 'module.yaml');
335+
if (await fs.pathExists(subCandidate)) {
336+
return path.dirname(subCandidate);
337+
}
338+
}
339+
}
340+
}
341+
}
342+
343+
// Check repo root as last fallback
344+
const rootCandidate = path.join(cloneDir, 'module.yaml');
345+
if (await fs.pathExists(rootCandidate)) {
346+
return path.dirname(rootCandidate);
347+
}
348+
349+
// Nothing found: return configured path (preserves old behavior for error messaging)
350+
return path.dirname(configuredPath);
320351
}
321352
}
322353

0 commit comments

Comments
 (0)