From a3e05458474b847739a6fcdfe0226460e0a023f8 Mon Sep 17 00:00:00 2001 From: bmad Date: Fri, 8 May 2026 18:10:22 -0300 Subject: [PATCH 1/2] feat(installer): register automator module --- tools/installer/modules/registry-fallback.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/installer/modules/registry-fallback.yaml b/tools/installer/modules/registry-fallback.yaml index 52bc4b4fc..e2416af9d 100644 --- a/tools/installer/modules/registry-fallback.yaml +++ b/tools/installer/modules/registry-fallback.yaml @@ -18,6 +18,17 @@ modules: npmPackage: bmad-builder default_channel: stable + bmad-automator: + url: https://github.com/bmad-code-org/bmad-automator + module-definition: skills/module.yaml + code: baut + name: "BMad Automator" + description: "Story automation skills" + defaultSelected: false + type: experimental + npmPackage: bmad-story-automator + default_channel: next + bmad-creative-intelligence-suite: url: https://github.com/bmad-code-org/bmad-module-creative-intelligence-suite module-definition: src/module.yaml From 724867d48db9005cc66a4b32273abb8b45c5b45a Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 12 May 2026 23:44:11 -0500 Subject: [PATCH 2/2] fix(installer): descriptive error when module definition missing after clone (#2377) * fix(installer): throw descriptive error when module definition missing after clone When a stable tag predates a module restructure (e.g. baut v1.14.0 had payload/source dirs, but the registry pointed to skills/module.yaml which only exists on main), findExternalModuleSource silently returned the configured but non-existent path. This caused a confusing ENOENT inside getFileList/copyModuleWithFiltering rather than a clear error. Now throws with the version that was cloned and a --next hint when the install channel was stable, so users know exactly how to recover. Closes #2372 * style: fix prettier formatting in external-manager.js * style: apply prettier formatting --- tools/installer/modules/external-manager.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tools/installer/modules/external-manager.js b/tools/installer/modules/external-manager.js index 7d2add4fb..d8ecf8a5d 100644 --- a/tools/installer/modules/external-manager.js +++ b/tools/installer/modules/external-manager.js @@ -524,8 +524,20 @@ class ExternalModuleManager { return path.dirname(rootCandidate); } - // Nothing found: return configured path (preserves old behavior for error messaging) - return path.dirname(configuredPath); + // Nothing found: the cloned ref does not contain a recognizable module structure. + // This happens when a stable tag predates a module restructure (e.g. the repo + // moved files from payload/ to skills/ after the tag was cut). Returning a + // non-existent path silently causes a confusing ENOENT deep inside copyModuleWithFiltering; + // throw a descriptive error here instead so the user knows what happened and how to recover. + const resolution = ExternalModuleManager._resolutions.get(moduleCode); + const versionHint = resolution?.version ? `version ${resolution.version}` : 'the cloned version'; + const channelHint = + resolution?.channel === 'stable' ? ` Try reinstalling with \`--next=${moduleCode}\` to use the latest main branch instead.` : ''; + throw new Error( + `Module '${moduleCode}' was downloaded but its module definition was not found. ` + + `Expected '${moduleDefinitionPath}' to exist in ${versionHint}, but it is missing. ` + + `The repository may have been restructured after this release was tagged.${channelHint}`, + ); } cachedModules = null; }