fix(plugins): localize bundled runtime deps to extensions (#67099)

* fix(plugins): localize bundled runtime deps to extensions

* fix(plugins): move staged runtime deps out of root

* fix(packaging): harden prepack and runtime dep staging

* fix(packaging): preserve optional runtime dep staging

* Update CHANGELOG.md

* fix(packaging): harden runtime staging filesystem writes

* fix(docker): ship preinstall warning in bootstrap layers

* fix(packaging): exclude staged plugin node_modules from npm pack
This commit is contained in:
Vincent Koc
2026-04-15 12:04:31 +01:00
committed by GitHub
parent a780151fd1
commit c727388f93
29 changed files with 1335 additions and 277 deletions

View File

@@ -6,19 +6,16 @@ const packageManifestContractTests: PackageManifestContractParams[] = [
{ pluginId: "bluebubbles", minHostVersionBaseline: "2026.3.22" },
{
pluginId: "discord",
mirroredRootRuntimeDeps: [
"@buape/carbon",
"@discordjs/opus",
"https-proxy-agent",
"opusscript",
],
pluginLocalRuntimeDeps: ["@buape/carbon", "@discordjs/opus", "discord-api-types", "opusscript"],
mirroredRootRuntimeDeps: ["https-proxy-agent"],
minHostVersionBaseline: "2026.3.22",
},
{
pluginId: "feishu",
mirroredRootRuntimeDeps: ["@larksuiteoapi/node-sdk"],
pluginLocalRuntimeDeps: ["@larksuiteoapi/node-sdk"],
minHostVersionBaseline: "2026.3.22",
},
{ pluginId: "google", pluginLocalRuntimeDeps: ["@google/genai"] },
{
pluginId: "googlechat",
mirroredRootRuntimeDeps: ["google-auth-library"],
@@ -26,6 +23,11 @@ const packageManifestContractTests: PackageManifestContractParams[] = [
},
{ pluginId: "irc", minHostVersionBaseline: "2026.3.22" },
{ pluginId: "line", minHostVersionBaseline: "2026.3.22" },
{ pluginId: "amazon-bedrock", pluginLocalRuntimeDeps: ["@aws-sdk/client-bedrock"] },
{
pluginId: "amazon-bedrock-mantle",
pluginLocalRuntimeDeps: ["@aws/bedrock-token-generator"],
},
{ pluginId: "matrix", minHostVersionBaseline: "2026.3.22" },
{ pluginId: "mattermost", minHostVersionBaseline: "2026.3.22" },
{
@@ -36,9 +38,11 @@ const packageManifestContractTests: PackageManifestContractParams[] = [
{ pluginId: "msteams", minHostVersionBaseline: "2026.3.22" },
{ pluginId: "nextcloud-talk", minHostVersionBaseline: "2026.3.22" },
{ pluginId: "nostr", minHostVersionBaseline: "2026.3.22" },
{ pluginId: "openshell", pluginLocalRuntimeDeps: ["openshell"] },
{
pluginId: "slack",
mirroredRootRuntimeDeps: ["@slack/bolt", "@slack/web-api", "https-proxy-agent"],
pluginLocalRuntimeDeps: ["@slack/bolt", "@slack/web-api"],
mirroredRootRuntimeDeps: ["https-proxy-agent"],
},
{ pluginId: "synology-chat", minHostVersionBaseline: "2026.3.22" },
{

View File

@@ -73,18 +73,6 @@ function readMatrixPackageJson(): {
};
}
function readAmazonBedrockPackageJson(): {
dependencies?: Record<string, string>;
optionalDependencies?: Record<string, string>;
} {
return JSON.parse(
readFileSync(resolve(REPO_ROOT, "extensions/amazon-bedrock/package.json"), "utf8"),
) as {
dependencies?: Record<string, string>;
optionalDependencies?: Record<string, string>;
};
}
function collectRuntimeDependencySpecs(packageJson: {
dependencies?: Record<string, string>;
optionalDependencies?: Record<string, string>;
@@ -318,16 +306,6 @@ describe("plugin-sdk package contract guardrails", () => {
}
});
it("mirrors Bedrock runtime deps needed by the bundled host graph", () => {
const rootRuntimeDeps = collectRuntimeDependencySpecs(readRootPackageJson());
const bedrockPackageJson = readAmazonBedrockPackageJson();
const bedrockRuntimeDeps = collectRuntimeDependencySpecs(bedrockPackageJson);
for (const dep of ["@aws-sdk/client-bedrock"]) {
expect(rootRuntimeDeps.get(dep)).toBe(bedrockRuntimeDeps.get(dep));
}
});
it("resolves matrix crypto WASM from the root runtime surface", () => {
const rootRequire = createRootPackageRequire();
// Normalize filesystem separators so the package assertion stays portable.
@@ -346,14 +324,9 @@ describe("plugin-sdk package contract guardrails", () => {
const archivePath = packOpenClawToTempDir(packDir);
const packedPackageJson = await readPackedRootPackageJson(archivePath);
const matrixPackageJson = readMatrixPackageJson();
const bedrockPackageJson = readAmazonBedrockPackageJson();
expect(packedPackageJson.dependencies?.["@matrix-org/matrix-sdk-crypto-wasm"]).toBe(
matrixPackageJson.dependencies?.["@matrix-org/matrix-sdk-crypto-wasm"],
);
expect(packedPackageJson.dependencies?.["@aws-sdk/client-bedrock"]).toBe(
bedrockPackageJson.dependencies?.["@aws-sdk/client-bedrock"],
);
expect(packedPackageJson.dependencies?.["@openclaw/plugin-package-contract"]).toBeUndefined();
});

View File

@@ -793,16 +793,21 @@ describe("plugin sdk alias helpers", () => {
}
});
it("allows plugin loader dist shortcuts on non-Windows hosts", () => {
it("keeps bundled plugin dist modules on the aliased Jiti path", () => {
expect(
resolvePluginLoaderJitiTryNative(`/repo/${bundledDistPluginFile("browser", "index.js")}`, {
preferBuiltDist: true,
}),
).toBe(true);
).toBe(false);
expect(
resolvePluginLoaderJitiTryNative(`/repo/${bundledDistPluginFile("browser", "helper.ts")}`, {
preferBuiltDist: true,
}),
).toBe(false);
expect(
resolvePluginLoaderJitiTryNative("/repo/dist/plugins/runtime/index.js", {
preferBuiltDist: true,
}),
).toBe(true);
});

View File

@@ -472,6 +472,10 @@ function supportsNativeJitiRuntime(): boolean {
return typeof versions.bun !== "string" && process.platform !== "win32";
}
function isBundledPluginDistModulePath(modulePath: string): boolean {
return modulePath.replace(/\\/g, "/").includes("/dist/extensions/");
}
export function shouldPreferNativeJiti(modulePath: string): boolean {
if (!supportsNativeJitiRuntime()) {
return false;
@@ -493,6 +497,9 @@ export function resolvePluginLoaderJitiTryNative(
preferBuiltDist?: boolean;
},
): boolean {
if (isBundledPluginDistModulePath(modulePath)) {
return false;
}
return (
shouldPreferNativeJiti(modulePath) ||
(supportsNativeJitiRuntime() &&

View File

@@ -252,7 +252,7 @@ describe("stageBundledPluginRuntimeDeps", () => {
});
});
it("strips non-runtime dependency sections before temp npm staging", async () => {
it("strips non-runtime dependency sections before fallback runtime staging", async () => {
const repoRoot = makeRepoRoot("openclaw-stage-bundled-runtime-manifest-");
writeRepoFile(
repoRoot,