fix(plugins): refresh registry after chat toggles

This commit is contained in:
Vincent Koc
2026-04-25 05:50:00 -07:00
parent 29988335fc
commit f14aa65bcc
3 changed files with 44 additions and 1 deletions

View File

@@ -19,6 +19,7 @@ Docs: https://docs.openclaw.ai
- Plugins/CLI: make `openclaw plugins list` read the cold persisted registry snapshot by default, leaving module-aware diagnostics to `plugins doctor` and `plugins inspect`. Thanks @vincentkoc.
- Plugins/startup: move gateway startup plugin planning onto the versioned cold registry index, with postinstall repair for older registry files that predate startup metadata. Thanks @vincentkoc.
- Providers/plugins: resolve provider ownership, provider discovery scopes, and catalog-hook provider ids from the cold plugin registry instead of rescanning manifests on those paths. Thanks @vincentkoc.
- Plugins/chat commands: refresh the persisted plugin registry after `/plugins enable` and `/plugins disable`, matching the CLI mutation path. Thanks @vincentkoc.
- Diagnostics/OTEL: add bounded outbound message delivery lifecycle diagnostics and export them as low-cardinality delivery spans/metrics without message body, recipient, room, or media-path data. (#71471) Thanks @vincentkoc and @jlapenna.
- Diagnostics/OTEL: emit bounded exec-process diagnostics and export them as `openclaw.exec` spans without exposing command text, working directories, or container identifiers. (#71451) Thanks @vincentkoc and @jlapenna.
- Diagnostics/OTEL: support `OPENCLAW_OTEL_PRELOADED=1` so the plugin can reuse an already-registered OpenTelemetry SDK while keeping OpenClaw diagnostic listeners wired. (#71450) Thanks @vincentkoc and @jlapenna.

View File

@@ -11,6 +11,7 @@ const buildPluginDiagnosticsReportMock = vi.hoisted(() => vi.fn());
const buildPluginInspectReportMock = vi.hoisted(() => vi.fn());
const buildAllPluginInspectReportsMock = vi.hoisted(() => vi.fn());
const formatPluginCompatibilityNoticeMock = vi.hoisted(() => vi.fn(() => "ok"));
const refreshPluginRegistryAfterConfigMutationMock = vi.hoisted(() => vi.fn(async () => undefined));
vi.mock("../../cli/npm-resolution.js", () => ({
buildNpmInstallRecordFields: vi.fn(),
@@ -27,6 +28,10 @@ vi.mock("../../cli/plugins-install-persist.js", () => ({
persistPluginInstall: vi.fn(async () => undefined),
}));
vi.mock("../../cli/plugins-registry-refresh.js", () => ({
refreshPluginRegistryAfterConfigMutation: refreshPluginRegistryAfterConfigMutationMock,
}));
vi.mock("../../config/config.js", () => ({
readConfigFileSnapshot: readConfigFileSnapshotMock,
validateConfigObjectWithPlugins: validateConfigObjectWithPluginsMock,
@@ -208,6 +213,18 @@ describe("handlePluginsCommand", () => {
}),
}),
);
expect(refreshPluginRegistryAfterConfigMutationMock).toHaveBeenLastCalledWith(
expect.objectContaining({
reason: "policy-changed",
config: expect.objectContaining({
plugins: expect.objectContaining({
entries: expect.objectContaining({
superpowers: expect.objectContaining({ enabled: true }),
}),
}),
}),
}),
);
const disableParams = buildPluginsParams("/plugins disable superpowers", buildCfg());
disableParams.command.senderIsOwner = true;
@@ -223,6 +240,18 @@ describe("handlePluginsCommand", () => {
}),
}),
);
expect(refreshPluginRegistryAfterConfigMutationMock).toHaveBeenLastCalledWith(
expect.objectContaining({
reason: "policy-changed",
config: expect.objectContaining({
plugins: expect.objectContaining({
entries: expect.objectContaining({
superpowers: expect.objectContaining({ enabled: false }),
}),
}),
}),
}),
);
});
it("resolves write targets by runtime-derived plugin name", async () => {

View File

@@ -7,6 +7,7 @@ import {
resolveFileNpmSpecToLocalPath,
} from "../../cli/plugins-command-helpers.js";
import { persistPluginInstall } from "../../cli/plugins-install-persist.js";
import { refreshPluginRegistryAfterConfigMutation } from "../../cli/plugins-registry-refresh.js";
import {
readConfigFileSnapshot,
validateConfigObjectWithPlugins,
@@ -473,11 +474,23 @@ export const handlePluginsCommand: CommandHandler = async (params, allowTextComm
};
}
await writeConfigFile(validated.config);
let registryWarning: string | undefined;
await refreshPluginRegistryAfterConfigMutation({
config: validated.config,
reason: "policy-changed",
logger: {
warn: (message) => {
registryWarning = message;
},
},
});
return {
shouldContinue: false,
reply: {
text: `🔌 Plugin "${plugin.id}" ${pluginsCommand.action}d in ${loaded.path}. Restart the gateway to apply.`,
text:
`🔌 Plugin "${plugin.id}" ${pluginsCommand.action}d in ${loaded.path}. Restart the gateway to apply.` +
(registryWarning ? `\n${registryWarning}` : ""),
},
};
};