























@@ -3,6 +3,7 @@ import path from "node:path";
33import { afterEach, describe, expect, it } from "vitest";
44import type { PluginCandidate } from "./discovery.js";
55import {
6+inspectPersistedInstalledPluginIndex,
67readPersistedInstalledPluginIndex,
78refreshPersistedInstalledPluginIndex,
89resolveInstalledPluginIndexStorePath,
@@ -111,6 +112,76 @@ describe("installed plugin index persistence", () => {
111112await expect(readPersistedInstalledPluginIndex({ stateDir })).resolves.toBeNull();
112113});
113114115+it("inspects missing, fresh, and stale persisted index state without loading runtime", async () => {
116+const stateDir = makeTempDir();
117+const pluginDir = path.join(stateDir, "plugins", "demo");
118+fs.mkdirSync(pluginDir, { recursive: true });
119+const candidate = createCandidate(pluginDir);
120+const env = {
121+OPENCLAW_BUNDLED_PLUGINS_DIR: undefined,
122+OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE: "1",
123+OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE: "1",
124+OPENCLAW_VERSION: "2026.4.25",
125+VITEST: "true",
126+};
127+128+await expect(
129+inspectPersistedInstalledPluginIndex({ stateDir, candidates: [candidate], env }),
130+).resolves.toMatchObject({
131+state: "missing",
132+refreshReasons: ["missing"],
133+persisted: null,
134+current: {
135+plugins: [expect.objectContaining({ pluginId: "demo" })],
136+},
137+});
138+139+const current = await refreshPersistedInstalledPluginIndex({
140+reason: "manual",
141+ stateDir,
142+candidates: [candidate],
143+ env,
144+});
145+146+await expect(
147+inspectPersistedInstalledPluginIndex({ stateDir, candidates: [candidate], env }),
148+).resolves.toMatchObject({
149+state: "fresh",
150+refreshReasons: [],
151+persisted: current,
152+current: {
153+plugins: [expect.objectContaining({ pluginId: "demo" })],
154+},
155+});
156+157+fs.writeFileSync(
158+path.join(pluginDir, "openclaw.plugin.json"),
159+JSON.stringify({
160+id: "demo",
161+name: "Demo",
162+configSchema: { type: "object" },
163+providers: ["demo", "demo-next"],
164+}),
165+"utf8",
166+);
167+168+await expect(
169+inspectPersistedInstalledPluginIndex({ stateDir, candidates: [candidate], env }),
170+).resolves.toMatchObject({
171+state: "stale",
172+refreshReasons: ["stale-manifest"],
173+persisted: current,
174+current: {
175+plugins: [
176+expect.objectContaining({
177+pluginId: "demo",
178+contributions: expect.objectContaining({ providers: ["demo", "demo-next"] }),
179+}),
180+],
181+},
182+});
183+});
184+114185it("refreshes and persists a rebuilt index without loading plugin runtime", async () => {
115186const stateDir = makeTempDir();
116187const pluginDir = path.join(stateDir, "plugins", "demo");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。