From 7d4da9c610c81e1f73cbae175fd26d6843586374 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 28 Apr 2026 02:36:19 +0100 Subject: [PATCH] fix(plugins): ignore inherited npm dry-run for runtime deps --- CHANGELOG.md | 1 + scripts/postinstall-bundled-plugins.mjs | 1 + scripts/stage-bundled-plugin-runtime-deps.mjs | 1 + src/infra/npm-install-env.ts | 2 ++ src/plugins/bundled-runtime-deps.test.ts | 3 +++ .../postinstall-bundled-plugins.test.ts | 2 ++ .../stage-bundled-plugin-runtime-deps.test.ts | 25 +++++++++++++++++++ 7 files changed, 35 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98bf0941466..75689643dba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ Docs: https://docs.openclaw.ai - Doctor/channels: suppress disabled bundled-plugin blocker warnings when a trusted external plugin owns the configured channel, so Lark/Feishu installs no longer get Feishu repair noise after switching to `openclaw-lark`. Fixes #56794. Thanks @wuji-tech-dev. - CLI/status: show skipped fast-path memory checks as `not checked` and report active custom memory plugin runtime status from `status --json --all` without requiring built-in `agents.defaults.memorySearch`, so plugins such as memory-lancedb-pro and memory-cms no longer look unavailable when their own runtime is healthy. Fixes #56968. Thanks @Tony-ooo and @aderius. - Gateway/channels: record and log unexpected clean channel monitor exits so channels that return without throwing no longer appear stopped with no error. Fixes #73099. Thanks @balaji1968-kingler. +- Plugins/package: force nested bundled-plugin runtime dependency installs out of inherited npm dry-run mode during prepack and package smoke checks, so packed installs materialize required plugin modules instead of reporting missing bundled files. Refs #73128. Thanks @Adam-Researchh. - Channels/Telegram: centralize polling update tracking so accepted offsets remain durable across restarts, same-process handler failures can still retry, and slow offset writes cannot overwrite newer accepted watermarks. Refs #73115. Thanks @vdruts. - Agents/models: classify empty, reasoning-only, and planning-only terminal agent runs before accepting a model fallback candidate, so invalid or incompatible models can advance to the next configured fallback instead of returning a 30-second terminal failure. Fixes #73115. Thanks @vdruts. - Memory/LanceDB: let embedding config use provider-backed auth profiles, environment credentials, or provider config without a separate plugin `embedding.apiKey`, so OAuth-capable embedding providers can power auto-recall/capture. Fixes #68950. Thanks @malshaalan-ai. diff --git a/scripts/postinstall-bundled-plugins.mjs b/scripts/postinstall-bundled-plugins.mjs index 4d97e71dd5f..f3816d17ab0 100644 --- a/scripts/postinstall-bundled-plugins.mjs +++ b/scripts/postinstall-bundled-plugins.mjs @@ -450,6 +450,7 @@ export function createNestedNpmInstallEnv(env = process.env) { export function createBundledRuntimeDependencyInstallEnv(env = process.env) { return { ...createNestedNpmInstallEnv(env), + npm_config_dry_run: "false", npm_config_legacy_peer_deps: "true", npm_config_package_lock: "false", npm_config_save: "false", diff --git a/scripts/stage-bundled-plugin-runtime-deps.mjs b/scripts/stage-bundled-plugin-runtime-deps.mjs index 2b9507253f5..ffe90358f70 100644 --- a/scripts/stage-bundled-plugin-runtime-deps.mjs +++ b/scripts/stage-bundled-plugin-runtime-deps.mjs @@ -885,6 +885,7 @@ function runNpmInstall(params) { ...(params.npmRunner.env ?? process.env), CI: "1", npm_config_audit: "false", + npm_config_dry_run: "false", npm_config_fund: "false", npm_config_legacy_peer_deps: "true", npm_config_loglevel: "error", diff --git a/src/infra/npm-install-env.ts b/src/infra/npm-install-env.ts index 039035742a6..de42371dea8 100644 --- a/src/infra/npm-install-env.ts +++ b/src/infra/npm-install-env.ts @@ -4,6 +4,7 @@ export type NpmProjectInstallEnvOptions = { const NPM_CONFIG_KEYS_TO_RESET = new Set([ "npm_config_cache", + "npm_config_dry_run", "npm_config_global", "npm_config_location", "npm_config_prefix", @@ -21,6 +22,7 @@ export function createNpmProjectInstallEnv( } return { ...nextEnv, + npm_config_dry_run: "false", npm_config_global: "false", npm_config_location: "project", npm_config_package_lock: "false", diff --git a/src/plugins/bundled-runtime-deps.test.ts b/src/plugins/bundled-runtime-deps.test.ts index d53138243ba..70aecfced78 100644 --- a/src/plugins/bundled-runtime-deps.test.ts +++ b/src/plugins/bundled-runtime-deps.test.ts @@ -135,6 +135,7 @@ describe("resolveBundledRuntimeDepsNpmRunner", () => { NPM_CONFIG_LOCATION: "global", NPM_CONFIG_PREFIX: "/Users/alice", npm_config_cache: "/Users/alice/.npm", + npm_config_dry_run: "true", npm_config_global: "true", npm_config_location: "global", npm_config_prefix: "/opt/homebrew", @@ -144,6 +145,7 @@ describe("resolveBundledRuntimeDepsNpmRunner", () => { ).toEqual({ PATH: "/usr/bin:/bin", npm_config_cache: "/opt/openclaw/runtime-cache", + npm_config_dry_run: "false", npm_config_global: "false", npm_config_legacy_peer_deps: "true", npm_config_location: "project", @@ -320,6 +322,7 @@ describe("installBundledRuntimeDeps", () => { cwd: installRoot, windowsHide: true, env: expect.objectContaining({ + npm_config_dry_run: "false", npm_config_legacy_peer_deps: "true", npm_config_package_lock: "false", npm_config_save: "false", diff --git a/test/scripts/postinstall-bundled-plugins.test.ts b/test/scripts/postinstall-bundled-plugins.test.ts index 34107e7262f..06cefb18fee 100644 --- a/test/scripts/postinstall-bundled-plugins.test.ts +++ b/test/scripts/postinstall-bundled-plugins.test.ts @@ -142,10 +142,12 @@ describe("bundled plugin postinstall", () => { expect( createBundledRuntimeDependencyInstallEnv({ HOME: "/tmp/home", + npm_config_dry_run: "true", npm_config_prefix: "/opt/homebrew", }), ).toEqual({ HOME: "/tmp/home", + npm_config_dry_run: "false", npm_config_legacy_peer_deps: "true", npm_config_package_lock: "false", npm_config_save: "false", diff --git a/test/scripts/stage-bundled-plugin-runtime-deps.test.ts b/test/scripts/stage-bundled-plugin-runtime-deps.test.ts index db08f95df44..784a251ceab 100644 --- a/test/scripts/stage-bundled-plugin-runtime-deps.test.ts +++ b/test/scripts/stage-bundled-plugin-runtime-deps.test.ts @@ -155,6 +155,31 @@ describe("stageBundledPluginRuntimeDeps", () => { ); }); + it("forces fallback runtime installs off inherited npm dry-run mode", () => { + const spawnSyncImpl = vi.fn(() => ({ status: 0, stderr: "", stdout: "" })); + + stageBundledPluginRuntimeDepsTesting.runNpmInstall({ + cwd: "/tmp/openclaw-runtime-deps", + npmRunner: { + command: "npm", + args: ["install"], + env: { PATH: "/usr/bin", npm_config_dry_run: "true" }, + shell: false, + }, + spawnSyncImpl, + }); + + expect(spawnSyncImpl).toHaveBeenCalledWith( + "npm", + ["install"], + expect.objectContaining({ + env: expect.objectContaining({ + npm_config_dry_run: "false", + }), + }), + ); + }); + it("skips restaging when runtime deps stamp matches the sanitized manifest", () => { const { pluginDir, repoRoot } = createBundledPluginFixture({ packageJson: {