diff --git a/src/cli/plugins-cli.ts b/src/cli/plugins-cli.ts index 6ba9ec8293a..7eb584fde3d 100644 --- a/src/cli/plugins-cli.ts +++ b/src/cli/plugins-cli.ts @@ -36,6 +36,7 @@ import { import { setPluginEnabledInConfig } from "./plugins-config.js"; import { runPluginInstallCommand } from "./plugins-install-command.js"; import { formatPluginLine } from "./plugins-list-format.js"; +import { refreshPluginRegistryAfterConfigMutation } from "./plugins-registry-refresh.js"; import { resolvePluginUninstallId } from "./plugins-uninstall-selection.js"; import { runPluginUpdateCommand } from "./plugins-update-command.js"; import { promptYesNo } from "./prompt.js"; @@ -498,6 +499,13 @@ export function registerPluginsCli(program: Command) { nextConfig: next, ...(snapshot.hash !== undefined ? { baseHash: snapshot.hash } : {}), }); + await refreshPluginRegistryAfterConfigMutation({ + config: next, + reason: "policy-changed", + logger: { + warn: (message) => defaultRuntime.log(theme.warn(message)), + }, + }); logSlotWarnings(slotResult.warnings); if (enableResult.enabled) { defaultRuntime.log(`Enabled plugin "${id}". Restart the gateway to apply.`); @@ -522,6 +530,13 @@ export function registerPluginsCli(program: Command) { nextConfig: next, ...(snapshot.hash !== undefined ? { baseHash: snapshot.hash } : {}), }); + await refreshPluginRegistryAfterConfigMutation({ + config: next, + reason: "policy-changed", + logger: { + warn: (message) => defaultRuntime.log(theme.warn(message)), + }, + }); defaultRuntime.log(`Disabled plugin "${id}". Restart the gateway to apply.`); }); @@ -645,6 +660,13 @@ export function registerPluginsCli(program: Command) { nextConfig: result.config, ...(snapshot.hash !== undefined ? { baseHash: snapshot.hash } : {}), }); + await refreshPluginRegistryAfterConfigMutation({ + config: result.config, + reason: "source-changed", + logger: { + warn: (message) => defaultRuntime.log(theme.warn(message)), + }, + }); const removed: string[] = []; if (result.actions.entry) { diff --git a/src/cli/plugins-install-persist.ts b/src/cli/plugins-install-persist.ts index 8cf60d65448..0dca0408f1d 100644 --- a/src/cli/plugins-install-persist.ts +++ b/src/cli/plugins-install-persist.ts @@ -11,6 +11,7 @@ import { logHookPackRestartHint, logSlotWarnings, } from "./plugins-command-helpers.js"; +import { refreshPluginRegistryAfterConfigMutation } from "./plugins-registry-refresh.js"; function addInstalledPluginToAllowlist(cfg: OpenClawConfig, pluginId: string): OpenClawConfig { const allow = cfg.plugins?.allow; @@ -48,6 +49,13 @@ export async function persistPluginInstall(params: { nextConfig: next, ...(params.baseHash !== undefined ? { baseHash: params.baseHash } : {}), }); + await refreshPluginRegistryAfterConfigMutation({ + config: next, + reason: "source-changed", + logger: { + warn: (message) => defaultRuntime.log(theme.warn(message)), + }, + }); logSlotWarnings(slotResult.warnings); if (params.warningMessage) { defaultRuntime.log(theme.warn(params.warningMessage)); diff --git a/src/cli/plugins-registry-refresh.ts b/src/cli/plugins-registry-refresh.ts new file mode 100644 index 00000000000..67ebc37ad62 --- /dev/null +++ b/src/cli/plugins-registry-refresh.ts @@ -0,0 +1,27 @@ +import type { OpenClawConfig } from "../config/types.openclaw.js"; +import { formatErrorMessage } from "../infra/errors.js"; +import type { InstalledPluginIndexRefreshReason } from "../plugins/installed-plugin-index.js"; +import { refreshPluginRegistry } from "../plugins/plugin-registry.js"; + +export type PluginRegistryRefreshLogger = { + warn?: (message: string) => void; +}; + +export async function refreshPluginRegistryAfterConfigMutation(params: { + config: OpenClawConfig; + reason: InstalledPluginIndexRefreshReason; + workspaceDir?: string; + env?: NodeJS.ProcessEnv; + logger?: PluginRegistryRefreshLogger; +}): Promise { + try { + await refreshPluginRegistry({ + config: params.config, + reason: params.reason, + ...(params.workspaceDir ? { workspaceDir: params.workspaceDir } : {}), + ...(params.env ? { env: params.env } : {}), + }); + } catch (error) { + params.logger?.warn?.(`Plugin registry refresh failed: ${formatErrorMessage(error)}`); + } +} diff --git a/src/cli/plugins-update-command.ts b/src/cli/plugins-update-command.ts index 6819ca610d1..aacdaf43f6a 100644 --- a/src/cli/plugins-update-command.ts +++ b/src/cli/plugins-update-command.ts @@ -3,6 +3,7 @@ import { updateNpmInstalledHookPacks } from "../hooks/update.js"; import { updateNpmInstalledPlugins } from "../plugins/update.js"; import { defaultRuntime } from "../runtime.js"; import { theme } from "../terminal/theme.js"; +import { refreshPluginRegistryAfterConfigMutation } from "./plugins-registry-refresh.js"; import { resolveHookPackUpdateSelection, resolvePluginUpdateSelection, @@ -112,6 +113,13 @@ export async function runPluginUpdateCommand(params: { nextConfig: hookResult.config, baseHash: (await sourceSnapshotPromise)?.hash, }); + if (pluginResult.changed) { + await refreshPluginRegistryAfterConfigMutation({ + config: hookResult.config, + reason: "source-changed", + logger, + }); + } defaultRuntime.log("Restart the gateway to load plugins and hooks."); } } diff --git a/src/cli/update-cli/update-command.ts b/src/cli/update-cli/update-command.ts index 44c635fd61b..bfd3e2be1a9 100644 --- a/src/cli/update-cli/update-command.ts +++ b/src/cli/update-cli/update-command.ts @@ -57,6 +57,7 @@ import { terminateStaleGatewayPids, waitForGatewayHealthyRestart, } from "../daemon-cli/restart-health.js"; +import { refreshPluginRegistryAfterConfigMutation } from "../plugins-registry-refresh.js"; import { createUpdateProgress, printResult } from "./progress.js"; import { prepareRestartScript, runRestartScript } from "./restart-helper.js"; import { @@ -619,6 +620,12 @@ async function updatePluginsAfterCoreUpdate(params: { nextConfig: pluginConfig, baseHash: params.configSnapshot.hash, }); + await refreshPluginRegistryAfterConfigMutation({ + config: pluginConfig, + reason: "source-changed", + workspaceDir: params.root, + logger: pluginLogger, + }); } if (params.opts.json) {