fix(plugins): clean resolved npm load paths · openclaw/openclaw@ac00d78
vincentkoc
·
2026-05-04
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -75,6 +75,7 @@ Docs: https://docs.openclaw.ai
|
75 | 75 | - OpenAI Codex: let SSRF-guarded provider requests inherit OpenClaw's undici IPv4/IPv6 fallback policy, so ChatGPT-backed Codex runs recover on IPv4-working hosts when DNS still returns unreachable IPv6 addresses. Fixes #76857. Thanks @jplavoiemtl and @SymbolStar. |
76 | 76 | - Gateway/systemd: preserve operator-added secrets in the Gateway env file across re-stage while clearing OpenClaw-managed keys (such as `OPENCLAW_GATEWAY_TOKEN`) so a fresh staging value is never shadowed by a stale env-file copy; operator secrets are also retained when the state-dir `.env` is empty. Fixes #76860. Thanks @hclsys. |
77 | 77 | - Plugin updates: do not short-circuit trusted official npm updates as unchanged when the default/latest spec still resolves to an already-installed prerelease that the installer should replace with a stable fallback. Thanks @vincentkoc. |
| 78 | +- Plugin updates: clean stale bundled load paths for already-externalized npm installs whose legacy install record only preserved the resolved package name. Thanks @vincentkoc. |
78 | 79 | - Plugin tools: keep auth-unavailable optional tools hidden even when another default tool from the same plugin is available and `tools.alsoAllow` names the optional tool. Thanks @vincentkoc. |
79 | 80 | - Realtime transcription: report socket closes before provider readiness as closed-before-ready failures instead of mislabeling them as connection timeouts for OpenAI, xAI, and Deepgram streaming transcription. Thanks @vincentkoc. |
80 | 81 | - OpenAI/Google Meet: fail realtime voice connection attempts when the socket closes before `session.updated`, avoiding stuck Meet joins waiting on a bridge that never became ready. Thanks @vincentkoc. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -2620,6 +2620,48 @@ describe("syncPluginsForUpdateChannel", () => {
|
2620 | 2620 | }); |
2621 | 2621 | }); |
2622 | 2622 | |
| 2623 | +it("removes stale bundled load paths for already-externalized resolved-name-only npm installs", async () => { |
| 2624 | +resolveBundledPluginSourcesMock.mockReturnValue(new Map()); |
| 2625 | + |
| 2626 | +const result = await syncPluginsForUpdateChannel({ |
| 2627 | +channel: "stable", |
| 2628 | +externalizedBundledPluginBridges: [ |
| 2629 | +{ |
| 2630 | +bundledPluginId: "legacy-chat", |
| 2631 | +npmSpec: "@openclaw/legacy-chat", |
| 2632 | +channelIds: ["legacy-chat"], |
| 2633 | +}, |
| 2634 | +], |
| 2635 | +config: { |
| 2636 | +channels: { |
| 2637 | +"legacy-chat": { |
| 2638 | +enabled: true, |
| 2639 | +}, |
| 2640 | +}, |
| 2641 | +plugins: { |
| 2642 | +load: { |
| 2643 | +paths: [appBundledPluginRoot("legacy-chat"), "/workspace/plugins/other"], |
| 2644 | +}, |
| 2645 | +installs: { |
| 2646 | +"legacy-chat": { |
| 2647 | +source: "npm", |
| 2648 | +resolvedName: "@openclaw/legacy-chat", |
| 2649 | +installPath: "/tmp/openclaw-plugins/legacy-chat", |
| 2650 | +}, |
| 2651 | +}, |
| 2652 | +}, |
| 2653 | +}, |
| 2654 | +}); |
| 2655 | + |
| 2656 | +expect(installPluginFromNpmSpecMock).not.toHaveBeenCalled(); |
| 2657 | +expect(result.changed).toBe(true); |
| 2658 | +expect(result.config.plugins?.load?.paths).toEqual(["/workspace/plugins/other"]); |
| 2659 | +expect(result.config.plugins?.installs?.["legacy-chat"]).toMatchObject({ |
| 2660 | +source: "npm", |
| 2661 | +resolvedName: "@openclaw/legacy-chat", |
| 2662 | +}); |
| 2663 | +}); |
| 2664 | + |
2623 | 2665 | it("removes stale bundled load paths for already-externalized pinned npm installs", async () => { |
2624 | 2666 | resolveBundledPluginSourcesMock.mockReturnValue(new Map()); |
2625 | 2667 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -580,6 +580,7 @@ function isBridgeAlreadyInstalledFromPreferredSource(params: {
|
580 | 580 | if (npmSpec && params.record.source === "npm") { |
581 | 581 | const bridgePackageName = resolveNpmSpecPackageName(npmSpec); |
582 | 582 | const recordPackageName = |
| 583 | +params.record.resolvedName ?? |
583 | 584 | resolveNpmSpecPackageName(params.record.spec) ?? |
584 | 585 | resolveNpmSpecPackageName(params.record.resolvedSpec); |
585 | 586 | if (bridgePackageName && recordPackageName === bridgePackageName) { |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。