fix: support ESM and .cjs module installers in ModuleManager
Module installer loading now handles three cases: - .cjs files loaded via require() (always CommonJS regardless of package type) - .js files loaded via dynamic import() (works for both CJS and ESM) - CJS default export unwrapped automatically for consistent API This fixes errors when external modules set "type":"module" in their package.json. Those modules must still rename installer.js to installer.cjs if it uses require() internally. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bf8d1e8022
commit
6fd5db4aed
|
|
@ -1277,16 +1277,31 @@ class ModuleManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const installerPath = path.join(sourcePath, '_module-installer', 'installer.js');
|
const installerDir = path.join(sourcePath, '_module-installer');
|
||||||
|
// Prefer .cjs (always CommonJS) then fall back to .js
|
||||||
|
const cjsPath = path.join(installerDir, 'installer.cjs');
|
||||||
|
const jsPath = path.join(installerDir, 'installer.js');
|
||||||
|
const hasCjs = await fs.pathExists(cjsPath);
|
||||||
|
const installerPath = hasCjs ? cjsPath : jsPath;
|
||||||
|
|
||||||
// Check if module has a custom installer
|
// Check if module has a custom installer
|
||||||
if (!(await fs.pathExists(installerPath))) {
|
if (!hasCjs && !(await fs.pathExists(jsPath))) {
|
||||||
return; // No custom installer
|
return; // No custom installer
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Load the module installer
|
// .cjs files are always CommonJS and safe to require().
|
||||||
const moduleInstaller = require(installerPath);
|
// .js files may be ESM (when the package sets "type":"module"),
|
||||||
|
// so use dynamic import() which handles both CJS and ESM.
|
||||||
|
let moduleInstaller;
|
||||||
|
if (hasCjs) {
|
||||||
|
moduleInstaller = require(installerPath);
|
||||||
|
} else {
|
||||||
|
const { pathToFileURL } = require('node:url');
|
||||||
|
const imported = await import(pathToFileURL(installerPath).href);
|
||||||
|
// CJS module.exports lands on .default, ESM named exports are top-level
|
||||||
|
moduleInstaller = imported.default && typeof imported.default === 'object' ? imported.default : imported;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof moduleInstaller.install === 'function') {
|
if (typeof moduleInstaller.install === 'function') {
|
||||||
// Get project root (parent of bmad directory)
|
// Get project root (parent of bmad directory)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue