fix(plugin): preserve sdk alias fallback for native loads

This commit is contained in:
Vincent Koc
2026-05-03 23:24:57 -07:00
parent 6e8cdd7d59
commit baecb6b4d6
6 changed files with 33 additions and 12 deletions

View File

@@ -1037,7 +1037,8 @@ describe("loadOpenClawPlugins", () => {
},
});
expect(registry.plugins.find((entry) => entry.id === "discord")?.status).toBe("loaded");
const record = registry.plugins.find((entry) => entry.id === "discord");
expect(record?.status, record?.error).toBe("loaded");
});
it("registers standalone text transforms", () => {
useNoBundledPlugins();
@@ -6591,7 +6592,7 @@ module.exports = {
}),
);
const record = registry.plugins.find((entry) => entry.id === "legacy-root-import");
expect(record?.status).toBe("loaded");
expect(record?.status, record?.error).toBe("loaded");
});
it("supports legacy plugins subscribing to diagnostic events from the root sdk", async () => {
@@ -6639,7 +6640,7 @@ module.exports = {
const record = registry.plugins.find(
(entry) => entry.id === "legacy-root-diagnostic-listener",
);
expect(record?.status).toBe("loaded");
expect(record?.status, record?.error).toBe("loaded");
emitDiagnosticEvent({
type: "model.usage",

View File

@@ -64,6 +64,19 @@ describe("tryNativeRequireJavaScriptModule", () => {
);
});
it("declines missing dependency errors when source-transform fallback is available", () => {
const dir = makeTempDir();
const modulePath = path.join(dir, "plugin.cjs");
fs.writeFileSync(modulePath, 'require("openclaw/plugin-sdk");\n', "utf8");
expect(
tryNativeRequireJavaScriptModule(modulePath, {
allowWindows: true,
fallbackOnMissingDependency: true,
}),
).toEqual({ ok: false });
});
it("propagates real module evaluation errors instead of falling back", () => {
const dir = makeTempDir();
const modulePath = path.join(dir, "plugin.cjs");

View File

@@ -33,7 +33,7 @@ function isSourceTransformFallbackError(error: unknown, modulePath: string): boo
export function tryNativeRequireJavaScriptModule(
modulePath: string,
options: { allowWindows?: boolean } = {},
options: { allowWindows?: boolean; fallbackOnMissingDependency?: boolean } = {},
): { ok: true; moduleExport: unknown } | { ok: false } {
if (process.platform === "win32" && options.allowWindows !== true) {
return { ok: false };
@@ -44,7 +44,15 @@ export function tryNativeRequireJavaScriptModule(
try {
return { ok: true, moduleExport: nodeRequire(modulePath) };
} catch (error) {
if (!isSourceTransformFallbackError(error, modulePath)) {
const code =
error && typeof error === "object" ? (error as { code?: unknown }).code : undefined;
if (
!isSourceTransformFallbackError(error, modulePath) &&
!(
options.fallbackOnMissingDependency === true &&
(code === "MODULE_NOT_FOUND" || code === "ERR_MODULE_NOT_FOUND")
)
) {
throw error;
}
return { ok: false };

View File

@@ -406,6 +406,7 @@ describe("getCachedPluginModuleLoader", () => {
// allowWindows must be passed so the native fast path works on Windows too.
expect(nativeStub).toHaveBeenCalledWith("/repo/dist/extensions/demo/api.js", {
allowWindows: true,
fallbackOnMissingDependency: true,
});
expect(getPluginModuleLoaderStats()).toMatchObject({
calls: 1,

View File

@@ -282,7 +282,10 @@ function createPluginModuleLoader(params: {
...rest,
);
}
const native = tryNativeRequireJavaScriptModule(target, { allowWindows: true });
const native = tryNativeRequireJavaScriptModule(target, {
allowWindows: true,
fallbackOnMissingDependency: true,
});
if (native.ok) {
pluginModuleLoaderStats.nativeHits += 1;
return native.moduleExport;

View File

@@ -8,12 +8,7 @@ function writeRuntimeJsonFile(targetPath: string, value: unknown): void {
function writeRuntimeModuleWrapper(sourcePath: string, targetPath: string): void {
const relative = `./${path.relative(path.dirname(targetPath), sourcePath).split(path.sep).join("/")}`;
const content = [
`export * from ${JSON.stringify(relative)};`,
`import * as moduleExports from ${JSON.stringify(relative)};`,
`export default moduleExports.default ?? moduleExports;`,
"",
].join("\n");
const content = [`export * from ${JSON.stringify(relative)};`, ""].join("\n");
try {
if (fs.readFileSync(targetPath, "utf8") === content) {
return;