refactor: simplify plugin dependency handling

Simplify plugin installation and runtime loading around package-manager-owned dependencies, with Jiti reserved for local/TS fallback paths.

Also scans npm plugin install roots so hoisted transitive dependencies are covered by dependency denylist and node_modules symlink checks.
This commit is contained in:
Peter Steinberger
2026-05-01 21:32:22 +01:00
committed by GitHub
parent 2e8e9cd6ca
commit ed8f50f240
294 changed files with 2562 additions and 25454 deletions

View File

@@ -14,9 +14,6 @@
"openclaw": {
"extensions": [
"./index.ts"
],
"bundle": {
"stageRuntimeDependencies": true
}
]
}
}

View File

@@ -177,7 +177,7 @@ describe("prepareAcpxCodexAuthConfig", () => {
});
const wrapper = await fs.readFile(generated.wrapperPath, "utf8");
expect(wrapper).toContain('"@agentclientprotocol/claude-agent-acp@0.31.1"');
expect(wrapper).toContain('"@agentclientprotocol/claude-agent-acp@0.31.4"');
expect(wrapper).toContain('"--", "claude-agent-acp"');
expect(wrapper).not.toContain("@agentclientprotocol/claude-agent-acp@^0.31.0");
expect(wrapper).not.toContain("@agentclientprotocol/claude-agent-acp@0.31.0");
@@ -379,7 +379,7 @@ describe("prepareAcpxCodexAuthConfig", () => {
rawConfig: {
agents: {
claude: {
command: "npx -y @agentclientprotocol/claude-agent-acp@0.31.1 --permission-mode bypass",
command: "npx -y @agentclientprotocol/claude-agent-acp@0.31.4 --permission-mode bypass",
},
},
},
@@ -425,7 +425,7 @@ describe("prepareAcpxCodexAuthConfig", () => {
const root = await makeTempDir();
const stateDir = path.join(root, "state");
const command =
"node ./custom-claude-wrapper.mjs @agentclientprotocol/claude-agent-acp@0.31.1 --flag";
"node ./custom-claude-wrapper.mjs @agentclientprotocol/claude-agent-acp@0.31.4 --flag";
const pluginConfig = resolveAcpxPluginConfig({
rawConfig: {
agents: {

View File

@@ -7,7 +7,7 @@ const CODEX_ACP_PACKAGE = "@zed-industries/codex-acp";
const CODEX_ACP_PACKAGE_RANGE = "^0.12.0";
const CODEX_ACP_BIN = "codex-acp";
const CLAUDE_ACP_PACKAGE = "@agentclientprotocol/claude-agent-acp";
const CLAUDE_ACP_PACKAGE_VERSION = "0.31.1";
const CLAUDE_ACP_PACKAGE_VERSION = "0.31.4";
const CLAUDE_ACP_BIN = "claude-agent-acp";
const RUN_CONFIGURED_COMMAND_SENTINEL = "--openclaw-run-configured";
const requireFromHere = createRequire(import.meta.url);

View File

@@ -4,15 +4,10 @@ import { describe, expect, it } from "vitest";
type AcpxPackageManifest = {
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
openclaw?: {
bundle?: {
stageRuntimeDependencies?: boolean;
};
};
};
describe("acpx package manifest", () => {
it("opts into staging bundled runtime dependencies", () => {
it("keeps runtime dependencies in the package manifest", () => {
const packageJson = JSON.parse(
fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
) as AcpxPackageManifest;
@@ -21,6 +16,5 @@ describe("acpx package manifest", () => {
expect(packageJson.dependencies?.["@zed-industries/codex-acp"]).toBe("0.12.0");
expect(packageJson.dependencies?.["@agentclientprotocol/claude-agent-acp"]).toBe("0.31.4");
expect(packageJson.devDependencies?.["@agentclientprotocol/claude-agent-acp"]).toBeUndefined();
expect(packageJson.openclaw?.bundle?.stageRuntimeDependencies).toBe(true);
});
});

View File

@@ -13,9 +13,6 @@
"@openclaw/plugin-sdk": "workspace:*"
},
"openclaw": {
"bundle": {
"stageRuntimeDependencies": true
},
"extensions": [
"./index.ts"
]

View File

@@ -13,9 +13,6 @@
"@openclaw/plugin-sdk": "workspace:*"
},
"openclaw": {
"bundle": {
"stageRuntimeDependencies": true
},
"extensions": [
"./index.ts"
]

View File

@@ -13,9 +13,6 @@
"@openclaw/plugin-sdk": "workspace:*"
},
"openclaw": {
"bundle": {
"stageRuntimeDependencies": true
},
"extensions": [
"./index.ts"
]

View File

@@ -11,9 +11,6 @@
"@openclaw/plugin-sdk": "workspace:*"
},
"openclaw": {
"bundle": {
"stageRuntimeDependencies": true
},
"extensions": [
"./index.ts"
]

View File

@@ -12,9 +12,6 @@
"openclaw": {
"extensions": [
"./index.ts"
],
"bundle": {
"stageRuntimeDependencies": true
}
]
}
}

View File

@@ -84,7 +84,7 @@ export async function requirePwAi(
501,
[
`Playwright is not available in this gateway build; '${feature}' is unsupported.`,
"Repair the bundled browser plugin runtime dependencies so playwright-core is installed, then restart the gateway. In Docker, also install Chromium with the bundled playwright-core CLI.",
"Reinstall or update OpenClaw so the core browser runtime dependency is present, then restart the gateway. In Docker, also install Chromium with the bundled playwright-core CLI.",
"Docs: /tools/browser#playwright-requirement",
].join("\n"),
);

View File

@@ -16,9 +16,6 @@
"openclaw": {
"extensions": [
"./index.ts"
],
"bundle": {
"stageRuntimeDependencies": true
}
]
}
}

View File

@@ -105,7 +105,7 @@ async function findManagedCodexAppServerCommandPath(params: {
throw new Error(
[
`Managed Codex app-server binary was not found for ${MANAGED_CODEX_APP_SERVER_PACKAGE}.`,
"Run OpenClaw with bundled plugin runtime dependencies enabled, or run pnpm install in a source checkout.",
"Reinstall or update OpenClaw, or run pnpm install in a source checkout.",
"Set plugins.entries.codex.config.appServer.command or OPENCLAW_CODEX_APP_SERVER_BIN to use a custom Codex binary.",
].join(" "),
);

View File

@@ -4,15 +4,10 @@ import { MANAGED_CODEX_APP_SERVER_PACKAGE_VERSION } from "./app-server/version.j
type CodexPackageManifest = {
dependencies?: Record<string, string>;
openclaw?: {
bundle?: {
stageRuntimeDependencies?: boolean;
};
};
};
describe("codex package manifest", () => {
it("opts into staging bundled runtime dependencies", () => {
it("keeps runtime dependencies in the package manifest", () => {
const packageJson = JSON.parse(
fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
) as CodexPackageManifest;
@@ -21,6 +16,5 @@ describe("codex package manifest", () => {
expect(packageJson.dependencies?.["@openai/codex"]).toBe(
MANAGED_CODEX_APP_SERVER_PACKAGE_VERSION,
);
expect(packageJson.openclaw?.bundle?.stageRuntimeDependencies).toBe(true);
});
});

View File

@@ -1,7 +1,7 @@
{
"id": "diffs",
"activation": {
"onStartup": true
"onStartup": false
},
"name": "Diffs",
"description": "Read-only diff viewer and file renderer for agents.",

View File

@@ -17,11 +17,27 @@
"@openclaw/plugin-sdk": "workspace:*"
},
"openclaw": {
"bundle": {
"stageRuntimeDependencies": true
},
"extensions": [
"./index.ts"
]
],
"install": {
"npmSpec": "@openclaw/diffs",
"localPath": "extensions/diffs",
"defaultChoice": "npm",
"minHostVersion": ">=2026.4.30"
},
"compat": {
"pluginApi": ">=2026.4.30"
},
"build": {
"openclawVersion": "2026.4.30"
},
"bundle": {
"includeInCore": false
},
"release": {
"publishToClawHub": true,
"publishToNpm": true
}
}
}

View File

@@ -3,20 +3,14 @@ import { describe, expect, it } from "vitest";
type DiffsPackageManifest = {
dependencies?: Record<string, string>;
openclaw?: {
bundle?: {
stageRuntimeDependencies?: boolean;
};
};
};
describe("diffs package manifest", () => {
it("opts into staging bundled runtime dependencies", () => {
it("keeps runtime dependencies in the package manifest", () => {
const packageJson = JSON.parse(
fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
) as DiffsPackageManifest;
expect(packageJson.dependencies?.["@pierre/diffs"]).toBeDefined();
expect(packageJson.openclaw?.bundle?.stageRuntimeDependencies).toBe(true);
});
});

View File

@@ -59,9 +59,6 @@
"build": {
"openclawVersion": "2026.4.25"
},
"bundle": {
"stageRuntimeDependencies": true
},
"release": {
"publishToClawHub": true,
"publishToNpm": true

View File

@@ -48,9 +48,6 @@
"build": {
"openclawVersion": "2026.4.25"
},
"bundle": {
"stageRuntimeDependencies": true
},
"release": {
"publishToClawHub": true,
"publishToNpm": true

View File

@@ -13,9 +13,6 @@
"openclaw": {
"extensions": [
"./index.ts"
],
"bundle": {
"stageRuntimeDependencies": false
}
]
}
}

View File

@@ -12,9 +12,6 @@
"@openclaw/plugin-sdk": "workspace:*"
},
"openclaw": {
"bundle": {
"stageRuntimeDependencies": true
},
"extensions": [
"./index.ts"
]

View File

@@ -22,9 +22,6 @@
}
},
"openclaw": {
"bundle": {
"stageRuntimeDependencies": true
},
"extensions": [
"./index.ts"
],

View File

@@ -80,9 +80,6 @@
"defaultChoice": "npm",
"minHostVersion": ">=2026.4.10",
"allowInvalidConfigRecovery": true
},
"bundle": {
"stageRuntimeDependencies": true
}
}
}

View File

@@ -3,20 +3,14 @@ import { describe, expect, it } from "vitest";
type MatrixPackageManifest = {
dependencies?: Record<string, string>;
openclaw?: {
bundle?: {
stageRuntimeDependencies?: boolean;
};
};
};
describe("matrix package manifest", () => {
it("opts into staging bundled runtime dependencies", () => {
it("keeps runtime dependencies in the package manifest", () => {
const packageJson = JSON.parse(
fs.readFileSync(new URL("../package.json", import.meta.url), "utf8"),
) as MatrixPackageManifest;
expect(packageJson.dependencies?.["fake-indexeddb"]).toBeDefined();
expect(packageJson.openclaw?.bundle?.stageRuntimeDependencies).toBe(true);
});
});

View File

@@ -10,9 +10,5 @@
"devDependencies": {
"@openclaw/plugin-sdk": "workspace:*"
},
"openclaw": {
"bundle": {
"stageRuntimeDependencies": true
}
}
"openclaw": {}
}

View File

@@ -7,9 +7,6 @@
"contracts": {
"memoryEmbeddingProviders": ["local"]
},
"runtimeDependencies": {
"localMemoryEmbedding": ["node-llama-cpp@3.18.1"]
},
"commandAliases": [
{
"name": "dreaming",

View File

@@ -59,9 +59,6 @@
"build": {
"openclawVersion": "2026.4.25"
},
"bundle": {
"stageRuntimeDependencies": true
},
"release": {
"publishToClawHub": true,
"publishToNpm": true

View File

@@ -55,9 +55,6 @@
"build": {
"openclawVersion": "2026.4.25"
},
"bundle": {
"stageRuntimeDependencies": true
},
"release": {
"publishToClawHub": true,
"publishToNpm": true

View File

@@ -65,7 +65,9 @@ function raiseMinimalReasoningForOpenAINativeWebSearch(payload: Record<string, u
reasoning.effort = "low";
}
function patchOpenAINativeWebSearchPayload(payload: unknown): OpenAINativeWebSearchPatchResult {
export function patchOpenAINativeWebSearchPayload(
payload: unknown,
): OpenAINativeWebSearchPatchResult {
if (!isRecord(payload)) {
return "payload_not_object";
}

View File

@@ -21,11 +21,6 @@ const packageJson = JSON.parse(
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
) as {
dependencies?: Record<string, string>;
openclaw?: {
bundle?: {
stageRuntimeDependencies?: boolean;
};
};
};
function manifestComparableWizardFields(choice: {
@@ -64,10 +59,9 @@ function providerWizardByKey() {
}
describe("OpenAI plugin manifest", () => {
it("opts into staging bundled runtime dependencies", () => {
it("keeps runtime dependencies in the package manifest", () => {
expect(packageJson.dependencies?.["@mariozechner/pi-ai"]).toBe("0.71.1");
expect(packageJson.dependencies?.ws).toBe("^8.20.0");
expect(packageJson.openclaw?.bundle?.stageRuntimeDependencies).toBe(true);
});
it("keeps removed Codex CLI import auth choice as a deprecated browser-login alias", () => {

View File

@@ -12,9 +12,6 @@
"@openclaw/plugin-sdk": "workspace:*"
},
"openclaw": {
"bundle": {
"stageRuntimeDependencies": true
},
"extensions": [
"./index.ts"
]

View File

@@ -934,8 +934,8 @@ describe("qa bundled plugin dir", () => {
).resolves.toBeTruthy();
});
it("skips transient runtime dependency artifacts while staging built bundled plugins", async () => {
const repoRoot = await mkdtemp(path.join(os.tmpdir(), "qa-bundled-runtime-deps-"));
it("skips legacy dependency debris while staging built bundled plugins", async () => {
const repoRoot = await mkdtemp(path.join(os.tmpdir(), "qa-bundled-legacy-deps-"));
cleanups.push(async () => {
await rm(repoRoot, { recursive: true, force: true });
});
@@ -961,7 +961,7 @@ describe("qa bundled plugin dir", () => {
"export {};\n",
"utf8",
);
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "qa-bundled-runtime-deps-target-"));
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "qa-bundled-legacy-deps-target-"));
cleanups.push(async () => {
await rm(tempRoot, { recursive: true, force: true });
});

View File

@@ -52,7 +52,7 @@
"openclawVersion": "2026.4.27"
},
"bundle": {
"stageRuntimeDependencies": true
"includeInCore": false
},
"release": {
"publishToClawHub": true,

View File

@@ -36,9 +36,6 @@
"specifier": "./configured-state",
"exportName": "hasSlackConfiguredState"
}
},
"bundle": {
"stageRuntimeDependencies": true
}
}
}

View File

@@ -46,9 +46,6 @@
"specifier": "./configured-state",
"exportName": "hasTelegramConfiguredState"
}
},
"bundle": {
"stageRuntimeDependencies": true
}
}
}

View File

@@ -3,11 +3,6 @@ import { describe, expect, it } from "vitest";
type TokenjuicePackageManifest = {
dependencies?: Record<string, string>;
openclaw?: {
bundle?: {
stageRuntimeDependencies?: boolean;
};
};
};
type TokenjuicePluginManifest = {
@@ -17,13 +12,12 @@ type TokenjuicePluginManifest = {
};
describe("tokenjuice package manifest", () => {
it("opts into staging bundled runtime dependencies", () => {
it("keeps runtime dependencies in the package manifest", () => {
const packageJson = JSON.parse(
fs.readFileSync(new URL("./package.json", import.meta.url), "utf8"),
) as TokenjuicePackageManifest;
expect(packageJson.dependencies?.tokenjuice).toBe("0.7.0");
expect(packageJson.openclaw?.bundle?.stageRuntimeDependencies).toBe(true);
});
it("declares runtime-neutral tool result middleware ownership in the manifest contract", () => {

View File

@@ -12,9 +12,6 @@
"openclaw": {
"extensions": [
"./index.ts"
],
"bundle": {
"stageRuntimeDependencies": true
}
]
}
}

View File

@@ -11,9 +11,6 @@
"@openclaw/plugin-sdk": "workspace:*"
},
"openclaw": {
"bundle": {
"stageRuntimeDependencies": true
},
"extensions": [
"./index.ts"
]

View File

@@ -59,9 +59,6 @@
"compat": {
"pluginApi": ">=2026.4.25"
},
"bundle": {
"stageRuntimeDependencies": true
},
"build": {
"openclawVersion": "2026.4.25"
},