fix(onboarding): refresh plugin registry after plugin installs

This commit is contained in:
Vincent Koc
2026-04-25 16:25:24 -07:00
parent 435be06cde
commit d228463120
3 changed files with 50 additions and 0 deletions

View File

@@ -46,6 +46,7 @@ export async function ensureChannelSetupPluginInstalled(params: {
cfg: params.cfg,
entry: toOnboardingPluginInstallEntry(params.entry),
prompter: params.prompter,
refreshRegistry: false,
runtime: params.runtime,
workspaceDir: params.workspaceDir,
});

View File

@@ -10,6 +10,11 @@ vi.mock("../cli/plugin-install-plan.js", () => ({
resolveBundledInstallPlanForCatalogEntry,
}));
const refreshPluginRegistryAfterConfigMutation = vi.hoisted(() => vi.fn(async () => undefined));
vi.mock("../cli/plugins-registry-refresh.js", () => ({
refreshPluginRegistryAfterConfigMutation,
}));
const resolveBundledPluginSources = vi.hoisted(() => vi.fn(() => new Map()));
const findBundledPluginSourceInMap = vi.hoisted(() => vi.fn(() => null));
vi.mock("../plugins/bundled-sources.js", () => ({
@@ -61,6 +66,7 @@ describe("ensureOnboardingPluginInstalled", () => {
beforeEach(() => {
vi.clearAllMocks();
withTimeout.mockImplementation(async <T>(promise: Promise<T>) => await promise);
refreshPluginRegistryAfterConfigMutation.mockResolvedValue(undefined);
});
it("passes npm specs and optional expected integrity to npm installs with progress", async () => {
@@ -135,6 +141,12 @@ describe("ensureOnboardingPluginInstalled", () => {
expect(result.installed).toBe(true);
expect(result.status).toBe("installed");
expect(result.cfg.plugins?.installs).toBeUndefined();
expect(refreshPluginRegistryAfterConfigMutation).toHaveBeenCalledWith(
expect.objectContaining({
config: result.cfg,
reason: "source-changed",
}),
);
});
it("returns a timed out status and notes the retry path when npm install hangs", async () => {

View File

@@ -1,6 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import { resolveBundledInstallPlanForCatalogEntry } from "../cli/plugin-install-plan.js";
import { refreshPluginRegistryAfterConfigMutation } from "../cli/plugins-registry-refresh.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { parseRegistryNpmSpec } from "../infra/npm-registry-spec.js";
import {
@@ -149,6 +150,23 @@ async function persistOnboardingPluginInstallRecord(params: {
await writePersistedPluginInstallLedger(recordPluginInstallInRecords(records, params.install));
}
async function refreshRegistryAfterOnboardingPluginInstall(params: {
cfg: OpenClawConfig;
refreshRegistry?: boolean;
runtime: RuntimeEnv;
workspaceDir?: string;
}) {
if (params.refreshRegistry === false) {
return;
}
await refreshPluginRegistryAfterConfigMutation({
config: params.cfg,
reason: "source-changed",
...(params.workspaceDir ? { workspaceDir: params.workspaceDir } : {}),
logger: { warn: (message) => params.runtime.log(message) },
});
}
async function recordLocalPluginInstall(params: {
cfg: OpenClawConfig;
entry: OnboardingPluginInstallEntry;
@@ -438,6 +456,7 @@ export async function ensureOnboardingPluginInstalled(params: {
cfg: OpenClawConfig;
entry: OnboardingPluginInstallEntry;
prompter: WizardPrompter;
refreshRegistry?: boolean;
runtime: RuntimeEnv;
workspaceDir?: string;
}): Promise<OnboardingPluginInstallResult> {
@@ -494,6 +513,12 @@ export async function ensureOnboardingPluginInstalled(params: {
}
next = addPluginLoadPath(enableResult.config, localPath);
next = await recordLocalPluginInstall({ cfg: next, entry, localPath, npmSpec, workspaceDir });
await refreshRegistryAfterOnboardingPluginInstall({
cfg: next,
refreshRegistry: params.refreshRegistry,
runtime,
workspaceDir,
});
return {
cfg: next,
installed: true,
@@ -576,6 +601,12 @@ export async function ensureOnboardingPluginInstalled(params: {
install,
});
next = withoutPluginInstallRecords(recordPluginInstall(next, install));
await refreshRegistryAfterOnboardingPluginInstall({
cfg: next,
refreshRegistry: params.refreshRegistry,
runtime,
workspaceDir,
});
return {
cfg: next,
installed: true,
@@ -615,6 +646,12 @@ export async function ensureOnboardingPluginInstalled(params: {
}
next = addPluginLoadPath(enableResult.config, localPath);
next = await recordLocalPluginInstall({ cfg: next, entry, localPath, npmSpec, workspaceDir });
await refreshRegistryAfterOnboardingPluginInstall({
cfg: next,
refreshRegistry: params.refreshRegistry,
runtime,
workspaceDir,
});
return {
cfg: next,
installed: true,