From 64837e1eb93204ab688cb8cee7294a6ee4230ca5 Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Fri, 17 Apr 2026 12:06:42 -0400 Subject: [PATCH] CLI: preserve active setup plugin lookup --- src/flows/channel-setup.test.ts | 69 +++++++++++++++++++++++++++++++++ src/flows/channel-setup.ts | 8 +++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/flows/channel-setup.test.ts b/src/flows/channel-setup.test.ts index 058e2641434..040c2ea4b46 100644 --- a/src/flows/channel-setup.test.ts +++ b/src/flows/channel-setup.test.ts @@ -269,6 +269,75 @@ describe("setupChannels workspace shadow exclusion", () => { expect(collectChannelStatus).not.toHaveBeenCalled(); }); + it("uses an active deferred setup plugin without enabling config on selection", async () => { + const setupWizard = { + channel: "custom-chat", + getStatus: vi.fn(async () => ({ + channel: "custom-chat", + configured: false, + statusLines: [], + })), + configure: vi.fn(async ({ cfg }: { cfg: Record }) => ({ + cfg: { + ...cfg, + channels: { + "custom-chat": { token: "secret" }, + }, + }, + })), + }; + const activePlugin = { + id: "custom-chat", + meta: { id: "custom-chat", label: "Custom Chat", blurb: "" }, + capabilities: {}, + config: { + resolveAccount: vi.fn(() => ({})), + }, + setupWizard, + }; + listActiveChannelSetupPlugins.mockReturnValue([activePlugin]); + resolveChannelSetupEntries.mockReturnValue({ + entries: [ + { + id: "custom-chat", + meta: { id: "custom-chat", label: "Custom Chat", blurb: "" }, + }, + ], + installedCatalogEntries: [], + installableCatalogEntries: [], + installedCatalogById: new Map(), + installableCatalogById: new Map(), + }); + const select = vi.fn().mockResolvedValueOnce("custom-chat").mockResolvedValueOnce("__done__"); + + const next = await setupChannels( + {} 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).not.toHaveBeenCalled(); + expect(setupWizard.configure).toHaveBeenCalledWith( + expect.objectContaining({ + cfg: {}, + }), + ); + expect(next).toEqual({ + channels: { + "custom-chat": { token: "secret" }, + }, + }); + }); + it("loads the selected bundled catalog plugin without writing explicit plugin enablement", async () => { const setupWizard = { channel: "telegram", diff --git a/src/flows/channel-setup.ts b/src/flows/channel-setup.ts index e7cd7b69533..6faf4160430 100644 --- a/src/flows/channel-setup.ts +++ b/src/flows/channel-setup.ts @@ -125,8 +125,14 @@ export async function setupChannels( scopedPluginsById.set(channel, plugin); options?.onResolvedPlugin?.(channel, plugin); }; + const activePluginsById = new Map(); + const rememberActivePlugin = (plugin: ChannelSetupPlugin) => { + activePluginsById.set(plugin.id, plugin); + return plugin; + }; const getVisibleChannelPlugin = (channel: ChannelChoice): ChannelSetupPlugin | undefined => scopedPluginsById.get(channel) ?? + activePluginsById.get(channel) ?? (deferStatusUntilSelection ? undefined : getChannelSetupPlugin(channel)); const listVisibleInstalledPlugins = (params?: { includeRegistry?: boolean; @@ -135,7 +141,7 @@ export async function setupChannels( const merged = new Map(); const registryPlugins = includeRegistry ? listChannelSetupPlugins() - : listActiveChannelSetupPlugins(); + : listActiveChannelSetupPlugins().map(rememberActivePlugin); for (const plugin of registryPlugins) { if (shouldShowChannelInSetup(plugin.meta)) { merged.set(plugin.id, plugin);