diff --git a/extensions/matrix/package.json b/extensions/matrix/package.json index 2ace082d928..86e9cf0953f 100644 --- a/extensions/matrix/package.json +++ b/extensions/matrix/package.json @@ -24,8 +24,7 @@ }, "openclaw": { "extensions": [ - "./index.ts", - "./src/plugin-entry.runtime.ts" + "./index.ts" ], "setupEntry": "./setup-entry.ts", "channel": { diff --git a/src/plugin-sdk/plugin-entry-guardrails.test.ts b/src/plugin-sdk/plugin-entry-guardrails.test.ts index bb7d7ee3128..3866b18a653 100644 --- a/src/plugin-sdk/plugin-entry-guardrails.test.ts +++ b/src/plugin-sdk/plugin-entry-guardrails.test.ts @@ -12,6 +12,7 @@ const REPO_ROOT = resolve(ROOT_DIR, ".."); const EXTENSIONS_DIR = resolve(REPO_ROOT, BUNDLED_PLUGIN_ROOT_DIR); const CORE_PLUGIN_ENTRY_IMPORT_RE = /import\s*\{[^}]*\bdefinePluginEntry\b[^}]*\}\s*from\s*"openclaw\/plugin-sdk\/core"/; +const RUNTIME_ENTRY_HELPER_RE = /(^|\/)plugin-entry\.runtime\.[cm]?[jt]s$/; describe("plugin entry guardrails", () => { it("keeps bundled extension entry modules off direct definePluginEntry imports from core", () => { @@ -34,4 +35,32 @@ describe("plugin entry guardrails", () => { expect(failures).toEqual([]); }); + + it("does not advertise runtime helper sidecars as bundled plugin entry extensions", () => { + const failures: string[] = []; + + for (const entry of readdirSync(EXTENSIONS_DIR, { withFileTypes: true })) { + if (!entry.isDirectory()) { + continue; + } + const packageJsonPath = resolve(EXTENSIONS_DIR, entry.name, "package.json"); + try { + const pkg = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { + openclaw?: { extensions?: unknown }; + }; + const extensions = Array.isArray(pkg.openclaw?.extensions) ? pkg.openclaw.extensions : []; + if ( + extensions.some( + (candidate) => typeof candidate === "string" && RUNTIME_ENTRY_HELPER_RE.test(candidate), + ) + ) { + failures.push(bundledPluginFile(entry.name, "package.json")); + } + } catch { + // Skip directories without package metadata. + } + } + + expect(failures).toEqual([]); + }); });