fix(plugins): ignore inherited npm dry-run for runtime deps

This commit is contained in:
Peter Steinberger
2026-04-28 02:36:19 +01:00
parent 13ff3142bd
commit 7d4da9c610
7 changed files with 35 additions and 0 deletions

View File

@@ -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.

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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",

View File

@@ -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: {