Skip to content

Commit c19f8a5

Browse files
committed
refactor: consolidate plugin install index store
1 parent f8123e4 commit c19f8a5

35 files changed

Lines changed: 522 additions & 489 deletions

src/auto-reply/reply/commands-plugins.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,10 @@ vi.mock("../../plugins/install.js", () => ({
5555
installPluginFromPath: vi.fn(),
5656
}));
5757

58-
vi.mock("../../plugins/install-ledger-store.js", () => ({
59-
loadPluginInstallRecords: vi.fn(async ({ config }) => config?.plugins?.installs ?? {}),
58+
vi.mock("../../plugins/installed-plugin-index-records.js", () => ({
59+
loadInstalledPluginIndexInstallRecords: vi.fn(
60+
async ({ config }) => config?.plugins?.installs ?? {},
61+
),
6062
}));
6163

6264
vi.mock("../../plugins/manifest-registry.js", () => ({

src/auto-reply/reply/commands-plugins.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import type { PluginInstallRecord } from "../../config/types.plugins.js";
1818
import { resolveArchiveKind } from "../../infra/archive.js";
1919
import { parseClawHubPluginSpec } from "../../infra/clawhub.js";
2020
import { installPluginFromClawHub } from "../../plugins/clawhub.js";
21-
import { loadPluginInstallRecords } from "../../plugins/install-ledger-store.js";
2221
import { installPluginFromNpmSpec, installPluginFromPath } from "../../plugins/install.js";
22+
import { loadInstalledPluginIndexInstallRecords } from "../../plugins/installed-plugin-index-records.js";
2323
import { clearPluginManifestRegistryCache } from "../../plugins/manifest-registry.js";
2424
import type { PluginRecord } from "../../plugins/registry.js";
2525
import {
@@ -416,7 +416,7 @@ export const handlePluginsCommand: CommandHandler = async (params, allowTextComm
416416
}
417417

418418
if (pluginsCommand.action === "inspect") {
419-
const installRecords = await loadPluginInstallRecords({ config: loaded.config });
419+
const installRecords = await loadInstalledPluginIndexInstallRecords();
420420
if (!pluginsCommand.name) {
421421
return {
422422
shouldContinue: false,

src/cli/plugins-cli-test-helpers.ts

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,15 @@ export const listMarketplacePlugins: Mock<ListMarketplacePluginsFn> = vi.fn();
3333
export const resolveMarketplaceInstallShortcut: Mock<ResolveMarketplaceInstallShortcutFn> = vi.fn();
3434
export const enablePluginInConfig: UnknownMock = vi.fn();
3535
export const recordPluginInstall: UnknownMock = vi.fn();
36-
export const loadPluginInstallRecords: AsyncUnknownMock = vi.fn(async (...args: unknown[]) => {
37-
const params = args[0] as LoadPluginInstallRecordsParams | undefined;
38-
return structuredClone(params?.config?.plugins?.installs ?? {});
39-
});
40-
export const writePersistedPluginInstallLedger: AsyncUnknownMock = vi.fn(async () => undefined);
36+
export const loadInstalledPluginIndexInstallRecords: AsyncUnknownMock = vi.fn(
37+
async (...args: unknown[]) => {
38+
const params = args[0] as LoadPluginInstallRecordsParams | undefined;
39+
return structuredClone(params?.config?.plugins?.installs ?? {});
40+
},
41+
);
42+
export const writePersistedInstalledPluginIndexInstallRecords: AsyncUnknownMock = vi.fn(
43+
async () => undefined,
44+
);
4145
export const clearPluginManifestRegistryCache: UnknownMock = vi.fn();
4246
export const loadPluginManifestRegistry: UnknownMock = vi.fn();
4347
export const buildPluginSnapshotReport: UnknownMock = vi.fn();
@@ -157,18 +161,20 @@ vi.mock("../plugins/installs.js", () => ({
157161
)) as (typeof import("../plugins/installs.js"))["recordPluginInstall"],
158162
}));
159163

160-
vi.mock("../plugins/install-ledger-store.js", async (importOriginal) => {
161-
const actual = await importOriginal<typeof import("../plugins/install-ledger-store.js")>();
164+
vi.mock("../plugins/installed-plugin-index-records.js", async (importOriginal) => {
165+
const actual =
166+
await importOriginal<typeof import("../plugins/installed-plugin-index-records.js")>();
162167
return {
163168
...actual,
164-
loadPluginInstallRecords: ((...args: unknown[]) =>
165-
invokeMock<unknown[], unknown>(loadPluginInstallRecords, ...args)) as (
166-
...args: unknown[]
167-
) => unknown,
168-
writePersistedPluginInstallLedger: ((...args: unknown[]) =>
169-
invokeMock<unknown[], unknown>(writePersistedPluginInstallLedger, ...args)) as (
169+
loadInstalledPluginIndexInstallRecords: ((...args: unknown[]) =>
170+
invokeMock<unknown[], unknown>(loadInstalledPluginIndexInstallRecords, ...args)) as (
170171
...args: unknown[]
171172
) => unknown,
173+
writePersistedInstalledPluginIndexInstallRecords: ((...args: unknown[]) =>
174+
invokeMock<unknown[], unknown>(
175+
writePersistedInstalledPluginIndexInstallRecords,
176+
...args,
177+
)) as (...args: unknown[]) => unknown,
172178
recordPluginInstallInRecords: (
173179
records: Record<string, unknown>,
174180
update: { pluginId: string; installedAt?: string } & Record<string, unknown>,
@@ -459,8 +465,8 @@ export function resetPluginsCliTestState() {
459465
resolveMarketplaceInstallShortcut.mockReset();
460466
enablePluginInConfig.mockReset();
461467
recordPluginInstall.mockReset();
462-
loadPluginInstallRecords.mockReset();
463-
writePersistedPluginInstallLedger.mockReset();
468+
loadInstalledPluginIndexInstallRecords.mockReset();
469+
writePersistedInstalledPluginIndexInstallRecords.mockReset();
464470
clearPluginManifestRegistryCache.mockReset();
465471
loadPluginManifestRegistry.mockReset();
466472
buildPluginSnapshotReport.mockReset();
@@ -519,11 +525,11 @@ export function resetPluginsCliTestState() {
519525
recordPluginInstall.mockImplementation(
520526
((cfg: OpenClawConfig) => cfg) as (...args: unknown[]) => unknown,
521527
);
522-
loadPluginInstallRecords.mockImplementation(async (...args: unknown[]) => {
528+
loadInstalledPluginIndexInstallRecords.mockImplementation(async (...args: unknown[]) => {
523529
const params = args[0] as LoadPluginInstallRecordsParams | undefined;
524530
return structuredClone(params?.config?.plugins?.installs ?? {});
525531
});
526-
writePersistedPluginInstallLedger.mockResolvedValue(undefined);
532+
writePersistedInstalledPluginIndexInstallRecords.mockResolvedValue(undefined);
527533
loadPluginManifestRegistry.mockReturnValue({
528534
plugins: [],
529535
diagnostics: [],
@@ -544,7 +550,7 @@ export function resetPluginsCliTestState() {
544550
version: 1,
545551
hostContractVersion: "2026.4.25",
546552
compatRegistryVersion: "compat-v1",
547-
migrationVersion: 2,
553+
migrationVersion: 1,
548554
policyHash: "policy-v1",
549555
generatedAtMs: 1777118400000,
550556
plugins: [],

src/cli/plugins-cli.install.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
runtimeErrors,
2626
runtimeLogs,
2727
writeConfigFile,
28-
writePersistedPluginInstallLedger,
28+
writePersistedInstalledPluginIndexInstallRecords,
2929
} from "./plugins-cli-test-helpers.js";
3030

3131
const CLI_STATE_ROOT = "/tmp/openclaw-state";
@@ -290,7 +290,7 @@ describe("plugins cli install", () => {
290290
expect(writeConfigFile).not.toHaveBeenCalled();
291291
});
292292

293-
it("installs marketplace plugins and persists install ledger", async () => {
293+
it("installs marketplace plugins and persists plugin index", async () => {
294294
const cfg = {
295295
plugins: {
296296
entries: {},
@@ -329,7 +329,7 @@ describe("plugins cli install", () => {
329329
await runPluginsCommand(["plugins", "install", "alpha", "--marketplace", "local/repo"]);
330330

331331
expect(clearPluginManifestRegistryCache).toHaveBeenCalledTimes(1);
332-
expect(writePersistedPluginInstallLedger).toHaveBeenCalledWith({
332+
expect(writePersistedInstalledPluginIndexInstallRecords).toHaveBeenCalledWith({
333333
alpha: expect.objectContaining({
334334
source: "marketplace",
335335
installPath: cliInstallPath("alpha"),
@@ -384,7 +384,7 @@ describe("plugins cli install", () => {
384384
spec: "clawhub:demo",
385385
}),
386386
);
387-
expect(writePersistedPluginInstallLedger).toHaveBeenCalledWith({
387+
expect(writePersistedInstalledPluginIndexInstallRecords).toHaveBeenCalledWith({
388388
demo: expect.objectContaining({
389389
source: "clawhub",
390390
spec: "clawhub:demo@1.2.3",
@@ -464,7 +464,7 @@ describe("plugins cli install", () => {
464464
}),
465465
);
466466
expect(installPluginFromNpmSpec).not.toHaveBeenCalled();
467-
expect(writePersistedPluginInstallLedger).toHaveBeenCalledWith({
467+
expect(writePersistedInstalledPluginIndexInstallRecords).toHaveBeenCalledWith({
468468
demo: expect.objectContaining({
469469
source: "clawhub",
470470
spec: "clawhub:demo@1.2.3",

src/cli/plugins-cli.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import type { OpenClawConfig } from "../config/types.openclaw.js";
77
import type { PluginInstallRecord } from "../config/types.plugins.js";
88
import { enablePluginInConfig } from "../plugins/enable.js";
99
import {
10-
loadPluginInstallRecords,
10+
loadInstalledPluginIndexInstallRecords,
1111
PLUGIN_INSTALLS_CONFIG_PATH,
1212
removePluginInstallRecordFromRecords,
1313
withoutPluginInstallRecords,
14-
writePersistedPluginInstallLedger,
14+
writePersistedInstalledPluginIndexInstallRecords,
1515
withPluginInstallRecords,
16-
} from "../plugins/install-ledger-store.js";
16+
} from "../plugins/installed-plugin-index-records.js";
1717
import { listMarketplacePlugins } from "../plugins/marketplace.js";
1818
import { inspectPluginRegistry, refreshPluginRegistry } from "../plugins/plugin-registry.js";
1919
import { defaultSlotIdForKey } from "../plugins/slots.js";
@@ -290,7 +290,7 @@ export function registerPluginsCli(program: Command) {
290290
.option("--json", "Print JSON")
291291
.action(async (id: string | undefined, opts: PluginInspectOptions) => {
292292
const cfg = loadConfig();
293-
const installRecords = await loadPluginInstallRecords({ config: cfg });
293+
const installRecords = await loadInstalledPluginIndexInstallRecords();
294294
const report = buildPluginDiagnosticsReport({
295295
config: cfg,
296296
...(opts.json ? { logger: quietPluginJsonLogger } : {}),
@@ -584,7 +584,7 @@ export function registerPluginsCli(program: Command) {
584584
.action(async (id: string, opts: PluginUninstallOptions) => {
585585
const snapshot = await readConfigFileSnapshot();
586586
const sourceConfig = (snapshot.sourceConfig ?? snapshot.config) as OpenClawConfig;
587-
const installRecords = await loadPluginInstallRecords({ config: sourceConfig });
587+
const installRecords = await loadInstalledPluginIndexInstallRecords();
588588
const cfg = withPluginInstallRecords(sourceConfig, installRecords);
589589
const report = buildPluginDiagnosticsReport({ config: cfg });
590590
const extensionsDir = path.join(resolveStateDir(process.env, os.homedir), "extensions");
@@ -691,7 +691,7 @@ export function registerPluginsCli(program: Command) {
691691
defaultRuntime.log(theme.warn(warning));
692692
}
693693

694-
await writePersistedPluginInstallLedger(
694+
await writePersistedInstalledPluginIndexInstallRecords(
695695
removePluginInstallRecordFromRecords(installRecords, pluginId),
696696
);
697697
await replaceConfigFile({

src/cli/plugins-cli.uninstall.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
runtimeLogs,
1313
uninstallPlugin,
1414
writeConfigFile,
15-
writePersistedPluginInstallLedger,
15+
writePersistedInstalledPluginIndexInstallRecords,
1616
} from "./plugins-cli-test-helpers.js";
1717

1818
const CLI_STATE_ROOT = "/tmp/openclaw-state";
@@ -103,7 +103,7 @@ describe("plugins cli uninstall", () => {
103103
deleteFiles: false,
104104
}),
105105
);
106-
expect(writePersistedPluginInstallLedger).toHaveBeenCalledWith({});
106+
expect(writePersistedInstalledPluginIndexInstallRecords).toHaveBeenCalledWith({});
107107
expect(writeConfigFile).toHaveBeenCalledWith({
108108
plugins: {
109109
entries: {},

src/cli/plugins-cli.update.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
updateNpmInstalledHookPacks,
1313
updateNpmInstalledPlugins,
1414
writeConfigFile,
15-
writePersistedPluginInstallLedger,
15+
writePersistedInstalledPluginIndexInstallRecords,
1616
} from "./plugins-cli-test-helpers.js";
1717

1818
function createTrackedPluginConfig(params: {
@@ -211,7 +211,9 @@ describe("plugins cli update", () => {
211211
dryRun: false,
212212
}),
213213
);
214-
expect(writePersistedPluginInstallLedger).toHaveBeenCalledWith(nextConfig.plugins?.installs);
214+
expect(writePersistedInstalledPluginIndexInstallRecords).toHaveBeenCalledWith(
215+
nextConfig.plugins?.installs,
216+
);
215217
expect(writeConfigFile).toHaveBeenCalledWith({});
216218
expect(refreshPluginRegistry).toHaveBeenCalledWith({
217219
config: {},

src/cli/plugins-install-persist.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
refreshPluginRegistry,
66
resetPluginsCliTestState,
77
writeConfigFile,
8-
writePersistedPluginInstallLedger,
8+
writePersistedInstalledPluginIndexInstallRecords,
99
} from "./plugins-cli-test-helpers.js";
1010

1111
describe("persistPluginInstall", () => {
@@ -46,7 +46,7 @@ describe("persistPluginInstall", () => {
4646
});
4747

4848
expect(next).toEqual(enabledConfig);
49-
expect(writePersistedPluginInstallLedger).toHaveBeenCalledWith({
49+
expect(writePersistedInstalledPluginIndexInstallRecords).toHaveBeenCalledWith({
5050
alpha: expect.objectContaining({
5151
source: "npm",
5252
spec: "alpha@1.0.0",

src/cli/plugins-install-persist.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import type { OpenClawConfig } from "../config/types.openclaw.js";
33
import { type HookInstallUpdate, recordHookInstall } from "../hooks/installs.js";
44
import { enablePluginInConfig } from "../plugins/enable.js";
55
import {
6-
loadPluginInstallRecords,
6+
loadInstalledPluginIndexInstallRecords,
77
PLUGIN_INSTALLS_CONFIG_PATH,
88
recordPluginInstallInRecords,
99
withoutPluginInstallRecords,
10-
writePersistedPluginInstallLedger,
11-
} from "../plugins/install-ledger-store.js";
10+
writePersistedInstalledPluginIndexInstallRecords,
11+
} from "../plugins/installed-plugin-index-records.js";
1212
import type { PluginInstallUpdate } from "../plugins/installs.js";
1313
import { defaultRuntime } from "../runtime.js";
1414
import { theme } from "../terminal/theme.js";
@@ -46,14 +46,14 @@ export async function persistPluginInstall(params: {
4646
addInstalledPluginToAllowlist(params.config, params.pluginId),
4747
params.pluginId,
4848
).config;
49-
const installRecords = await loadPluginInstallRecords({ config: params.config });
49+
const installRecords = await loadInstalledPluginIndexInstallRecords();
5050
const nextInstallRecords = recordPluginInstallInRecords(installRecords, {
5151
pluginId: params.pluginId,
5252
...params.install,
5353
});
5454
const slotResult = applySlotSelectionForPlugin(next, params.pluginId);
5555
next = withoutPluginInstallRecords(slotResult.config);
56-
await writePersistedPluginInstallLedger(nextInstallRecords);
56+
await writePersistedInstalledPluginIndexInstallRecords(nextInstallRecords);
5757
await replaceConfigFile({
5858
nextConfig: next,
5959
...(params.baseHash !== undefined ? { baseHash: params.baseHash } : {}),
@@ -62,6 +62,7 @@ export async function persistPluginInstall(params: {
6262
await refreshPluginRegistryAfterConfigMutation({
6363
config: next,
6464
reason: "source-changed",
65+
installRecords: nextInstallRecords,
6566
logger: {
6667
warn: (message) => defaultRuntime.log(theme.warn(message)),
6768
},

src/cli/plugins-registry-refresh.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { OpenClawConfig } from "../config/types.openclaw.js";
22
import { formatErrorMessage } from "../infra/errors.js";
3+
import { loadInstalledPluginIndexInstallRecords } from "../plugins/installed-plugin-index-records.js";
34
import type { InstalledPluginIndexRefreshReason } from "../plugins/installed-plugin-index.js";
45
import { refreshPluginRegistry } from "../plugins/plugin-registry.js";
56

@@ -12,12 +13,17 @@ export async function refreshPluginRegistryAfterConfigMutation(params: {
1213
reason: InstalledPluginIndexRefreshReason;
1314
workspaceDir?: string;
1415
env?: NodeJS.ProcessEnv;
16+
installRecords?: Awaited<ReturnType<typeof loadInstalledPluginIndexInstallRecords>>;
1517
logger?: PluginRegistryRefreshLogger;
1618
}): Promise<void> {
1719
try {
20+
const installRecords =
21+
params.installRecords ??
22+
(await loadInstalledPluginIndexInstallRecords(params.env ? { env: params.env } : {}));
1823
await refreshPluginRegistry({
1924
config: params.config,
2025
reason: params.reason,
26+
installRecords,
2127
...(params.workspaceDir ? { workspaceDir: params.workspaceDir } : {}),
2228
...(params.env ? { env: params.env } : {}),
2329
});

0 commit comments

Comments
 (0)