From b0c46cbd768d976096d9453d48c74609b8439a16 Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Fri, 17 Apr 2026 03:08:45 -0400 Subject: [PATCH] CLI: preserve disabled channels during lazy setup --- src/flows/channel-setup.test.ts | 71 +++++++++++++++++++++++++++++++++ src/flows/channel-setup.ts | 10 +++++ 2 files changed, 81 insertions(+) diff --git a/src/flows/channel-setup.test.ts b/src/flows/channel-setup.test.ts index b0b00393c9b..928d9eca210 100644 --- a/src/flows/channel-setup.test.ts +++ b/src/flows/channel-setup.test.ts @@ -314,4 +314,75 @@ describe("setupChannels workspace shadow exclusion", () => { }, }); }); + + it("does not re-enable an explicitly disabled channel when selected lazily", async () => { + const setupWizard = { + channel: "telegram", + getStatus: vi.fn(async () => ({ + channel: "telegram", + configured: true, + statusLines: [], + })), + configure: vi.fn(), + }; + const telegramPlugin = { + id: "telegram", + meta: { id: "telegram", label: "Telegram", blurb: "" }, + capabilities: {}, + config: { + resolveAccount: vi.fn(() => ({ enabled: false })), + }, + setupWizard, + }; + resolveChannelSetupEntries.mockReturnValue({ + entries: [ + { + id: "telegram", + meta: { id: "telegram", label: "Telegram", blurb: "" }, + }, + ], + installedCatalogEntries: [], + installableCatalogEntries: [], + installedCatalogById: new Map(), + installableCatalogById: new Map(), + }); + loadChannelSetupPluginRegistrySnapshotForChannel.mockReturnValue({ + channels: [{ plugin: telegramPlugin }], + channelSetups: [], + }); + const select = vi.fn().mockResolvedValueOnce("telegram").mockResolvedValueOnce("__done__"); + const cfg = { + channels: { + telegram: { enabled: false, token: "secret" }, + }, + }; + + const next = await setupChannels( + cfg as never, + {} as never, + { + confirm: vi.fn(async () => true), + note: vi.fn(async () => undefined), + select, + } as never, + { + deferStatusUntilSelection: true, + skipConfirm: true, + skipDmPolicyPrompt: true, + }, + ); + + expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledWith( + expect.objectContaining({ + channel: "telegram", + workspaceDir: "/tmp/openclaw-workspace", + }), + ); + expect(setupWizard.configure).not.toHaveBeenCalled(); + expect(next).toEqual({ + channels: { + telegram: { enabled: false, token: "secret" }, + }, + }); + }); }); diff --git a/src/flows/channel-setup.ts b/src/flows/channel-setup.ts index 65481dc2ed3..10d1e5ec062 100644 --- a/src/flows/channel-setup.ts +++ b/src/flows/channel-setup.ts @@ -323,6 +323,16 @@ export async function setupChannels( await refreshStatus(channel); return true; } + const disabledHint = resolveConfigDisabledHint(channel); + if (disabledHint) { + const plugin = await loadScopedChannelPlugin(channel); + if (!plugin) { + await prompter.note(`${channel} plugin not available (${disabledHint}).`, "Channel setup"); + return false; + } + await refreshStatus(channel); + return true; + } const result = enablePluginInConfig(next, channel); next = result.config; if (!result.enabled) {