From e763ea1119649adc92e658d1bb50adac3c4777ce Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 23 Apr 2026 05:48:38 +0100 Subject: [PATCH] fix(plugins): stop tracking runtime deps manifests --- .gitignore | 4 ++ .../.openclaw-runtime-deps.json | 7 --- .../.openclaw-runtime-deps.json | 7 --- .../anthropic/.openclaw-runtime-deps.json | 3 -- extensions/brave/.openclaw-runtime-deps.json | 3 -- extensions/codex/.openclaw-runtime-deps.json | 3 -- .../firecrawl/.openclaw-runtime-deps.json | 3 -- .../fireworks/.openclaw-runtime-deps.json | 3 -- .../.openclaw-runtime-deps.json | 3 -- extensions/google/.openclaw-runtime-deps.json | 3 -- .../kimi-coding/.openclaw-runtime-deps.json | 3 -- .../lmstudio/.openclaw-runtime-deps.json | 3 -- .../mistral/.openclaw-runtime-deps.json | 3 -- extensions/ollama/.openclaw-runtime-deps.json | 3 -- extensions/openai/.openclaw-runtime-deps.json | 3 -- extensions/tavily/.openclaw-runtime-deps.json | 3 -- extensions/xai/.openclaw-runtime-deps.json | 3 -- src/plugins/bundled-runtime-deps.test.ts | 46 ++++++++++++++++++- src/plugins/bundled-runtime-deps.ts | 29 +++++++++++- 19 files changed, 76 insertions(+), 59 deletions(-) delete mode 100644 extensions/amazon-bedrock-mantle/.openclaw-runtime-deps.json delete mode 100644 extensions/amazon-bedrock/.openclaw-runtime-deps.json delete mode 100644 extensions/anthropic/.openclaw-runtime-deps.json delete mode 100644 extensions/brave/.openclaw-runtime-deps.json delete mode 100644 extensions/codex/.openclaw-runtime-deps.json delete mode 100644 extensions/firecrawl/.openclaw-runtime-deps.json delete mode 100644 extensions/fireworks/.openclaw-runtime-deps.json delete mode 100644 extensions/github-copilot/.openclaw-runtime-deps.json delete mode 100644 extensions/google/.openclaw-runtime-deps.json delete mode 100644 extensions/kimi-coding/.openclaw-runtime-deps.json delete mode 100644 extensions/lmstudio/.openclaw-runtime-deps.json delete mode 100644 extensions/mistral/.openclaw-runtime-deps.json delete mode 100644 extensions/ollama/.openclaw-runtime-deps.json delete mode 100644 extensions/openai/.openclaw-runtime-deps.json delete mode 100644 extensions/tavily/.openclaw-runtime-deps.json delete mode 100644 extensions/xai/.openclaw-runtime-deps.json diff --git a/.gitignore b/.gitignore index 7b882fc2402..9588d168b4b 100644 --- a/.gitignore +++ b/.gitignore @@ -152,3 +152,7 @@ test/fixtures/openclaw-vitest-unit-report.json analysis/ .artifacts/qa-e2e/ extensions/qa-lab/web/dist/ + +# Generated bundled plugin runtime dependency manifests +extensions/**/.openclaw-runtime-deps.json +extensions/**/.openclaw-runtime-deps-stamp.json diff --git a/extensions/amazon-bedrock-mantle/.openclaw-runtime-deps.json b/extensions/amazon-bedrock-mantle/.openclaw-runtime-deps.json deleted file mode 100644 index c5df11fa2ef..00000000000 --- a/extensions/amazon-bedrock-mantle/.openclaw-runtime-deps.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "specs": [ - "@anthropic-ai/sdk@0.90.0", - "@aws/bedrock-token-generator@^1.1.0", - "@mariozechner/pi-ai@0.69.0" - ] -} diff --git a/extensions/amazon-bedrock/.openclaw-runtime-deps.json b/extensions/amazon-bedrock/.openclaw-runtime-deps.json deleted file mode 100644 index 7b5d1821f13..00000000000 --- a/extensions/amazon-bedrock/.openclaw-runtime-deps.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "specs": [ - "@aws-sdk/client-bedrock-runtime@3.1033.0", - "@aws-sdk/client-bedrock@3.1033.0", - "@aws-sdk/credential-provider-node@3.972.33" - ] -} diff --git a/extensions/anthropic/.openclaw-runtime-deps.json b/extensions/anthropic/.openclaw-runtime-deps.json deleted file mode 100644 index d6173cc32ab..00000000000 --- a/extensions/anthropic/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["@mariozechner/pi-ai@0.69.0"] -} diff --git a/extensions/brave/.openclaw-runtime-deps.json b/extensions/brave/.openclaw-runtime-deps.json deleted file mode 100644 index d7dc02e19bf..00000000000 --- a/extensions/brave/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["typebox@1.1.28"] -} diff --git a/extensions/codex/.openclaw-runtime-deps.json b/extensions/codex/.openclaw-runtime-deps.json deleted file mode 100644 index 6194276ad21..00000000000 --- a/extensions/codex/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["@mariozechner/pi-coding-agent@0.69.0", "ws@^8.20.0", "zod@^4.3.6"] -} diff --git a/extensions/firecrawl/.openclaw-runtime-deps.json b/extensions/firecrawl/.openclaw-runtime-deps.json deleted file mode 100644 index d7dc02e19bf..00000000000 --- a/extensions/firecrawl/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["typebox@1.1.28"] -} diff --git a/extensions/fireworks/.openclaw-runtime-deps.json b/extensions/fireworks/.openclaw-runtime-deps.json deleted file mode 100644 index d6173cc32ab..00000000000 --- a/extensions/fireworks/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["@mariozechner/pi-ai@0.69.0"] -} diff --git a/extensions/github-copilot/.openclaw-runtime-deps.json b/extensions/github-copilot/.openclaw-runtime-deps.json deleted file mode 100644 index cf69f849ac0..00000000000 --- a/extensions/github-copilot/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["@clack/prompts@^1.2.0", "@mariozechner/pi-ai@0.69.0"] -} diff --git a/extensions/google/.openclaw-runtime-deps.json b/extensions/google/.openclaw-runtime-deps.json deleted file mode 100644 index db5df21dd84..00000000000 --- a/extensions/google/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["@google/genai@^1.50.1", "@mariozechner/pi-ai@0.69.0"] -} diff --git a/extensions/kimi-coding/.openclaw-runtime-deps.json b/extensions/kimi-coding/.openclaw-runtime-deps.json deleted file mode 100644 index d6173cc32ab..00000000000 --- a/extensions/kimi-coding/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["@mariozechner/pi-ai@0.69.0"] -} diff --git a/extensions/lmstudio/.openclaw-runtime-deps.json b/extensions/lmstudio/.openclaw-runtime-deps.json deleted file mode 100644 index d6173cc32ab..00000000000 --- a/extensions/lmstudio/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["@mariozechner/pi-ai@0.69.0"] -} diff --git a/extensions/mistral/.openclaw-runtime-deps.json b/extensions/mistral/.openclaw-runtime-deps.json deleted file mode 100644 index b762204638d..00000000000 --- a/extensions/mistral/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["ws@^8.20.0"] -} diff --git a/extensions/ollama/.openclaw-runtime-deps.json b/extensions/ollama/.openclaw-runtime-deps.json deleted file mode 100644 index b791e12d1f9..00000000000 --- a/extensions/ollama/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["@mariozechner/pi-ai@0.69.0", "typebox@1.1.28"] -} diff --git a/extensions/openai/.openclaw-runtime-deps.json b/extensions/openai/.openclaw-runtime-deps.json deleted file mode 100644 index ebfe980ffa9..00000000000 --- a/extensions/openai/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["@mariozechner/pi-ai@0.69.0", "ws@^8.20.0"] -} diff --git a/extensions/tavily/.openclaw-runtime-deps.json b/extensions/tavily/.openclaw-runtime-deps.json deleted file mode 100644 index d7dc02e19bf..00000000000 --- a/extensions/tavily/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["typebox@1.1.28"] -} diff --git a/extensions/xai/.openclaw-runtime-deps.json b/extensions/xai/.openclaw-runtime-deps.json deleted file mode 100644 index a7342e22d7f..00000000000 --- a/extensions/xai/.openclaw-runtime-deps.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "specs": ["@mariozechner/pi-ai@0.69.0", "typebox@1.1.28", "ws@^8.20.0"] -} diff --git a/src/plugins/bundled-runtime-deps.test.ts b/src/plugins/bundled-runtime-deps.test.ts index ea3569e75bb..1ba15e5ba07 100644 --- a/src/plugins/bundled-runtime-deps.test.ts +++ b/src/plugins/bundled-runtime-deps.test.ts @@ -575,14 +575,21 @@ describe("ensureBundledPluginRuntimeDeps", () => { ]); expect(installRoot).toContain(stageDir); expect(installRoot).not.toBe(pluginRoot); + expect( + JSON.parse(fs.readFileSync(path.join(installRoot, ".openclaw-runtime-deps.json"), "utf8")), + ).toEqual({ specs: ["tokenjuice@0.6.1"] }); }); - it("keeps source-checkout bundled runtime deps in the plugin root by default", () => { + it("keeps source-checkout bundled runtime deps in the plugin root without manifest churn", () => { const packageRoot = makeTempDir(); fs.mkdirSync(path.join(packageRoot, ".git"), { recursive: true }); fs.mkdirSync(path.join(packageRoot, "src"), { recursive: true }); const pluginRoot = path.join(packageRoot, "extensions", "tokenjuice"); fs.mkdirSync(pluginRoot, { recursive: true }); + fs.writeFileSync( + path.join(pluginRoot, ".openclaw-runtime-deps.json"), + JSON.stringify({ specs: ["stale@9.9.9"] }), + ); fs.writeFileSync( path.join(pluginRoot, "package.json"), JSON.stringify({ @@ -617,6 +624,43 @@ describe("ensureBundledPluginRuntimeDeps", () => { }, ]); expect(resolveBundledRuntimeDependencyInstallRoot(pluginRoot, { env: {} })).toBe(pluginRoot); + expect(fs.existsSync(path.join(pluginRoot, ".openclaw-runtime-deps.json"))).toBe(false); + }); + + it("removes stale source-checkout manifests even when runtime deps are present", () => { + const packageRoot = makeTempDir(); + fs.mkdirSync(path.join(packageRoot, ".git"), { recursive: true }); + fs.mkdirSync(path.join(packageRoot, "src"), { recursive: true }); + const pluginRoot = path.join(packageRoot, "extensions", "tokenjuice"); + fs.mkdirSync(path.join(pluginRoot, "node_modules", "tokenjuice"), { recursive: true }); + fs.writeFileSync( + path.join(pluginRoot, "package.json"), + JSON.stringify({ + dependencies: { + tokenjuice: "0.6.1", + }, + }), + ); + fs.writeFileSync( + path.join(pluginRoot, "node_modules", "tokenjuice", "package.json"), + JSON.stringify({ name: "tokenjuice", version: "0.6.1" }), + ); + fs.writeFileSync( + path.join(pluginRoot, ".openclaw-runtime-deps.json"), + JSON.stringify({ specs: ["stale@9.9.9"] }), + ); + + const result = ensureBundledPluginRuntimeDeps({ + env: {}, + installDeps: () => { + throw new Error("present source-checkout runtime deps should not reinstall"); + }, + pluginId: "tokenjuice", + pluginRoot, + }); + + expect(result).toEqual({ installedSpecs: [], retainSpecs: [] }); + expect(fs.existsSync(path.join(pluginRoot, ".openclaw-runtime-deps.json"))).toBe(false); }); it("treats Docker build source trees without .git as source checkouts", () => { diff --git a/src/plugins/bundled-runtime-deps.ts b/src/plugins/bundled-runtime-deps.ts index 653b954fc95..9ec9c11f7d3 100644 --- a/src/plugins/bundled-runtime-deps.ts +++ b/src/plugins/bundled-runtime-deps.ts @@ -263,6 +263,20 @@ function writeRetainedRuntimeDepsManifest(installRoot: string, specs: readonly s ); } +function removeRetainedRuntimeDepsManifest(installRoot: string): void { + fs.rmSync(path.join(installRoot, RETAINED_RUNTIME_DEPS_MANIFEST), { force: true }); +} + +function shouldPersistRetainedRuntimeDepsManifest(params: { + pluginRoot: string; + installRoot: string; +}): boolean { + if (path.resolve(params.installRoot) !== path.resolve(params.pluginRoot)) { + return true; + } + return !resolveSourceCheckoutPackageRoot(params.pluginRoot); +} + export function isWritableDirectory(dir: string): boolean { let probeDir: string | null = null; try { @@ -873,6 +887,13 @@ export function ensureBundledPluginRuntimeDeps(params: { const installRoot = resolveBundledRuntimeDependencyInstallRoot(params.pluginRoot, { env: params.env, }); + const persistRetainedManifest = shouldPersistRetainedRuntimeDepsManifest({ + pluginRoot: params.pluginRoot, + installRoot, + }); + if (!persistRetainedManifest) { + removeRetainedRuntimeDepsManifest(installRoot); + } const dependencySpecs = deps .map((dep) => `${dep.name}@${dep.version}`) .toSorted((left, right) => left.localeCompare(right)); @@ -883,7 +904,9 @@ export function ensureBundledPluginRuntimeDeps(params: { if (missingSpecs.length === 0) { return { installedSpecs: [], retainSpecs: [] }; } - const retainedManifestSpecs = readRetainedRuntimeDepsManifest(installRoot); + const retainedManifestSpecs = persistRetainedManifest + ? readRetainedRuntimeDepsManifest(installRoot) + : []; const installSpecs = [ ...new Set([...(params.retainSpecs ?? []), ...retainedManifestSpecs, ...dependencySpecs]), ].toSorted((left, right) => left.localeCompare(right)); @@ -918,7 +941,9 @@ export function ensureBundledPluginRuntimeDeps(params: { env: params.env, })); install({ installRoot, installExecutionRoot, missingSpecs, installSpecs }); - writeRetainedRuntimeDepsManifest(installRoot, installSpecs); + if (persistRetainedManifest) { + writeRetainedRuntimeDepsManifest(installRoot, installSpecs); + } storeSourceCheckoutRuntimeDepsCache({ cacheDir, installRoot }); return { installedSpecs: missingSpecs, retainSpecs: installSpecs }; }