diff --git a/extensions/matrix/src/plugin-entry.runtime.js b/extensions/matrix/src/plugin-entry.runtime.js index 4a0eba6ebf6..c34c085bf03 100644 --- a/extensions/matrix/src/plugin-entry.runtime.js +++ b/extensions/matrix/src/plugin-entry.runtime.js @@ -38,11 +38,26 @@ function readPackageJson(packageRoot) { } } +function hasTrustedOpenClawRootIndicator(packageRoot, packageJson) { + const packageExports = packageJson?.exports ?? {}; + if (!Object.prototype.hasOwnProperty.call(packageExports, "./plugin-sdk")) { + return false; + } + const hasCliEntryExport = Object.prototype.hasOwnProperty.call(packageExports, "./cli-entry"); + const hasOpenClawBin = + (typeof packageJson?.bin === "string" && packageJson.bin.includes("openclaw")) || + (typeof packageJson?.bin === "object" && + packageJson.bin !== null && + typeof packageJson.bin.openclaw === "string"); + const hasOpenClawEntrypoint = fs.existsSync(path.join(packageRoot, "openclaw.mjs")); + return hasCliEntryExport || hasOpenClawBin || hasOpenClawEntrypoint; +} + function findOpenClawPackageRoot(startDir) { let cursor = path.resolve(startDir); for (let i = 0; i < 12; i += 1) { const pkg = readPackageJson(cursor); - if (pkg?.name === "openclaw" && pkg.exports?.["./plugin-sdk"]) { + if (pkg?.name === "openclaw" && hasTrustedOpenClawRootIndicator(cursor, pkg)) { return { packageRoot: cursor, packageJson: pkg }; } const parent = path.dirname(cursor); diff --git a/extensions/matrix/src/plugin-entry.runtime.test.ts b/extensions/matrix/src/plugin-entry.runtime.test.ts index 0739a560308..60473b4438a 100644 --- a/extensions/matrix/src/plugin-entry.runtime.test.ts +++ b/extensions/matrix/src/plugin-entry.runtime.test.ts @@ -77,6 +77,7 @@ function writeOpenClawPackageFixture(fixtureRoot: string) { 2, ) + "\n", ); + writeFixtureFile(fixtureRoot, "openclaw.mjs", "export {};\n"); writeFixtureFile(fixtureRoot, "dist/plugin-sdk/index.js", "export {};\n"); } @@ -100,6 +101,7 @@ function writeOpenClawAliasFixture(fixtureRoot: string, extraExports?: Record { + const fixtureRoot = makeFixtureRoot(".tmp-matrix-runtime-trusted-root-"); + const wrapperSource = fs.readFileSync( + path.join(REPO_ROOT, "extensions", "matrix", "src", "plugin-entry.runtime.js"), + "utf8", + ); + + delete matrixWrapperGlobal.__openclawMatrixWrapperJitiOptions; + writeOpenClawAliasFixture(fixtureRoot); + writeFixtureFile( + fixtureRoot, + "extensions/package.json", + JSON.stringify( + { + name: "openclaw", + type: "module", + exports: { + "./plugin-sdk": "./dist/plugin-sdk/index.js", + "./plugin-sdk/group-access": "./dist/plugin-sdk/group-access.js", + }, + }, + null, + 2, + ) + "\n", + ); + writeFixtureFile( + fixtureRoot, + "extensions/src/plugin-sdk/root-alias.cjs", + "module.exports = {};\n", + ); + writeFixtureFile(fixtureRoot, "extensions/src/plugin-sdk/group-access.ts", "export {};\n"); + writeCapturingJitiFixture(fixtureRoot); + writeFixtureFile(fixtureRoot, "extensions/matrix/src/plugin-entry.runtime.js", wrapperSource); + writeFixtureFile( + fixtureRoot, + "extensions/matrix/plugin-entry.handlers.runtime.js", + PACKAGED_RUNTIME_STUB, + ); + + const wrapperUrl = pathToFileURL( + path.join(fixtureRoot, "extensions", "matrix", "src", "plugin-entry.runtime.js"), + ); + await import(`${wrapperUrl.href}?t=${Date.now()}`); + + expect(matrixWrapperGlobal.__openclawMatrixWrapperJitiOptions).toMatchObject({ + alias: { + "openclaw/plugin-sdk": path.join(fixtureRoot, "src", "plugin-sdk", "root-alias.cjs"), + "@openclaw/plugin-sdk": path.join(fixtureRoot, "src", "plugin-sdk", "root-alias.cjs"), + "openclaw/plugin-sdk/group-access": path.join( + fixtureRoot, + "src", + "plugin-sdk", + "group-access.ts", + ), + "@openclaw/plugin-sdk/group-access": path.join( + fixtureRoot, + "src", + "plugin-sdk", + "group-access.ts", + ), + }, + }); +}, 240_000);