

























@@ -3,10 +3,13 @@ import type { OpenClawConfig } from "../config/config.js";
33import {
44applyExclusiveSlotSelection,
55buildPluginDiagnosticsReport,
6+clearPluginRegistryLoadCache,
67enablePluginInConfig,
78loadPluginManifestRegistry,
9+replaceConfigFile,
810refreshPluginRegistry,
911resetPluginsCliTestState,
12+runtimeLogs,
1013writeConfigFile,
1114writePersistedInstalledPluginIndexInstallRecords,
1215} from "./plugins-cli-test-helpers.js";
@@ -60,6 +63,14 @@ describe("persistPluginInstall", () => {
6063}),
6164});
6265expect(writeConfigFile).toHaveBeenCalledWith(enabledConfig);
66+expect(replaceConfigFile).toHaveBeenCalledWith({
67+nextConfig: enabledConfig,
68+baseHash: "config-1",
69+writeOptions: {
70+afterWrite: { mode: "restart", reason: "plugin source changed" },
71+unsetPaths: [["plugins", "installs"]],
72+},
73+});
6374expect(refreshPluginRegistry).toHaveBeenCalledWith({
6475config: enabledConfig,
6576installRecords: {
@@ -71,6 +82,82 @@ describe("persistPluginInstall", () => {
7182},
7283reason: "source-changed",
7384});
85+expect(clearPluginRegistryLoadCache).toHaveBeenCalledTimes(1);
86+});
87+88+it("persists installs even when runtime cache invalidation fails", async () => {
89+const { persistPluginInstall } = await import("./plugins-install-persist.js");
90+const baseConfig = {
91+plugins: {
92+entries: {},
93+},
94+} as OpenClawConfig;
95+const enabledConfig = {
96+plugins: {
97+entries: {
98+alpha: { enabled: true },
99+},
100+},
101+} as OpenClawConfig;
102+enablePluginInConfig.mockReturnValue({ config: enabledConfig });
103+clearPluginRegistryLoadCache.mockImplementation(() => {
104+throw new Error("cache unavailable");
105+});
106+107+const next = await persistPluginInstall({
108+snapshot: {
109+config: baseConfig,
110+baseHash: "config-1",
111+},
112+pluginId: "alpha",
113+install: {
114+source: "npm",
115+spec: "alpha@1.0.0",
116+installPath: "/tmp/alpha",
117+},
118+});
119+120+expect(next).toEqual(enabledConfig);
121+expect(refreshPluginRegistry).toHaveBeenCalled();
122+expect(
123+runtimeLogs.some((line) => line.includes("Plugin runtime cache invalidation failed")),
124+).toBe(true);
125+});
126+127+it("invalidates runtime cache even when registry refresh fails", async () => {
128+const { persistPluginInstall } = await import("./plugins-install-persist.js");
129+const baseConfig = {
130+plugins: {
131+entries: {},
132+},
133+} as OpenClawConfig;
134+const enabledConfig = {
135+plugins: {
136+entries: {
137+alpha: { enabled: true },
138+},
139+},
140+} as OpenClawConfig;
141+enablePluginInConfig.mockReturnValue({ config: enabledConfig });
142+refreshPluginRegistry.mockRejectedValueOnce(new Error("registry unavailable"));
143+144+const next = await persistPluginInstall({
145+snapshot: {
146+config: baseConfig,
147+baseHash: "config-1",
148+},
149+pluginId: "alpha",
150+install: {
151+source: "npm",
152+spec: "alpha@1.0.0",
153+installPath: "/tmp/alpha",
154+},
155+});
156+157+expect(next).toEqual(enabledConfig);
158+expect(refreshPluginRegistry).toHaveBeenCalled();
159+expect(clearPluginRegistryLoadCache).toHaveBeenCalledTimes(1);
160+expect(runtimeLogs.some((line) => line.includes("Plugin registry refresh failed"))).toBe(true);
74161});
7516276163it("removes stale denylist entries before enabling installed plugins", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。