mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-21 06:51:01 +00:00
fix(plugin-sdk): restore root diagnostic compat
This commit is contained in:
@@ -42,7 +42,7 @@ const exportedNames = exportMatch[1]
|
||||
|
||||
const exportSet = new Set(exportedNames);
|
||||
|
||||
const requiredRuntimeShimEntries = ["root-alias.cjs"];
|
||||
const requiredRuntimeShimEntries = ["compat.js", "root-alias.cjs"];
|
||||
|
||||
// Critical functions that channel extension plugins import from openclaw/plugin-sdk.
|
||||
// If any of these are missing, plugins will fail at runtime with:
|
||||
@@ -65,6 +65,7 @@ const requiredExports = [
|
||||
"resolveChannelMediaMaxBytes",
|
||||
"warnMissingProviderGroupPolicyFallbackOnce",
|
||||
"emptyPluginConfigSchema",
|
||||
"onDiagnosticEvent",
|
||||
"normalizePluginHttpPath",
|
||||
"registerPluginHttpRoute",
|
||||
"DEFAULT_ACCOUNT_ID",
|
||||
|
||||
@@ -21,6 +21,7 @@ const requiredPathGroups = [
|
||||
["dist/index.js", "dist/index.mjs"],
|
||||
["dist/entry.js", "dist/entry.mjs"],
|
||||
...listPluginSdkDistArtifacts(),
|
||||
"dist/plugin-sdk/compat.js",
|
||||
"dist/plugin-sdk/root-alias.cjs",
|
||||
"dist/build-info.json",
|
||||
];
|
||||
@@ -228,6 +229,7 @@ const requiredPluginSdkExports = [
|
||||
"resolveChannelMediaMaxBytes",
|
||||
"warnMissingProviderGroupPolicyFallbackOnce",
|
||||
"emptyPluginConfigSchema",
|
||||
"onDiagnosticEvent",
|
||||
"normalizePluginHttpPath",
|
||||
"registerPluginHttpRoute",
|
||||
"DEFAULT_ACCOUNT_ID",
|
||||
|
||||
@@ -36,6 +36,7 @@ describe("tsdown config", () => {
|
||||
expect.arrayContaining([
|
||||
"index",
|
||||
"plugins/runtime/index",
|
||||
"plugin-sdk/compat",
|
||||
"plugin-sdk/index",
|
||||
"extensions/openai/index",
|
||||
"bundled/boot-md/handler",
|
||||
|
||||
@@ -20,6 +20,8 @@ if (shouldWarnCompatImport) {
|
||||
export { emptyPluginConfigSchema } from "../plugins/config-schema.js";
|
||||
export { resolveControlCommandGate } from "../channels/command-gating.js";
|
||||
export { delegateCompactionToRuntime } from "../context-engine/delegate.js";
|
||||
export type { DiagnosticEventPayload } from "../infra/diagnostic-events.js";
|
||||
export { onDiagnosticEvent } from "../infra/diagnostic-events.js";
|
||||
|
||||
export { createAccountStatusSink } from "./channel-lifecycle.js";
|
||||
export { createPluginRuntimeStore } from "./runtime-store.js";
|
||||
|
||||
@@ -50,9 +50,11 @@ describe("plugin-sdk exports", () => {
|
||||
it("keeps the root runtime surface intentionally small", () => {
|
||||
expect(typeof sdk.emptyPluginConfigSchema).toBe("function");
|
||||
expect(typeof sdk.delegateCompactionToRuntime).toBe("function");
|
||||
expect(typeof sdk.onDiagnosticEvent).toBe("function");
|
||||
expect(Object.prototype.hasOwnProperty.call(sdk, "resolveControlCommandGate")).toBe(false);
|
||||
expect(Object.prototype.hasOwnProperty.call(sdk, "buildAgentSessionKey")).toBe(false);
|
||||
expect(Object.prototype.hasOwnProperty.call(sdk, "isDangerousNameMatchingEnabled")).toBe(false);
|
||||
expect(Object.prototype.hasOwnProperty.call(sdk, "emitDiagnosticEvent")).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps package.json plugin-sdk exports synced with the manifest", async () => {
|
||||
|
||||
@@ -64,7 +64,9 @@ export type { HookEntry } from "../hooks/types.js";
|
||||
export type { ReplyPayload } from "../auto-reply/types.js";
|
||||
export type { WizardPrompter } from "../wizard/prompts.js";
|
||||
export type { ContextEngineFactory } from "../context-engine/registry.js";
|
||||
export type { DiagnosticEventPayload } from "../infra/diagnostic-events.js";
|
||||
|
||||
export { emptyPluginConfigSchema } from "../plugins/config-schema.js";
|
||||
export { registerContextEngine } from "../context-engine/registry.js";
|
||||
export { delegateCompactionToRuntime } from "../context-engine/delegate.js";
|
||||
export { onDiagnosticEvent } from "../infra/diagnostic-events.js";
|
||||
|
||||
@@ -5,6 +5,7 @@ const fs = require("node:fs");
|
||||
|
||||
let monolithicSdk = null;
|
||||
const jitiLoaders = new Map();
|
||||
const pluginSdkSubpathsCache = new Map();
|
||||
|
||||
function emptyPluginConfigSchema() {
|
||||
function error(message) {
|
||||
@@ -61,6 +62,49 @@ function resolveControlCommandGate(params) {
|
||||
return { commandAuthorized, shouldBlock };
|
||||
}
|
||||
|
||||
function getPackageRoot() {
|
||||
return path.resolve(__dirname, "..", "..");
|
||||
}
|
||||
|
||||
function listPluginSdkExportedSubpaths() {
|
||||
const packageRoot = getPackageRoot();
|
||||
if (pluginSdkSubpathsCache.has(packageRoot)) {
|
||||
return pluginSdkSubpathsCache.get(packageRoot);
|
||||
}
|
||||
|
||||
let subpaths = [];
|
||||
try {
|
||||
const packageJsonPath = path.join(packageRoot, "package.json");
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
||||
subpaths = Object.keys(packageJson.exports ?? {})
|
||||
.filter((key) => key.startsWith("./plugin-sdk/"))
|
||||
.map((key) => key.slice("./plugin-sdk/".length));
|
||||
} catch {
|
||||
subpaths = [];
|
||||
}
|
||||
|
||||
pluginSdkSubpathsCache.set(packageRoot, subpaths);
|
||||
return subpaths;
|
||||
}
|
||||
|
||||
function buildPluginSdkAliasMap(useDist) {
|
||||
const packageRoot = getPackageRoot();
|
||||
const pluginSdkDir = path.join(packageRoot, useDist ? "dist" : "src", "plugin-sdk");
|
||||
const ext = useDist ? ".js" : ".ts";
|
||||
const aliasMap = {
|
||||
"openclaw/plugin-sdk": __filename,
|
||||
};
|
||||
|
||||
for (const subpath of listPluginSdkExportedSubpaths()) {
|
||||
const candidate = path.join(pluginSdkDir, `${subpath}${ext}`);
|
||||
if (fs.existsSync(candidate)) {
|
||||
aliasMap[`openclaw/plugin-sdk/${subpath}`] = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return aliasMap;
|
||||
}
|
||||
|
||||
function getJiti(tryNative) {
|
||||
if (jitiLoaders.has(tryNative)) {
|
||||
return jitiLoaders.get(tryNative);
|
||||
@@ -68,6 +112,7 @@ function getJiti(tryNative) {
|
||||
|
||||
const { createJiti } = require("jiti");
|
||||
const jitiLoader = createJiti(__filename, {
|
||||
alias: buildPluginSdkAliasMap(tryNative),
|
||||
interopDefault: true,
|
||||
// Prefer Node's native sync ESM loader for built dist/plugin-sdk/*.js files
|
||||
// so local plugins do not create a second transpiled OpenClaw core graph.
|
||||
|
||||
@@ -48,6 +48,12 @@ function loadRootAliasWithStubs(options?: {
|
||||
}
|
||||
if (id === "node:fs") {
|
||||
return {
|
||||
readFileSync: () =>
|
||||
JSON.stringify({
|
||||
exports: {
|
||||
"./plugin-sdk/group-access": { default: "./dist/plugin-sdk/group-access.js" },
|
||||
},
|
||||
}),
|
||||
existsSync: () => options?.distExists ?? false,
|
||||
};
|
||||
}
|
||||
@@ -164,8 +170,23 @@ describe("plugin-sdk root alias", () => {
|
||||
expect("delegateCompactionToRuntime" in lazyRootSdk).toBe(true);
|
||||
});
|
||||
|
||||
it("forwards onDiagnosticEvent through the compat-backed root alias", () => {
|
||||
const onDiagnosticEvent = () => () => undefined;
|
||||
const lazyModule = loadRootAliasWithStubs({
|
||||
monolithicExports: {
|
||||
onDiagnosticEvent,
|
||||
},
|
||||
});
|
||||
const lazyRootSdk = lazyModule.moduleExports;
|
||||
|
||||
expect(typeof lazyRootSdk.onDiagnosticEvent).toBe("function");
|
||||
expect(lazyRootSdk.onDiagnosticEvent).toBe(onDiagnosticEvent);
|
||||
expect("onDiagnosticEvent" in lazyRootSdk).toBe(true);
|
||||
});
|
||||
|
||||
it("loads legacy root exports through the merged root wrapper", { timeout: 240_000 }, () => {
|
||||
expect(typeof rootSdk.resolveControlCommandGate).toBe("function");
|
||||
expect(typeof rootSdk.onDiagnosticEvent).toBe("function");
|
||||
expect(typeof rootSdk.default).toBe("object");
|
||||
expect(rootSdk.default).toBe(rootSdk);
|
||||
expect(rootSdk.__esModule).toBe(true);
|
||||
@@ -173,9 +194,12 @@ describe("plugin-sdk root alias", () => {
|
||||
|
||||
it("preserves reflection semantics for lazily resolved exports", { timeout: 240_000 }, () => {
|
||||
expect("resolveControlCommandGate" in rootSdk).toBe(true);
|
||||
expect("onDiagnosticEvent" in rootSdk).toBe(true);
|
||||
const keys = Object.keys(rootSdk);
|
||||
expect(keys).toContain("resolveControlCommandGate");
|
||||
expect(keys).toContain("onDiagnosticEvent");
|
||||
const descriptor = Object.getOwnPropertyDescriptor(rootSdk, "resolveControlCommandGate");
|
||||
expect(descriptor).toBeDefined();
|
||||
expect(Object.getOwnPropertyDescriptor(rootSdk, "onDiagnosticEvent")).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -186,6 +186,8 @@ const coreDistEntries = buildCoreDistEntries();
|
||||
function buildUnifiedDistEntries(): Record<string, string> {
|
||||
return {
|
||||
...coreDistEntries,
|
||||
// Internal compat artifact for the root-alias.cjs lazy loader.
|
||||
"plugin-sdk/compat": "src/plugin-sdk/compat.ts",
|
||||
...Object.fromEntries(
|
||||
Object.entries(buildPluginSdkEntrySources()).map(([entry, source]) => [
|
||||
`plugin-sdk/${entry}`,
|
||||
|
||||
Reference in New Issue
Block a user