quick-update fails for locally-sourced custom modules: bmadDir not forwarded to OfficialModules.install()'s source lookup
Title: quick-update fails for locally-sourced custom modules: bmadDir not forwarded to OfficialModules.install()'s source lookup
Describe the bug
npx bmad-method install --action quick-update --yes fails with:
Installation failed: Source for module '<code>' is not available. It will be
retained but cannot be updated without its source files.
for a custom module that was originally installed via --custom-source <local-path> (not a Git URL). The module's localPath is correctly recorded in _bmad/_config/manifest.yaml, and that path does exist on disk — the lookup that's supposed to use it never receives the information it needs to find it.
Root cause
tools/installer/modules/official-modules.js, OfficialModules.install(moduleName, bmadDir, fileTrackingCallback, options):
const sourcePath = await this.findModuleSource(moduleName, {
silent: options.silent,
channelOptions: options.channelOptions,
});
bmadDir is a parameter of install() itself, but it is never included in the options object passed to findModuleSource(). That call eventually reaches custom-module-manager.js's _findLocalSourceFromManifest(moduleCode, options):
const bmadDir = options.bmadDir;
if (!bmadDir) return null; // always true here, so the manifest lookup never runs
so the manifest-fallback path (the only way to resolve a local-path custom module without a --custom-source re-supplied on the command line) is dead code from this call site.
Notably, Installer.quickUpdate() (tools/installer/core/installer.js) gets this right a few lines earlier, when just checking whether the module is available to update:
const customSource = await customMgr.findModuleSourceByCode(moduleId, { bmadDir });
— so the module correctly passes the "is it updatable" check and lands in modulesToUpdate, then fails later during the actual install step in _installOfficialModules() → OfficialModules.install(), which is the call site missing bmadDir.
Steps to reproduce
npx bmad-method install --custom-source /path/to/a/local/custom-module --yes(first install, local path — not a Git URL).- Confirm
_bmad/_config/manifest.yamlrecordslocalPath: /path/to/a/local/custom-modulefor that module. - Change nothing else; just run
npx bmad-method install --action quick-update --yes.
Expected: the module refreshes from the recorded localPath.
Actual: Installation failed: Source for module '<code>' is not available..., aborting the whole quick-update (core/bmm etc. may have already reported "up to date" before the abort).
Suggested fix
In official-modules.js, install():
const sourcePath = await this.findModuleSource(moduleName, {
silent: options.silent,
channelOptions: options.channelOptions,
+ bmadDir,
});
(bmadDir is already in scope as the method's own parameter.) Worth checking whether _installOfficialModules()'s other calls to officialModules.findModuleSource(...) (e.g. the one that resolves display name/version right after install()) have the same gap.
Environment
- bmad-method version: 6.12.0
- Custom module source type: local path (
--custom-source <local-dir>) - OS: Windows (via Git Bash), Node 22.20.0
Source: bmad-code-org/BMAD-METHOD