diff --git a/extensions/whatsapp/src/channel.runtime.ts b/extensions/whatsapp/src/channel.runtime.ts new file mode 100644 index 00000000000..ff67d34ee10 --- /dev/null +++ b/extensions/whatsapp/src/channel.runtime.ts @@ -0,0 +1 @@ +export { whatsappSetupWizard } from "./setup-surface.js"; diff --git a/extensions/whatsapp/src/channel.ts b/extensions/whatsapp/src/channel.ts index e240824c743..63c01bca05c 100644 --- a/extensions/whatsapp/src/channel.ts +++ b/extensions/whatsapp/src/channel.ts @@ -33,11 +33,60 @@ import { } from "./accounts.js"; import { looksLikeWhatsAppTargetId, normalizeWhatsAppMessagingTarget } from "./normalize.js"; import { getWhatsAppRuntime } from "./runtime.js"; -import { whatsappSetupAdapter, whatsappSetupWizard } from "./setup-surface.js"; +import { whatsappSetupAdapter } from "./setup-core.js"; import { collectWhatsAppStatusIssues } from "./status-issues.js"; const meta = getChatChannelMeta("whatsapp"); +async function loadWhatsAppChannelRuntime() { + return await import("./channel.runtime.js"); +} + +const whatsappSetupWizardProxy = { + channel: "whatsapp", + status: { + configuredLabel: "linked", + unconfiguredLabel: "not linked", + configuredHint: "linked", + unconfiguredHint: "not linked", + configuredScore: 5, + unconfiguredScore: 4, + resolveConfigured: async ({ cfg }) => + await ( + await loadWhatsAppChannelRuntime() + ).whatsappSetupWizard.status.resolveConfigured({ + cfg, + }), + resolveStatusLines: async ({ cfg, configured }) => + await ( + await loadWhatsAppChannelRuntime() + ).whatsappSetupWizard.status.resolveStatusLines?.({ + cfg, + configured, + }), + }, + resolveShouldPromptAccountIds: (params) => + (params.shouldPromptAccountIds || params.options?.promptWhatsAppAccountId) ?? false, + credentials: [], + finalize: async (params) => + await ( + await loadWhatsAppChannelRuntime() + ).whatsappSetupWizard.finalize!(params), + disable: (cfg) => ({ + ...cfg, + channels: { + ...cfg.channels, + whatsapp: { + ...cfg.channels?.whatsapp, + enabled: false, + }, + }, + }), + onAccountRecorded: (accountId, options) => { + options?.onWhatsAppAccountId?.(accountId); + }, +} satisfies NonNullable["setupWizard"]>; + export const whatsappPlugin: ChannelPlugin = { id: "whatsapp", meta: { @@ -47,7 +96,7 @@ export const whatsappPlugin: ChannelPlugin = { forceAccountBinding: true, preferSessionLookupForAnnounceTarget: true, }, - setupWizard: whatsappSetupWizard, + setupWizard: whatsappSetupWizardProxy, agentTools: () => [getWhatsAppRuntime().channel.whatsapp.createLoginTool()], pairing: { idLabel: "whatsappSenderId", diff --git a/extensions/whatsapp/src/setup-core.ts b/extensions/whatsapp/src/setup-core.ts new file mode 100644 index 00000000000..2b243743076 --- /dev/null +++ b/extensions/whatsapp/src/setup-core.ts @@ -0,0 +1,52 @@ +import { + applyAccountNameToChannelSection, + migrateBaseNameToDefaultAccount, +} from "../../../src/channels/plugins/setup-helpers.js"; +import type { ChannelSetupAdapter } from "../../../src/channels/plugins/types.adapters.js"; +import { normalizeAccountId } from "../../../src/routing/session-key.js"; + +const channel = "whatsapp" as const; + +export const whatsappSetupAdapter: ChannelSetupAdapter = { + resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), + applyAccountName: ({ cfg, accountId, name }) => + applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name, + alwaysUseAccounts: true, + }), + applyAccountConfig: ({ cfg, accountId, input }) => { + const namedConfig = applyAccountNameToChannelSection({ + cfg, + channelKey: channel, + accountId, + name: input.name, + alwaysUseAccounts: true, + }); + const next = migrateBaseNameToDefaultAccount({ + cfg: namedConfig, + channelKey: channel, + alwaysUseAccounts: true, + }); + const entry = { + ...next.channels?.whatsapp?.accounts?.[accountId], + ...(input.authDir ? { authDir: input.authDir } : {}), + enabled: true, + }; + return { + ...next, + channels: { + ...next.channels, + whatsapp: { + ...next.channels?.whatsapp, + accounts: { + ...next.channels?.whatsapp?.accounts, + [accountId]: entry, + }, + }, + }, + }; + }, +}; diff --git a/extensions/whatsapp/src/setup-surface.ts b/extensions/whatsapp/src/setup-surface.ts index 180f84a3fbf..e0e9fa3191b 100644 --- a/extensions/whatsapp/src/setup-surface.ts +++ b/extensions/whatsapp/src/setup-surface.ts @@ -5,12 +5,7 @@ import { splitOnboardingEntries, } from "../../../src/channels/plugins/onboarding/helpers.js"; import { setOnboardingChannelEnabled } from "../../../src/channels/plugins/onboarding/helpers.js"; -import { - applyAccountNameToChannelSection, - migrateBaseNameToDefaultAccount, -} from "../../../src/channels/plugins/setup-helpers.js"; import type { ChannelSetupWizard } from "../../../src/channels/plugins/setup-wizard.js"; -import type { ChannelSetupAdapter } from "../../../src/channels/plugins/types.adapters.js"; import { formatCliCommand } from "../../../src/cli/command-format.js"; import type { OpenClawConfig } from "../../../src/config/config.js"; import { mergeWhatsAppConfig } from "../../../src/config/merge-config.js"; @@ -19,6 +14,7 @@ import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../../src/routing/ses import { formatDocsLink } from "../../../src/terminal/links.js"; import { normalizeE164, pathExists } from "../../../src/utils.js"; import { listWhatsAppAccountIds, resolveWhatsAppAuthDir } from "./accounts.js"; +import { whatsappSetupAdapter } from "./setup-core.js"; const channel = "whatsapp" as const; @@ -247,50 +243,6 @@ async function promptWhatsAppDmAccess(params: { return setWhatsAppAllowFrom(next, parsed.entries); } -export const whatsappSetupAdapter: ChannelSetupAdapter = { - resolveAccountId: ({ accountId }) => normalizeAccountId(accountId), - applyAccountName: ({ cfg, accountId, name }) => - applyAccountNameToChannelSection({ - cfg, - channelKey: channel, - accountId, - name, - alwaysUseAccounts: true, - }), - applyAccountConfig: ({ cfg, accountId, input }) => { - const namedConfig = applyAccountNameToChannelSection({ - cfg, - channelKey: channel, - accountId, - name: input.name, - alwaysUseAccounts: true, - }); - const next = migrateBaseNameToDefaultAccount({ - cfg: namedConfig, - channelKey: channel, - alwaysUseAccounts: true, - }); - const entry = { - ...next.channels?.whatsapp?.accounts?.[accountId], - ...(input.authDir ? { authDir: input.authDir } : {}), - enabled: true, - }; - return { - ...next, - channels: { - ...next.channels, - whatsapp: { - ...next.channels?.whatsapp, - accounts: { - ...next.channels?.whatsapp?.accounts, - [accountId]: entry, - }, - }, - }, - }; - }, -}; - export const whatsappSetupWizard: ChannelSetupWizard = { channel, status: {