diff --git a/src/commands/doctor/shared/channel-plugin-blockers.test.ts b/src/commands/doctor/shared/channel-plugin-blockers.test.ts new file mode 100644 index 00000000000..406d4a04f77 --- /dev/null +++ b/src/commands/doctor/shared/channel-plugin-blockers.test.ts @@ -0,0 +1,69 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import * as configPresence from "../../../channels/config-presence.js"; +import * as manifestRegistry from "../../../plugins/manifest-registry.js"; +import { scanConfiguredChannelPluginBlockers } from "./channel-plugin-blockers.js"; + +describe("channel plugin blockers", () => { + beforeEach(() => { + vi.restoreAllMocks(); + }); + + it("skips plugin registry work when config has no plugin blocker surfaces", () => { + const presenceSpy = vi.spyOn(configPresence, "listPotentialConfiguredChannelIds"); + const registrySpy = vi.spyOn(manifestRegistry, "loadPluginManifestRegistry"); + + const hits = scanConfiguredChannelPluginBlockers({ + channels: { + slack: { + accounts: { + work: { + allowFrom: ["alice"], + }, + }, + }, + }, + }); + + expect(hits).toEqual([]); + expect(presenceSpy).not.toHaveBeenCalled(); + expect(registrySpy).not.toHaveBeenCalled(); + }); + + it("still evaluates configured channels when plugins are disabled globally", () => { + vi.spyOn(configPresence, "listPotentialConfiguredChannelIds").mockReturnValue(["slack"]); + vi.spyOn(manifestRegistry, "loadPluginManifestRegistry").mockReturnValue({ + plugins: [ + { + id: "slack", + origin: "bundled", + channels: ["slack"], + enabledByDefault: true, + }, + ], + diagnostics: [], + } as ReturnType); + + const hits = scanConfiguredChannelPluginBlockers({ + plugins: { + enabled: false, + }, + channels: { + slack: { + accounts: { + work: { + allowFrom: ["alice"], + }, + }, + }, + }, + }); + + expect(hits).toEqual([ + { + channelId: "slack", + pluginId: "slack", + reason: "plugins disabled", + }, + ]); + }); +}); diff --git a/src/commands/doctor/shared/channel-plugin-blockers.ts b/src/commands/doctor/shared/channel-plugin-blockers.ts index a7d3e42f21e..56815e48d82 100644 --- a/src/commands/doctor/shared/channel-plugin-blockers.ts +++ b/src/commands/doctor/shared/channel-plugin-blockers.ts @@ -13,10 +13,32 @@ export type ChannelPluginBlockerHit = { reason: "disabled in config" | "plugins disabled"; }; +function hasExplicitChannelPluginBlockerConfig(cfg: OpenClawConfig): boolean { + if (cfg.plugins?.enabled === false) { + return true; + } + const entries = cfg.plugins?.entries; + if (!entries || typeof entries !== "object") { + return false; + } + return Object.values(entries).some((entry) => { + return ( + entry && + typeof entry === "object" && + !Array.isArray(entry) && + "enabled" in entry && + (entry as { enabled?: unknown }).enabled === false + ); + }); +} + export function scanConfiguredChannelPluginBlockers( cfg: OpenClawConfig, env: NodeJS.ProcessEnv = process.env, ): ChannelPluginBlockerHit[] { + if (!hasExplicitChannelPluginBlockerConfig(cfg)) { + return []; + } const configuredChannelIds = new Set( listPotentialConfiguredChannelIds(cfg, env).map((id) => id.trim()), );