From 36219b0ffc16e8404ae3f59afa6f1b0e09a7ef71 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 25 Apr 2026 01:20:16 -0700 Subject: [PATCH] fix(plugins): invalidate index on policy changes --- .../installed-plugin-index-store.test.ts | 24 +++++++++++++ src/plugins/installed-plugin-index.test.ts | 34 +++++++++++++++++++ src/plugins/installed-plugin-index.ts | 4 +++ 3 files changed, 62 insertions(+) diff --git a/src/plugins/installed-plugin-index-store.test.ts b/src/plugins/installed-plugin-index-store.test.ts index 56b946265f8..e55c7cc044c 100644 --- a/src/plugins/installed-plugin-index-store.test.ts +++ b/src/plugins/installed-plugin-index-store.test.ts @@ -154,6 +154,30 @@ describe("installed plugin index persistence", () => { }, }); + await expect( + inspectPersistedInstalledPluginIndex({ + stateDir, + candidates: [candidate], + config: { + plugins: { + entries: { + demo: { + enabled: false, + }, + }, + }, + }, + env, + }), + ).resolves.toMatchObject({ + state: "stale", + refreshReasons: ["policy-changed"], + persisted: current, + current: { + plugins: [expect.objectContaining({ pluginId: "demo", enabled: false })], + }, + }); + fs.writeFileSync( path.join(pluginDir, "openclaw.plugin.json"), JSON.stringify({ diff --git a/src/plugins/installed-plugin-index.test.ts b/src/plugins/installed-plugin-index.test.ts index b0fce746da3..69c65fa3dbd 100644 --- a/src/plugins/installed-plugin-index.test.ts +++ b/src/plugins/installed-plugin-index.test.ts @@ -466,6 +466,40 @@ describe("installed plugin index", () => { ]); }); + it("treats enablement changes as policy invalidation", () => { + const fixture = createRichPluginFixture(); + const previous = loadInstalledPluginIndex({ + candidates: [fixture.candidate], + config: { + plugins: { + entries: { + demo: { + enabled: true, + }, + }, + }, + }, + env: hermeticEnv(), + }); + const current = loadInstalledPluginIndex({ + candidates: [fixture.candidate], + config: { + plugins: { + entries: { + demo: { + enabled: false, + }, + }, + }, + }, + env: hermeticEnv(), + }); + + expect(diffInstalledPluginIndexInvalidationReasons(previous, current)).toEqual([ + "policy-changed", + ]); + }); + it("marks disabled plugins without dropping their cold contributions", () => { const fixture = createRichPluginFixture(); diff --git a/src/plugins/installed-plugin-index.ts b/src/plugins/installed-plugin-index.ts index 11179978b83..6047e80e549 100644 --- a/src/plugins/installed-plugin-index.ts +++ b/src/plugins/installed-plugin-index.ts @@ -29,6 +29,7 @@ export type InstalledPluginIndexRefreshReason = | "stale-manifest" | "stale-package" | "source-changed" + | "policy-changed" | "host-contract-changed" | "compat-registry-changed" | "manual"; @@ -613,6 +614,9 @@ export function diffInstalledPluginIndexInvalidationReasons( ) { reasons.add("source-changed"); } + if (previousPlugin.enabled !== currentPlugin.enabled) { + reasons.add("policy-changed"); + } if (previousPlugin.manifestHash !== currentPlugin.manifestHash) { reasons.add("stale-manifest"); }