From c79399dc68648a4846f4867d19bb7ec7518de369 Mon Sep 17 00:00:00 2001 From: Shakker Date: Sat, 25 Apr 2026 23:16:57 +0100 Subject: [PATCH] fix: preserve plugin index records in update flows --- src/auto-reply/reply/commands-plugins.test.ts | 2 +- src/cli/update-cli.test.ts | 29 ++++++++++--------- src/commands/onboarding-plugin-install.ts | 1 + 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/auto-reply/reply/commands-plugins.test.ts b/src/auto-reply/reply/commands-plugins.test.ts index 8c6ff96a82b..d32586bae61 100644 --- a/src/auto-reply/reply/commands-plugins.test.ts +++ b/src/auto-reply/reply/commands-plugins.test.ts @@ -57,7 +57,7 @@ vi.mock("../../plugins/install.js", () => ({ vi.mock("../../plugins/installed-plugin-index-records.js", () => ({ loadInstalledPluginIndexInstallRecords: vi.fn( - async ({ config }) => config?.plugins?.installs ?? {}, + async (params = {}) => params.config?.plugins?.installs ?? {}, ), })); diff --git a/src/cli/update-cli.test.ts b/src/cli/update-cli.test.ts index 7dd4dc2aa3d..eb9361b7428 100644 --- a/src/cli/update-cli.test.ts +++ b/src/cli/update-cli.test.ts @@ -31,6 +31,9 @@ const formatPortDiagnostics = vi.fn(); const pathExists = vi.fn(); const syncPluginsForUpdateChannel = vi.fn(); const updateNpmInstalledPlugins = vi.fn(); +const loadInstalledPluginIndexInstallRecords = vi.fn( + async (params: { config?: OpenClawConfig } = {}) => params.config?.plugins?.installs ?? {}, +); const nodeVersionSatisfiesEngine = vi.fn(); const spawn = vi.fn(); const { defaultRuntime: runtimeCapture, resetRuntimeCapture } = createCliRuntimeCapture(); @@ -153,9 +156,7 @@ vi.mock("../plugins/installed-plugin-index-records.js", async (importOriginal) = await importOriginal(); return { ...actual, - loadInstalledPluginIndexInstallRecords: vi.fn( - async ({ config }) => config?.plugins?.installs ?? {}, - ), + loadInstalledPluginIndexInstallRecords, writePersistedInstalledPluginIndexInstallRecords: vi.fn(async () => undefined), }; }); @@ -1387,20 +1388,20 @@ describe("update-cli", () => { expect(lastWrite?.nextConfig?.update?.channel).toBe("beta"); }); - it("uses source config, not runtime-materialized config, for post-update plugin sync", async () => { + it("uses source config and plugin index records for post-update plugin sync", async () => { const tempDir = createCaseDir("openclaw-update"); mockPackageInstallStatus(tempDir); - const sourceConfig = { - plugins: { - installs: { - "lossless-claw": { - source: "npm", - spec: "@martian-engineering/lossless-claw", - installPath: "/tmp/lossless-claw", - }, - }, + const pluginInstallRecords = { + "lossless-claw": { + source: "npm", + spec: "@martian-engineering/lossless-claw", + installPath: "/tmp/lossless-claw", }, + } as const; + const sourceConfig = { + plugins: {}, } as OpenClawConfig; + loadInstalledPluginIndexInstallRecords.mockResolvedValueOnce(pluginInstallRecords); vi.mocked(readConfigFileSnapshot).mockResolvedValue({ ...baseSnapshot, sourceConfig, @@ -1440,7 +1441,7 @@ describe("update-cli", () => { const syncConfig = vi.mocked(syncPluginsForUpdateChannel).mock.calls[0]?.[0]?.config as | OpenClawConfig | undefined; - expect(syncConfig?.plugins?.installs).toEqual(sourceConfig.plugins?.installs); + expect(syncConfig?.plugins?.installs).toEqual(pluginInstallRecords); expect(syncConfig?.update?.channel).toBe("beta"); expect(syncConfig?.gateway?.auth).toBeUndefined(); expect(syncConfig?.plugins?.entries).toBeUndefined(); diff --git a/src/commands/onboarding-plugin-install.ts b/src/commands/onboarding-plugin-install.ts index 380759f9ec2..699b231848b 100644 --- a/src/commands/onboarding-plugin-install.ts +++ b/src/commands/onboarding-plugin-install.ts @@ -149,6 +149,7 @@ async function persistOnboardingPluginInstallRecord(params: { const records = await loadInstalledPluginIndexInstallRecords(); await writePersistedInstalledPluginIndexInstallRecords( recordPluginInstallInRecords(records, params.install), + { config: params.cfg }, ); }