@openclaw/whatsapp 2026.5.2 → 2026.5.3-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/dist/access-control-BQ3tCkH8.js +288 -0
  2. package/dist/account-config-CNQ33oav.js +47 -0
  3. package/dist/account-ids-DG18xddX.js +5 -0
  4. package/dist/accounts-BDqgpFEB.js +116 -0
  5. package/dist/action-runtime-DTGNgG-i.js +74 -0
  6. package/dist/action-runtime-api.js +2 -0
  7. package/dist/action-runtime.runtime.js +2 -0
  8. package/dist/active-listener-N7GFKsuN.js +11 -0
  9. package/dist/agent-tools-login-DpRxLNRB.js +89 -0
  10. package/dist/api.js +148 -0
  11. package/dist/audio-preflight.runtime-Bcdsl_ri.js +7 -0
  12. package/dist/auth-presence.js +32 -0
  13. package/dist/auth-store-BjCb50Ry.js +381 -0
  14. package/dist/channel-DQ-5Xoj9.js +542 -0
  15. package/dist/channel-config-api.js +2 -0
  16. package/dist/channel-plugin-api.js +2 -0
  17. package/dist/channel-react-action-Df20qAy9.js +42 -0
  18. package/dist/channel.runtime-DKXRnA8x.js +55 -0
  19. package/dist/channel.setup-DOHR2BGp.js +20 -0
  20. package/dist/command-policy-O8sRnqUV.js +8 -0
  21. package/dist/config-schema-Dmo66Ubb.js +27 -0
  22. package/dist/connection-controller-BiHAsTM8.js +596 -0
  23. package/dist/connection-controller-registry-D_iIGz5m.js +22 -0
  24. package/dist/constants-DLGCIbfl.js +4 -0
  25. package/dist/constants.js +2 -0
  26. package/dist/contract-api.js +19 -0
  27. package/dist/creds-files-_2V8jzQa.js +19 -0
  28. package/dist/directory-config-DVs4ffXu.js +37 -0
  29. package/dist/directory-contract-api.js +2 -0
  30. package/dist/doctor-A9tXm9Om.js +48 -0
  31. package/dist/doctor-contract-api.js +10 -0
  32. package/dist/group-session-contract-B8QBn0I2.js +15 -0
  33. package/dist/identity-QHAlV7Fu.js +75 -0
  34. package/dist/index.js +18 -0
  35. package/dist/legacy-session-surface-api.js +8 -0
  36. package/dist/legacy-state-migrations-api.js +2 -0
  37. package/dist/light-runtime-api.js +5 -0
  38. package/dist/login-DymdrKca.js +52 -0
  39. package/dist/login-qr-DIS0Iv-7.js +378 -0
  40. package/dist/login-qr-api.js +2 -0
  41. package/dist/login-qr-runtime.js +16 -0
  42. package/dist/monitor-C4Fhg_lD.js +3349 -0
  43. package/dist/normalize-CWYiGkXw.js +2 -0
  44. package/dist/normalize-target-BPVHNsM5.js +74 -0
  45. package/dist/outbound-adapter-BssVnZdz.js +29 -0
  46. package/dist/outbound-base-Bq1UYEK5.js +119 -0
  47. package/dist/outbound-media-contract-CGss_QHy.js +163 -0
  48. package/dist/outbound-payload-test-api.js +2 -0
  49. package/dist/quoted-message-TENQzyxV.js +108 -0
  50. package/dist/reaction-level-CRVEVAfi.js +16 -0
  51. package/dist/reply-resolver.runtime-BRCgoO4C.js +2 -0
  52. package/dist/resolve-outbound-target-CN-Wo6IY.js +39 -0
  53. package/dist/rolldown-runtime-RkAeH_Qm.js +27 -0
  54. package/dist/runtime-6fZ67abR.js +8 -0
  55. package/dist/runtime-api.js +15 -0
  56. package/dist/runtime-group-policy-Gp1lQ0at.js +11 -0
  57. package/dist/secret-contract-api.js +5 -0
  58. package/dist/security-contract-DqH8JDX6.js +26 -0
  59. package/dist/security-contract-api.js +2 -0
  60. package/dist/send-CIyLFxdZ.js +234 -0
  61. package/dist/session-contract-B0efQf9P.js +27 -0
  62. package/dist/session-errors-CSuKZPub.js +63 -0
  63. package/dist/session.runtime-C1eSE_KK.js +13 -0
  64. package/dist/setup-core-DZKvpzbH.js +46 -0
  65. package/dist/setup-entry.js +23 -0
  66. package/dist/setup-plugin-api.js +2 -0
  67. package/dist/setup-surface-ieFnIW4g.js +344 -0
  68. package/dist/shared-D_wzSVar.js +307 -0
  69. package/dist/state-migrations-DnCdvoYD.js +39 -0
  70. package/dist/targets.js +2 -0
  71. package/dist/test-api.js +3 -0
  72. package/dist/text-runtime-C1zNiZeO.js +116 -0
  73. package/package.json +14 -6
  74. package/action-runtime-api.ts +0 -1
  75. package/action-runtime.runtime.ts +0 -1
  76. package/api.ts +0 -213
  77. package/auth-presence.ts +0 -80
  78. package/channel-config-api.ts +0 -1
  79. package/channel-plugin-api.ts +0 -3
  80. package/config-api.ts +0 -4
  81. package/constants.ts +0 -1
  82. package/contract-api.ts +0 -29
  83. package/directory-contract-api.ts +0 -4
  84. package/doctor-contract-api.ts +0 -8
  85. package/index.test.ts +0 -13
  86. package/index.ts +0 -16
  87. package/legacy-session-surface-api.ts +0 -6
  88. package/legacy-state-migrations-api.ts +0 -1
  89. package/light-runtime-api.ts +0 -12
  90. package/login-qr-api.ts +0 -1
  91. package/login-qr-runtime.ts +0 -23
  92. package/outbound-payload-test-api.ts +0 -1
  93. package/runtime-api.ts +0 -84
  94. package/secret-contract-api.ts +0 -4
  95. package/security-contract-api.ts +0 -4
  96. package/setup-entry.test.ts +0 -21
  97. package/setup-entry.ts +0 -21
  98. package/setup-plugin-api.ts +0 -3
  99. package/src/account-config.ts +0 -77
  100. package/src/account-ids.ts +0 -13
  101. package/src/account-types.ts +0 -5
  102. package/src/accounts.test.ts +0 -182
  103. package/src/accounts.ts +0 -176
  104. package/src/accounts.whatsapp-auth.test.ts +0 -59
  105. package/src/action-runtime-target-auth.ts +0 -27
  106. package/src/action-runtime.test.ts +0 -330
  107. package/src/action-runtime.ts +0 -76
  108. package/src/active-listener.test.ts +0 -65
  109. package/src/active-listener.ts +0 -17
  110. package/src/agent-tools-login.test.ts +0 -81
  111. package/src/agent-tools-login.ts +0 -113
  112. package/src/approval-auth.test.ts +0 -24
  113. package/src/approval-auth.ts +0 -27
  114. package/src/auth-store.runtime.ts +0 -1
  115. package/src/auth-store.test.ts +0 -311
  116. package/src/auth-store.ts +0 -502
  117. package/src/auto-reply/config.runtime.ts +0 -16
  118. package/src/auto-reply/constants.ts +0 -1
  119. package/src/auto-reply/deliver-reply.test.ts +0 -843
  120. package/src/auto-reply/deliver-reply.ts +0 -279
  121. package/src/auto-reply/loggers.ts +0 -6
  122. package/src/auto-reply/mentions.ts +0 -131
  123. package/src/auto-reply/monitor/ack-reaction.test.ts +0 -170
  124. package/src/auto-reply/monitor/ack-reaction.ts +0 -99
  125. package/src/auto-reply/monitor/audio-preflight.runtime.ts +0 -9
  126. package/src/auto-reply/monitor/broadcast.ts +0 -153
  127. package/src/auto-reply/monitor/commands.ts +0 -19
  128. package/src/auto-reply/monitor/echo.ts +0 -64
  129. package/src/auto-reply/monitor/group-activation.runtime.ts +0 -1
  130. package/src/auto-reply/monitor/group-activation.test.ts +0 -189
  131. package/src/auto-reply/monitor/group-activation.ts +0 -73
  132. package/src/auto-reply/monitor/group-gating.audio-preflight.test.ts +0 -103
  133. package/src/auto-reply/monitor/group-gating.runtime.ts +0 -8
  134. package/src/auto-reply/monitor/group-gating.ts +0 -217
  135. package/src/auto-reply/monitor/group-members.test.ts +0 -56
  136. package/src/auto-reply/monitor/group-members.ts +0 -65
  137. package/src/auto-reply/monitor/inbound-context.test.ts +0 -97
  138. package/src/auto-reply/monitor/inbound-context.ts +0 -92
  139. package/src/auto-reply/monitor/inbound-dispatch.runtime.ts +0 -21
  140. package/src/auto-reply/monitor/inbound-dispatch.test.ts +0 -895
  141. package/src/auto-reply/monitor/inbound-dispatch.ts +0 -422
  142. package/src/auto-reply/monitor/last-route.test.ts +0 -37
  143. package/src/auto-reply/monitor/last-route.ts +0 -61
  144. package/src/auto-reply/monitor/message-line.runtime.ts +0 -38
  145. package/src/auto-reply/monitor/message-line.ts +0 -54
  146. package/src/auto-reply/monitor/on-message.audio-preflight.test.ts +0 -354
  147. package/src/auto-reply/monitor/on-message.ts +0 -291
  148. package/src/auto-reply/monitor/peer.ts +0 -17
  149. package/src/auto-reply/monitor/process-message.audio-preflight.test.ts +0 -420
  150. package/src/auto-reply/monitor/process-message.test.ts +0 -355
  151. package/src/auto-reply/monitor/process-message.ts +0 -531
  152. package/src/auto-reply/monitor/runtime-api.ts +0 -30
  153. package/src/auto-reply/monitor-state.test.ts +0 -64
  154. package/src/auto-reply/monitor-state.ts +0 -106
  155. package/src/auto-reply/monitor.ts +0 -600
  156. package/src/auto-reply/reply-resolver.runtime.ts +0 -1
  157. package/src/auto-reply/types.ts +0 -48
  158. package/src/auto-reply/util.ts +0 -63
  159. package/src/auto-reply/web-auto-reply-monitor.test.ts +0 -687
  160. package/src/auto-reply/web-auto-reply-utils.test.ts +0 -392
  161. package/src/auto-reply.broadcast-groups.combined.test.ts +0 -246
  162. package/src/auto-reply.broadcast-groups.test-harness.ts +0 -47
  163. package/src/auto-reply.impl.ts +0 -6
  164. package/src/auto-reply.test-harness.ts +0 -421
  165. package/src/auto-reply.ts +0 -1
  166. package/src/auto-reply.web-auto-reply.compresses-common-formats-jpeg-cap.test.ts +0 -427
  167. package/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts +0 -908
  168. package/src/auto-reply.web-auto-reply.last-route.test.ts +0 -184
  169. package/src/channel-actions.runtime.ts +0 -7
  170. package/src/channel-actions.test.ts +0 -216
  171. package/src/channel-actions.ts +0 -84
  172. package/src/channel-outbound.test.ts +0 -131
  173. package/src/channel-outbound.ts +0 -36
  174. package/src/channel-react-action.runtime.ts +0 -7
  175. package/src/channel-react-action.test.ts +0 -294
  176. package/src/channel-react-action.ts +0 -84
  177. package/src/channel.runtime.ts +0 -117
  178. package/src/channel.setup.test.ts +0 -461
  179. package/src/channel.setup.ts +0 -28
  180. package/src/channel.ts +0 -339
  181. package/src/command-policy.ts +0 -7
  182. package/src/config-accessors.test.ts +0 -34
  183. package/src/config-accessors.ts +0 -22
  184. package/src/config-schema.test.ts +0 -121
  185. package/src/config-schema.ts +0 -6
  186. package/src/config-ui-hints.ts +0 -24
  187. package/src/connection-controller-registry.test.ts +0 -27
  188. package/src/connection-controller-registry.ts +0 -49
  189. package/src/connection-controller.test.ts +0 -282
  190. package/src/connection-controller.ts +0 -679
  191. package/src/creds-files.ts +0 -19
  192. package/src/creds-persistence.ts +0 -102
  193. package/src/directory-config.test.ts +0 -60
  194. package/src/directory-config.ts +0 -40
  195. package/src/directory-contract.test.ts +0 -56
  196. package/src/doctor-contract.ts +0 -11
  197. package/src/doctor.test.ts +0 -74
  198. package/src/doctor.ts +0 -56
  199. package/src/group-intro.ts +0 -15
  200. package/src/group-policy.test.ts +0 -36
  201. package/src/group-policy.ts +0 -40
  202. package/src/group-session-contract.ts +0 -20
  203. package/src/group-session-key.test.ts +0 -53
  204. package/src/group-session-key.ts +0 -41
  205. package/src/heartbeat.ts +0 -34
  206. package/src/identity.ts +0 -164
  207. package/src/inbound/access-control.test-harness.ts +0 -37
  208. package/src/inbound/access-control.test.ts +0 -375
  209. package/src/inbound/access-control.ts +0 -237
  210. package/src/inbound/dedupe.ts +0 -132
  211. package/src/inbound/extract.test.ts +0 -282
  212. package/src/inbound/extract.ts +0 -488
  213. package/src/inbound/lifecycle.ts +0 -39
  214. package/src/inbound/media.node.test.ts +0 -83
  215. package/src/inbound/media.ts +0 -102
  216. package/src/inbound/monitor.ts +0 -890
  217. package/src/inbound/runtime-api.ts +0 -7
  218. package/src/inbound/save-media.runtime.ts +0 -1
  219. package/src/inbound/send-api.test.ts +0 -319
  220. package/src/inbound/send-api.ts +0 -145
  221. package/src/inbound/send-result.ts +0 -61
  222. package/src/inbound/types.ts +0 -106
  223. package/src/inbound-context.contract.test.ts +0 -32
  224. package/src/inbound-policy.ts +0 -231
  225. package/src/inbound.media.test.ts +0 -320
  226. package/src/inbound.test.ts +0 -290
  227. package/src/inbound.ts +0 -9
  228. package/src/login-qr.test.ts +0 -483
  229. package/src/login-qr.ts +0 -542
  230. package/src/login.coverage.test.ts +0 -133
  231. package/src/login.test.ts +0 -89
  232. package/src/login.ts +0 -70
  233. package/src/logout.test.ts +0 -162
  234. package/src/media.test.ts +0 -480
  235. package/src/media.ts +0 -10
  236. package/src/monitor-inbox.allows-messages-from-senders-allowfrom-list.test-support.ts +0 -400
  237. package/src/monitor-inbox.append-upsert.test-support.ts +0 -133
  238. package/src/monitor-inbox.behavior.test.ts +0 -5
  239. package/src/monitor-inbox.blocks-messages-from-unauthorized-senders-not-allowfrom.test-support.ts +0 -362
  240. package/src/monitor-inbox.captures-media-path-image-messages.test-support.ts +0 -306
  241. package/src/monitor-inbox.streams-inbound-messages.test-support.ts +0 -729
  242. package/src/monitor-inbox.test-harness.ts +0 -304
  243. package/src/normalize-target.ts +0 -123
  244. package/src/normalize.ts +0 -7
  245. package/src/outbound-adapter.poll.test.ts +0 -62
  246. package/src/outbound-adapter.sendpayload.test.ts +0 -195
  247. package/src/outbound-adapter.ts +0 -36
  248. package/src/outbound-base.test.ts +0 -560
  249. package/src/outbound-base.ts +0 -244
  250. package/src/outbound-media-contract.ts +0 -278
  251. package/src/outbound-media.runtime.ts +0 -36
  252. package/src/outbound-payload.contract.test.ts +0 -61
  253. package/src/outbound-send-deps.ts +0 -1
  254. package/src/outbound-test-support.ts +0 -16
  255. package/src/pairing-security.test-harness.ts +0 -59
  256. package/src/qr-image.ts +0 -1
  257. package/src/qr-terminal.ts +0 -1
  258. package/src/quoted-message.test.ts +0 -83
  259. package/src/quoted-message.ts +0 -184
  260. package/src/reaction-level.test.ts +0 -94
  261. package/src/reaction-level.ts +0 -21
  262. package/src/reconnect.test.ts +0 -51
  263. package/src/reconnect.ts +0 -55
  264. package/src/resolve-outbound-target.test.ts +0 -288
  265. package/src/resolve-outbound-target.ts +0 -58
  266. package/src/resolve-target.test.ts +0 -120
  267. package/src/runtime-api.ts +0 -59
  268. package/src/runtime-group-policy.ts +0 -16
  269. package/src/runtime.ts +0 -9
  270. package/src/security-contract.ts +0 -47
  271. package/src/security-fix.ts +0 -71
  272. package/src/send.test.ts +0 -534
  273. package/src/send.ts +0 -292
  274. package/src/session-contract.test.ts +0 -31
  275. package/src/session-contract.ts +0 -43
  276. package/src/session-errors.ts +0 -125
  277. package/src/session-route.test.ts +0 -41
  278. package/src/session-route.ts +0 -32
  279. package/src/session.runtime.ts +0 -8
  280. package/src/session.test.ts +0 -559
  281. package/src/session.ts +0 -330
  282. package/src/setup-core.ts +0 -52
  283. package/src/setup-finalize.ts +0 -446
  284. package/src/setup-surface.test.ts +0 -367
  285. package/src/setup-surface.ts +0 -69
  286. package/src/setup-test-helpers.ts +0 -216
  287. package/src/shared.ts +0 -291
  288. package/src/socket-timing.test.ts +0 -49
  289. package/src/socket-timing.ts +0 -38
  290. package/src/state-migrations.ts +0 -54
  291. package/src/status-issues.test.ts +0 -137
  292. package/src/status-issues.ts +0 -185
  293. package/src/system-prompt.test.ts +0 -199
  294. package/src/system-prompt.ts +0 -31
  295. package/src/targets-runtime.ts +0 -180
  296. package/src/test-helpers.ts +0 -690
  297. package/src/text-runtime.test.ts +0 -162
  298. package/src/text-runtime.ts +0 -11
  299. package/src/vcard.ts +0 -84
  300. package/targets.ts +0 -5
  301. package/test-api.ts +0 -2
  302. package/tsconfig.json +0 -16
@@ -0,0 +1,344 @@
1
+ import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-DG18xddX.js";
2
+ import { a as resolveWhatsAppAccount, o as resolveWhatsAppAuthDir } from "./accounts-BDqgpFEB.js";
3
+ import { i as formatWhatsAppWebAuthStatusState, m as readWebAuthState } from "./auth-store-BjCb50Ry.js";
4
+ import { t as whatsappSetupAdapter } from "./setup-core-DZKvpzbH.js";
5
+ import path from "node:path";
6
+ import { DEFAULT_ACCOUNT_ID, normalizeAllowFromEntries, normalizeE164, pathExists, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
7
+ import { formatCliCommand, formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
8
+ //#region extensions/whatsapp/src/setup-finalize.ts
9
+ function trimPromptText(value) {
10
+ return value?.trim() ?? "";
11
+ }
12
+ function isDefaultWhatsAppAccountKey(accountId) {
13
+ return accountId.trim().toLowerCase() === DEFAULT_ACCOUNT_ID;
14
+ }
15
+ function shouldWriteDefaultWhatsAppAccountConfigAtAccountScope(cfg) {
16
+ const accounts = cfg.channels?.whatsapp?.accounts;
17
+ if (!accounts) return false;
18
+ if (accounts.default) return true;
19
+ return Object.keys(accounts).some((accountId) => !isDefaultWhatsAppAccountKey(accountId));
20
+ }
21
+ function resolveDefaultWhatsAppAccountWriteKey(cfg) {
22
+ const accounts = cfg.channels?.whatsapp?.accounts;
23
+ if (!accounts) return DEFAULT_ACCOUNT_ID;
24
+ return Object.keys(accounts).find((accountId) => isDefaultWhatsAppAccountKey(accountId)) ?? DEFAULT_ACCOUNT_ID;
25
+ }
26
+ function resolveWhatsAppConfigPathPrefix(cfg, accountId) {
27
+ if (accountId === DEFAULT_ACCOUNT_ID && shouldWriteDefaultWhatsAppAccountConfigAtAccountScope(cfg)) return `channels.whatsapp.accounts.${resolveDefaultWhatsAppAccountWriteKey(cfg)}`;
28
+ return accountId === DEFAULT_ACCOUNT_ID ? "channels.whatsapp" : `channels.whatsapp.accounts.${accountId}`;
29
+ }
30
+ function mergeWhatsAppConfig(cfg, accountId, patch, options) {
31
+ const channelConfig = { ...cfg.channels?.whatsapp };
32
+ const mutableChannelConfig = channelConfig;
33
+ if (resolveWhatsAppConfigPathPrefix(cfg, accountId) === "channels.whatsapp") {
34
+ for (const [key, value] of Object.entries(patch)) {
35
+ if (value === void 0) {
36
+ if (options?.unsetOnUndefined?.includes(key)) delete mutableChannelConfig[key];
37
+ continue;
38
+ }
39
+ mutableChannelConfig[key] = value;
40
+ }
41
+ return {
42
+ ...cfg,
43
+ channels: {
44
+ ...cfg.channels,
45
+ whatsapp: channelConfig
46
+ }
47
+ };
48
+ }
49
+ const accounts = { ...channelConfig.accounts };
50
+ const targetAccountId = accountId === DEFAULT_ACCOUNT_ID ? resolveDefaultWhatsAppAccountWriteKey(cfg) : accountId;
51
+ const lowerDefaultAccount = accountId === DEFAULT_ACCOUNT_ID && targetAccountId !== DEFAULT_ACCOUNT_ID ? accounts[DEFAULT_ACCOUNT_ID] : void 0;
52
+ const nextAccount = {
53
+ ...accounts[targetAccountId],
54
+ ...lowerDefaultAccount
55
+ };
56
+ const mutableNextAccount = nextAccount;
57
+ for (const [key, value] of Object.entries(patch)) {
58
+ if (value === void 0) {
59
+ if (options?.unsetOnUndefined?.includes(key)) delete mutableNextAccount[key];
60
+ continue;
61
+ }
62
+ mutableNextAccount[key] = value;
63
+ }
64
+ accounts[targetAccountId] = nextAccount;
65
+ if (lowerDefaultAccount) delete accounts[DEFAULT_ACCOUNT_ID];
66
+ return {
67
+ ...cfg,
68
+ channels: {
69
+ ...cfg.channels,
70
+ whatsapp: {
71
+ ...channelConfig,
72
+ accounts
73
+ }
74
+ }
75
+ };
76
+ }
77
+ function setWhatsAppDmPolicy(cfg, accountId, dmPolicy) {
78
+ return mergeWhatsAppConfig(cfg, accountId, { dmPolicy });
79
+ }
80
+ function setWhatsAppAllowFrom(cfg, accountId, allowFrom) {
81
+ return mergeWhatsAppConfig(cfg, accountId, { allowFrom }, { unsetOnUndefined: ["allowFrom"] });
82
+ }
83
+ function setWhatsAppSelfChatMode(cfg, accountId, selfChatMode) {
84
+ return mergeWhatsAppConfig(cfg, accountId, { selfChatMode });
85
+ }
86
+ async function detectWhatsAppLinked(cfg, accountId) {
87
+ const { authDir } = resolveWhatsAppAuthDir({
88
+ cfg,
89
+ accountId
90
+ });
91
+ return await pathExists(path.join(authDir, "creds.json"));
92
+ }
93
+ async function promptWhatsAppOwnerAllowFrom(params) {
94
+ const { prompter, existingAllowFrom } = params;
95
+ await prompter.note("We need the sender/owner number so OpenClaw can allowlist you.", "WhatsApp number");
96
+ const normalized = normalizeE164(trimPromptText(await prompter.text({
97
+ message: "Your personal WhatsApp number (the phone you will message from)",
98
+ placeholder: "+15555550123",
99
+ initialValue: existingAllowFrom[0],
100
+ validate: (value) => {
101
+ const raw = trimPromptText(value);
102
+ if (!raw) return "Required";
103
+ if (!normalizeE164(raw)) return `Invalid number: ${raw}`;
104
+ }
105
+ })));
106
+ if (!normalized) throw new Error("Invalid WhatsApp owner number (expected E.164 after validation).");
107
+ return {
108
+ normalized,
109
+ allowFrom: normalizeAllowFromEntries([...existingAllowFrom.filter((item) => item !== "*"), normalized], normalizeE164)
110
+ };
111
+ }
112
+ async function applyWhatsAppOwnerAllowlist(params) {
113
+ const { normalized, allowFrom } = await promptWhatsAppOwnerAllowFrom({
114
+ prompter: params.prompter,
115
+ existingAllowFrom: params.existingAllowFrom
116
+ });
117
+ let next = setWhatsAppSelfChatMode(params.cfg, params.accountId, true);
118
+ next = setWhatsAppDmPolicy(next, params.accountId, "allowlist");
119
+ next = setWhatsAppAllowFrom(next, params.accountId, allowFrom);
120
+ await params.prompter.note([...params.messageLines, `- allowFrom includes ${normalized}`].join("\n"), params.title);
121
+ return next;
122
+ }
123
+ function parseWhatsAppAllowFromEntries(raw) {
124
+ const parts = splitSetupEntries(raw);
125
+ if (parts.length === 0) return { entries: [] };
126
+ const entries = [];
127
+ for (const part of parts) {
128
+ if (part === "*") {
129
+ entries.push("*");
130
+ continue;
131
+ }
132
+ const normalized = normalizeE164(part);
133
+ if (!normalized) return {
134
+ entries: [],
135
+ invalidEntry: part
136
+ };
137
+ entries.push(normalized);
138
+ }
139
+ return { entries: normalizeAllowFromEntries(entries, normalizeE164) };
140
+ }
141
+ async function promptWhatsAppDmAccess(params) {
142
+ const accountId = params.accountId.trim() || DEFAULT_ACCOUNT_ID;
143
+ const account = resolveWhatsAppAccount({
144
+ cfg: params.cfg,
145
+ accountId
146
+ });
147
+ const existingPolicy = account.dmPolicy ?? "pairing";
148
+ const existingAllowFrom = account.allowFrom ?? [];
149
+ const existingLabel = existingAllowFrom.length > 0 ? existingAllowFrom.join(", ") : "unset";
150
+ const configPathPrefix = resolveWhatsAppConfigPathPrefix(params.cfg, accountId);
151
+ const policyKey = `${configPathPrefix}.dmPolicy`;
152
+ const allowFromKey = `${configPathPrefix}.allowFrom`;
153
+ if (params.forceAllowFrom) return await applyWhatsAppOwnerAllowlist({
154
+ cfg: params.cfg,
155
+ accountId,
156
+ prompter: params.prompter,
157
+ existingAllowFrom,
158
+ title: "WhatsApp allowlist",
159
+ messageLines: ["Allowlist mode enabled."]
160
+ });
161
+ await params.prompter.note([
162
+ `WhatsApp direct chats are gated by \`${policyKey}\` + \`${allowFromKey}\`.`,
163
+ "- pairing (default): unknown senders get a pairing code; owner approves",
164
+ "- allowlist: unknown senders are blocked",
165
+ "- open: public inbound DMs (requires allowFrom to include \"*\")",
166
+ "- disabled: ignore WhatsApp DMs",
167
+ "",
168
+ `Current: dmPolicy=${existingPolicy}, allowFrom=${existingLabel}`,
169
+ `Docs: ${formatDocsLink("/whatsapp", "whatsapp")}`
170
+ ].join("\n"), "WhatsApp DM access");
171
+ if (await params.prompter.select({
172
+ message: "WhatsApp phone setup",
173
+ options: [{
174
+ value: "personal",
175
+ label: "This is my personal phone number"
176
+ }, {
177
+ value: "separate",
178
+ label: "Separate phone just for OpenClaw"
179
+ }]
180
+ }) === "personal") return await applyWhatsAppOwnerAllowlist({
181
+ cfg: params.cfg,
182
+ accountId,
183
+ prompter: params.prompter,
184
+ existingAllowFrom,
185
+ title: "WhatsApp personal phone",
186
+ messageLines: ["Personal phone mode enabled.", "- dmPolicy set to allowlist (pairing skipped)"]
187
+ });
188
+ const policy = await params.prompter.select({
189
+ message: "WhatsApp DM policy",
190
+ options: [
191
+ {
192
+ value: "pairing",
193
+ label: "Pairing (recommended)"
194
+ },
195
+ {
196
+ value: "allowlist",
197
+ label: "Allowlist only (block unknown senders)"
198
+ },
199
+ {
200
+ value: "open",
201
+ label: "Open (public inbound DMs)"
202
+ },
203
+ {
204
+ value: "disabled",
205
+ label: "Disabled (ignore WhatsApp DMs)"
206
+ }
207
+ ]
208
+ });
209
+ let next = setWhatsAppSelfChatMode(params.cfg, accountId, false);
210
+ next = setWhatsAppDmPolicy(next, accountId, policy);
211
+ if (policy === "open") {
212
+ const allowFrom = normalizeAllowFromEntries(["*", ...existingAllowFrom], normalizeE164);
213
+ next = setWhatsAppAllowFrom(next, accountId, allowFrom.length > 0 ? allowFrom : ["*"]);
214
+ return next;
215
+ }
216
+ if (policy === "disabled") return next;
217
+ const allowOptions = existingAllowFrom.length > 0 ? [
218
+ {
219
+ value: "keep",
220
+ label: "Keep current allowFrom"
221
+ },
222
+ {
223
+ value: "unset",
224
+ label: "Unset allowFrom (use pairing approvals only)"
225
+ },
226
+ {
227
+ value: "list",
228
+ label: "Set allowFrom to specific numbers"
229
+ }
230
+ ] : [{
231
+ value: "unset",
232
+ label: "Unset allowFrom (default)"
233
+ }, {
234
+ value: "list",
235
+ label: "Set allowFrom to specific numbers"
236
+ }];
237
+ const mode = await params.prompter.select({
238
+ message: "WhatsApp allowFrom (optional pre-allowlist)",
239
+ options: allowOptions.map((opt) => ({
240
+ value: opt.value,
241
+ label: opt.label
242
+ }))
243
+ });
244
+ if (mode === "keep") return next;
245
+ if (mode === "unset") return setWhatsAppAllowFrom(next, accountId, void 0);
246
+ const parsed = parseWhatsAppAllowFromEntries(trimPromptText(await params.prompter.text({
247
+ message: "Allowed sender numbers (comma-separated, E.164)",
248
+ placeholder: "+15555550123, +447700900123",
249
+ validate: (value) => {
250
+ const raw = trimPromptText(value);
251
+ if (!raw) return "Required";
252
+ const parsed = parseWhatsAppAllowFromEntries(raw);
253
+ if (parsed.entries.length === 0 && !parsed.invalidEntry) return "Required";
254
+ if (parsed.invalidEntry) return `Invalid number: ${parsed.invalidEntry}`;
255
+ }
256
+ })));
257
+ if (parsed.invalidEntry) throw new Error(`Invalid number: ${parsed.invalidEntry}`);
258
+ if (parsed.entries.length === 0) throw new Error("Invalid WhatsApp allowFrom list (expected at least one E.164 number).");
259
+ return setWhatsAppAllowFrom(next, accountId, parsed.entries);
260
+ }
261
+ async function finalizeWhatsAppSetup(params) {
262
+ const accountId = params.accountId.trim() || resolveDefaultWhatsAppAccountId(params.cfg);
263
+ let next = accountId === DEFAULT_ACCOUNT_ID ? params.cfg : whatsappSetupAdapter.applyAccountConfig({
264
+ cfg: params.cfg,
265
+ accountId,
266
+ input: {}
267
+ });
268
+ const linked = await detectWhatsAppLinked(next, accountId);
269
+ const { authDir } = resolveWhatsAppAuthDir({
270
+ cfg: next,
271
+ accountId
272
+ });
273
+ if (!linked) await params.prompter.note([
274
+ "Scan the QR with WhatsApp on your phone.",
275
+ `Credentials are stored under ${authDir}/ for future runs.`,
276
+ `Docs: ${formatDocsLink("/whatsapp", "whatsapp")}`
277
+ ].join("\n"), "WhatsApp linking");
278
+ if (await params.prompter.confirm({
279
+ message: linked ? "WhatsApp already linked. Re-link now?" : "Link WhatsApp now (QR)?",
280
+ initialValue: !linked
281
+ })) try {
282
+ const { loginWeb } = await import("./login-DymdrKca.js").then((n) => n.n);
283
+ await loginWeb(false, void 0, params.runtime, accountId);
284
+ } catch (error) {
285
+ params.runtime.error(`WhatsApp login failed: ${String(error)}`);
286
+ await params.prompter.note(`Docs: ${formatDocsLink("/whatsapp", "whatsapp")}`, "WhatsApp help");
287
+ }
288
+ else if (!linked) await params.prompter.note(`Run \`${formatCliCommand("openclaw channels login")}\` later to link WhatsApp.`, "WhatsApp");
289
+ next = await promptWhatsAppDmAccess({
290
+ cfg: next,
291
+ accountId,
292
+ forceAllowFrom: params.forceAllowFrom,
293
+ prompter: params.prompter
294
+ });
295
+ return { cfg: next };
296
+ }
297
+ //#endregion
298
+ //#region extensions/whatsapp/src/setup-surface.ts
299
+ const channel = "whatsapp";
300
+ async function readWhatsAppSetupLinkState(cfg, accountId) {
301
+ const { authDir } = resolveWhatsAppAuthDir({
302
+ cfg,
303
+ accountId
304
+ });
305
+ return await readWebAuthState(authDir);
306
+ }
307
+ const whatsappSetupWizard = {
308
+ channel,
309
+ status: {
310
+ configuredLabel: "linked",
311
+ unconfiguredLabel: "not linked",
312
+ configuredHint: "linked",
313
+ unconfiguredHint: "not linked",
314
+ configuredScore: 5,
315
+ unconfiguredScore: 4,
316
+ resolveConfigured: async ({ cfg, accountId }) => {
317
+ for (const resolvedAccountId of accountId ? [accountId] : listAccountIds(cfg)) if (await readWhatsAppSetupLinkState(cfg, resolvedAccountId) === "linked") return true;
318
+ return false;
319
+ },
320
+ resolveStatusLines: async ({ cfg, accountId, configured }) => {
321
+ const linkedAccountId = (await Promise.all((accountId ? [accountId] : listAccountIds(cfg)).map(async (resolvedAccountId) => ({
322
+ accountId: resolvedAccountId,
323
+ state: await readWhatsAppSetupLinkState(cfg, resolvedAccountId)
324
+ })))).find((entry) => entry.state === "linked" || entry.state === "unstable");
325
+ const labelAccountId = accountId ?? linkedAccountId?.accountId;
326
+ return [`${labelAccountId ? `WhatsApp (${labelAccountId === DEFAULT_ACCOUNT_ID ? "default" : labelAccountId})` : "WhatsApp"}: ${configured ? formatWhatsAppWebAuthStatusState("linked") : formatWhatsAppWebAuthStatusState(linkedAccountId?.state ?? "not-linked")}`];
327
+ }
328
+ },
329
+ resolveShouldPromptAccountIds: ({ shouldPromptAccountIds }) => shouldPromptAccountIds,
330
+ credentials: [],
331
+ finalize: async ({ cfg, accountId, forceAllowFrom, prompter, runtime }) => await finalizeWhatsAppSetup({
332
+ cfg,
333
+ accountId,
334
+ forceAllowFrom,
335
+ prompter,
336
+ runtime
337
+ }),
338
+ disable: (cfg) => setSetupChannelEnabled(cfg, channel, false),
339
+ onAccountRecorded: (accountId, options) => {
340
+ options?.onAccountId?.(channel, accountId);
341
+ }
342
+ };
343
+ //#endregion
344
+ export { whatsappSetupWizard };
@@ -0,0 +1,307 @@
1
+ import { r as resolveDefaultWhatsAppAccountId, t as listAccountIds } from "./account-ids-DG18xddX.js";
2
+ import { a as resolveWhatsAppAccount, n as hasAnyWhatsAppAuth } from "./accounts-BDqgpFEB.js";
3
+ import { a as normalizeWhatsAppAllowFromEntries } from "./normalize-target-BPVHNsM5.js";
4
+ import { t as WhatsAppChannelConfigSchema } from "./config-schema-Dmo66Ubb.js";
5
+ import { n as whatsappDoctor } from "./doctor-A9tXm9Om.js";
6
+ import { t as resolveLegacyGroupSessionKey } from "./group-session-contract-B8QBn0I2.js";
7
+ import { n as unsupportedSecretRefSurfacePatterns, t as collectUnsupportedSecretRefConfigCandidates } from "./security-contract-DqH8JDX6.js";
8
+ import { n as deriveLegacySessionChatType, r as isLegacyGroupSessionKey, t as canonicalizeLegacySessionKey } from "./session-contract-B0efQf9P.js";
9
+ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-core";
10
+ import { normalizeE164 } from "openclaw/plugin-sdk/account-resolution";
11
+ import { createChannelPluginBase, getChatChannelMeta } from "openclaw/plugin-sdk/core";
12
+ import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1 } from "openclaw/plugin-sdk/account-id";
13
+ import { collectOpenGroupPolicyRouteAllowlistWarnings, createAllowlistProviderGroupPolicyWarningCollector, resolveChannelGroupRequireMention, resolveChannelGroupToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
14
+ import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
15
+ import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
16
+ import { createDelegatedSetupWizardProxy } from "openclaw/plugin-sdk/setup-runtime";
17
+ import { readChannelAllowFromStore } from "openclaw/plugin-sdk/channel-pairing";
18
+ //#region extensions/whatsapp/src/config-accessors.ts
19
+ function formatWhatsAppConfigAllowFromEntries(allowFrom) {
20
+ return normalizeWhatsAppAllowFromEntries(allowFrom);
21
+ }
22
+ //#endregion
23
+ //#region extensions/whatsapp/src/group-intro.ts
24
+ const WHATSAPP_GROUP_INTRO_HINT = "WhatsApp IDs: SenderId is the participant JID (group participant id).";
25
+ function resolveWhatsAppGroupIntroHint() {
26
+ return WHATSAPP_GROUP_INTRO_HINT;
27
+ }
28
+ function resolveWhatsAppMentionStripRegexes(ctx) {
29
+ const selfE164 = (ctx.To ?? "").replace(/^whatsapp:/i, "");
30
+ if (!selfE164) return [];
31
+ const escaped = selfE164.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
32
+ return [new RegExp(escaped, "g"), new RegExp(`@${escaped}`, "g")];
33
+ }
34
+ //#endregion
35
+ //#region extensions/whatsapp/src/group-policy.ts
36
+ function resolveWhatsAppGroupRequireMention(params) {
37
+ return resolveChannelGroupRequireMention({
38
+ cfg: params.cfg,
39
+ channel: "whatsapp",
40
+ groupId: params.groupId,
41
+ accountId: params.accountId
42
+ });
43
+ }
44
+ function resolveWhatsAppGroupToolPolicy(params) {
45
+ return resolveChannelGroupToolsPolicy({
46
+ cfg: params.cfg,
47
+ channel: "whatsapp",
48
+ groupId: params.groupId,
49
+ accountId: params.accountId,
50
+ senderId: params.senderId,
51
+ senderName: params.senderName,
52
+ senderUsername: params.senderUsername,
53
+ senderE164: params.senderE164
54
+ });
55
+ }
56
+ //#endregion
57
+ //#region extensions/whatsapp/src/security-fix.ts
58
+ function applyGroupAllowFromFromStore(params) {
59
+ const next = structuredClone(params.cfg ?? {});
60
+ const section = next.channels?.whatsapp;
61
+ if (!section || typeof section !== "object" || params.storeAllowFrom.length === 0) return params.cfg;
62
+ let changed = false;
63
+ const maybeApply = (prefix, holder) => {
64
+ if (holder.groupPolicy !== "allowlist") return;
65
+ const allowFrom = Array.isArray(holder.allowFrom) ? holder.allowFrom : [];
66
+ const groupAllowFrom = Array.isArray(holder.groupAllowFrom) ? holder.groupAllowFrom : [];
67
+ if (allowFrom.length > 0 || groupAllowFrom.length > 0) return;
68
+ holder.groupAllowFrom = params.storeAllowFrom;
69
+ params.changes.push(`${prefix}groupAllowFrom=pairing-store`);
70
+ changed = true;
71
+ };
72
+ maybeApply("channels.whatsapp.", section);
73
+ const accounts = section.accounts;
74
+ if (accounts && typeof accounts === "object") for (const [accountId, accountValue] of Object.entries(accounts)) {
75
+ if (!accountValue || typeof accountValue !== "object") continue;
76
+ maybeApply(`channels.whatsapp.accounts.${accountId}.`, accountValue);
77
+ }
78
+ return changed ? next : params.cfg;
79
+ }
80
+ async function applyWhatsAppSecurityConfigFixes(params) {
81
+ const fromStore = await readChannelAllowFromStore("whatsapp", params.env, DEFAULT_ACCOUNT_ID$1).catch(() => []);
82
+ const normalized = Array.from(new Set(fromStore.map((entry) => entry.trim()))).filter(Boolean);
83
+ if (normalized.length === 0) return {
84
+ config: params.cfg,
85
+ changes: []
86
+ };
87
+ const changes = [];
88
+ return {
89
+ config: applyGroupAllowFromFromStore({
90
+ cfg: params.cfg,
91
+ storeAllowFrom: normalized,
92
+ changes
93
+ }),
94
+ changes
95
+ };
96
+ }
97
+ //#endregion
98
+ //#region extensions/whatsapp/src/shared.ts
99
+ const WHATSAPP_CHANNEL = "whatsapp";
100
+ const WHATSAPP_GROUP_SCOPE_FIELDS = [
101
+ "groupPolicy",
102
+ "groupAllowFrom",
103
+ "groups"
104
+ ];
105
+ function resolveWhatsAppAccountKey(accounts, accountId) {
106
+ if (!accounts) return;
107
+ if (Object.hasOwn(accounts, accountId)) return accountId;
108
+ const normalizedAccountId = accountId.trim().toLowerCase();
109
+ return Object.keys(accounts).find((key) => key.trim().toLowerCase() === normalizedAccountId);
110
+ }
111
+ function resolveWhatsAppGroupScopeBasePath(params) {
112
+ const accountId = typeof params.accountId === "string" ? params.accountId.trim() || DEFAULT_ACCOUNT_ID : DEFAULT_ACCOUNT_ID;
113
+ const accounts = params.cfg.channels?.whatsapp?.accounts;
114
+ const accountKey = resolveWhatsAppAccountKey(accounts, accountId);
115
+ const defaultAccountKey = resolveWhatsAppAccountKey(accounts, DEFAULT_ACCOUNT_ID);
116
+ const accountConfig = accountKey ? accounts?.[accountKey] : void 0;
117
+ const defaultAccountConfig = defaultAccountKey ? accounts?.[defaultAccountKey] : void 0;
118
+ const matchesAnyGroupScopeField = (config) => WHATSAPP_GROUP_SCOPE_FIELDS.some((field) => config?.[field] !== void 0);
119
+ if (matchesAnyGroupScopeField(accountConfig)) return `channels.whatsapp.accounts.${accountKey}`;
120
+ if (accountId !== DEFAULT_ACCOUNT_ID && matchesAnyGroupScopeField(defaultAccountConfig)) return `channels.whatsapp.accounts.${defaultAccountKey}`;
121
+ return "channels.whatsapp";
122
+ }
123
+ function resolveWhatsAppConfigPath(params) {
124
+ return `${resolveWhatsAppGroupScopeBasePath(params)}.${params.field}`;
125
+ }
126
+ async function loadWhatsAppChannelRuntime() {
127
+ return await import("./channel.runtime-DKXRnA8x.js");
128
+ }
129
+ async function loadWhatsAppSetupSurface() {
130
+ return await import("./setup-surface-ieFnIW4g.js");
131
+ }
132
+ const whatsappSetupWizardProxy = createWhatsAppSetupWizardProxy(async () => (await loadWhatsAppSetupSurface()).whatsappSetupWizard);
133
+ const whatsappConfigAdapter = createScopedChannelConfigAdapter({
134
+ sectionKey: WHATSAPP_CHANNEL,
135
+ listAccountIds,
136
+ resolveAccount: adaptScopedAccountAccessor(resolveWhatsAppAccount),
137
+ defaultAccountId: resolveDefaultWhatsAppAccountId,
138
+ clearBaseFields: [],
139
+ allowTopLevel: false,
140
+ resolveAllowFrom: (account) => account.allowFrom,
141
+ formatAllowFrom: (allowFrom) => formatWhatsAppConfigAllowFromEntries(allowFrom),
142
+ resolveDefaultTo: (account) => account.defaultTo
143
+ });
144
+ const whatsappResolveDmPolicy = createScopedDmSecurityResolver({
145
+ channelKey: WHATSAPP_CHANNEL,
146
+ resolvePolicy: (account) => account.dmPolicy,
147
+ resolveAllowFrom: (account) => account.allowFrom,
148
+ policyPathSuffix: "dmPolicy",
149
+ normalizeEntry: (raw) => normalizeE164(raw),
150
+ inheritSharedDefaultsFromDefaultAccount: true
151
+ });
152
+ function createWhatsAppSetupWizardProxy(loadWizard) {
153
+ return createDelegatedSetupWizardProxy({
154
+ channel: WHATSAPP_CHANNEL,
155
+ loadWizard,
156
+ status: {
157
+ configuredLabel: "linked",
158
+ unconfiguredLabel: "not linked",
159
+ configuredHint: "linked",
160
+ unconfiguredHint: "not linked",
161
+ configuredScore: 5,
162
+ unconfiguredScore: 4
163
+ },
164
+ resolveShouldPromptAccountIds: (params) => params.shouldPromptAccountIds,
165
+ credentials: [],
166
+ delegateFinalize: true,
167
+ disable: (cfg) => ({
168
+ ...cfg,
169
+ channels: {
170
+ ...cfg.channels,
171
+ whatsapp: {
172
+ ...cfg.channels?.whatsapp,
173
+ enabled: false
174
+ }
175
+ }
176
+ }),
177
+ onAccountRecorded: (accountId, options) => {
178
+ options?.onAccountId?.(WHATSAPP_CHANNEL, accountId);
179
+ }
180
+ });
181
+ }
182
+ function createWhatsAppPluginBase(params) {
183
+ const collectWhatsAppSecurityWarnings = createAllowlistProviderGroupPolicyWarningCollector({
184
+ providerConfigPresent: (cfg) => cfg.channels?.whatsapp !== void 0,
185
+ resolveGroupPolicy: ({ account }) => account.groupPolicy,
186
+ collect: ({ account, accountId, cfg, groupPolicy }) => collectOpenGroupPolicyRouteAllowlistWarnings({
187
+ groupPolicy,
188
+ routeAllowlistConfigured: Boolean(account.groups) && Object.keys(account.groups ?? {}).length > 0,
189
+ restrictSenders: {
190
+ surface: "WhatsApp groups",
191
+ openScope: "any member in allowed groups",
192
+ groupPolicyPath: resolveWhatsAppConfigPath({
193
+ cfg,
194
+ accountId,
195
+ field: "groupPolicy"
196
+ }),
197
+ groupAllowFromPath: resolveWhatsAppConfigPath({
198
+ cfg,
199
+ accountId,
200
+ field: "groupAllowFrom"
201
+ })
202
+ },
203
+ noRouteAllowlist: {
204
+ surface: "WhatsApp groups",
205
+ routeAllowlistPath: resolveWhatsAppConfigPath({
206
+ cfg,
207
+ accountId,
208
+ field: "groups"
209
+ }),
210
+ routeScope: "group",
211
+ groupPolicyPath: resolveWhatsAppConfigPath({
212
+ cfg,
213
+ accountId,
214
+ field: "groupPolicy"
215
+ }),
216
+ groupAllowFromPath: resolveWhatsAppConfigPath({
217
+ cfg,
218
+ accountId,
219
+ field: "groupAllowFrom"
220
+ })
221
+ }
222
+ })
223
+ });
224
+ const base = createChannelPluginBase({
225
+ id: WHATSAPP_CHANNEL,
226
+ meta: {
227
+ ...getChatChannelMeta(WHATSAPP_CHANNEL),
228
+ showConfigured: false,
229
+ quickstartAllowFrom: true,
230
+ forceAccountBinding: true,
231
+ preferSessionLookupForAnnounceTarget: true
232
+ },
233
+ setupWizard: params.setupWizard,
234
+ capabilities: {
235
+ chatTypes: [
236
+ "direct",
237
+ "group",
238
+ "channel"
239
+ ],
240
+ polls: true,
241
+ reactions: true,
242
+ media: true,
243
+ tts: { voice: {
244
+ synthesisTarget: "voice-note",
245
+ transcodesAudio: true
246
+ } }
247
+ },
248
+ reload: {
249
+ configPrefixes: ["web"],
250
+ noopPrefixes: ["channels.whatsapp"]
251
+ },
252
+ gatewayMethods: ["web.login.start", "web.login.wait"],
253
+ configSchema: WhatsAppChannelConfigSchema,
254
+ config: {
255
+ ...whatsappConfigAdapter,
256
+ isEnabled: (account, cfg) => account.enabled && cfg.web?.enabled !== false,
257
+ disabledReason: () => "disabled",
258
+ isConfigured: params.isConfigured,
259
+ hasPersistedAuthState: ({ cfg }) => hasAnyWhatsAppAuth(cfg),
260
+ unconfiguredReason: () => "not linked",
261
+ describeAccount: (account) => describeAccountSnapshot({
262
+ account,
263
+ configured: Boolean(account.authDir),
264
+ extra: {
265
+ linked: Boolean(account.authDir),
266
+ dmPolicy: account.dmPolicy,
267
+ allowFrom: account.allowFrom
268
+ }
269
+ })
270
+ },
271
+ security: {
272
+ applyConfigFixes: applyWhatsAppSecurityConfigFixes,
273
+ resolveDmPolicy: whatsappResolveDmPolicy,
274
+ collectWarnings: collectWhatsAppSecurityWarnings
275
+ },
276
+ doctor: whatsappDoctor,
277
+ setup: params.setup,
278
+ groups: params.groups
279
+ });
280
+ return {
281
+ ...base,
282
+ setupWizard: base.setupWizard,
283
+ capabilities: base.capabilities,
284
+ reload: base.reload,
285
+ gatewayMethods: base.gatewayMethods,
286
+ configSchema: base.configSchema,
287
+ config: base.config,
288
+ messaging: {
289
+ defaultMarkdownTableMode: "bullets",
290
+ deriveLegacySessionChatType,
291
+ resolveLegacyGroupSessionKey,
292
+ isLegacyGroupSessionKey,
293
+ canonicalizeLegacySessionKey: (params) => canonicalizeLegacySessionKey({
294
+ key: params.key,
295
+ agentId: params.agentId
296
+ })
297
+ },
298
+ secrets: {
299
+ unsupportedSecretRefSurfacePatterns,
300
+ collectUnsupportedSecretRefConfigCandidates
301
+ },
302
+ security: base.security,
303
+ groups: base.groups
304
+ };
305
+ }
306
+ //#endregion
307
+ export { resolveWhatsAppGroupToolPolicy as a, formatWhatsAppConfigAllowFromEntries as c, resolveWhatsAppGroupRequireMention as i, loadWhatsAppChannelRuntime as n, resolveWhatsAppGroupIntroHint as o, whatsappSetupWizardProxy as r, resolveWhatsAppMentionStripRegexes as s, createWhatsAppPluginBase as t };
@@ -0,0 +1,39 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
4
+ //#region extensions/whatsapp/src/state-migrations.ts
5
+ function fileExists(pathValue) {
6
+ try {
7
+ return fs.existsSync(pathValue) && fs.statSync(pathValue).isFile();
8
+ } catch {
9
+ return false;
10
+ }
11
+ }
12
+ function isLegacyWhatsAppAuthFile(name) {
13
+ if (name === "creds.json" || name === "creds.json.bak") return true;
14
+ if (!name.endsWith(".json")) return false;
15
+ return /^(app-state-sync|session|sender-key|pre-key)-/.test(name);
16
+ }
17
+ function detectWhatsAppLegacyStateMigrations(params) {
18
+ const targetDir = path.join(params.oauthDir, "whatsapp", DEFAULT_ACCOUNT_ID);
19
+ return (() => {
20
+ try {
21
+ return fs.readdirSync(params.oauthDir, { withFileTypes: true });
22
+ } catch {
23
+ return [];
24
+ }
25
+ })().flatMap((entry) => {
26
+ if (!entry.isFile() || entry.name === "oauth.json" || !isLegacyWhatsAppAuthFile(entry.name)) return [];
27
+ const sourcePath = path.join(params.oauthDir, entry.name);
28
+ const targetPath = path.join(targetDir, entry.name);
29
+ if (fileExists(targetPath)) return [];
30
+ return [{
31
+ kind: "move",
32
+ label: `WhatsApp auth ${entry.name}`,
33
+ sourcePath,
34
+ targetPath
35
+ }];
36
+ });
37
+ }
38
+ //#endregion
39
+ export { detectWhatsAppLegacyStateMigrations as t };
@@ -0,0 +1,2 @@
1
+ import { r as isWhatsAppUserTarget, s as normalizeWhatsAppTarget, t as isWhatsAppGroupJid } from "./normalize-target-BPVHNsM5.js";
2
+ export { isWhatsAppGroupJid, isWhatsAppUserTarget, normalizeWhatsAppTarget };
@@ -0,0 +1,3 @@
1
+ import { t as resolveWhatsAppRuntimeGroupPolicy } from "./runtime-group-policy-Gp1lQ0at.js";
2
+ import { t as whatsappOutbound } from "./outbound-adapter-BssVnZdz.js";
3
+ export { resolveWhatsAppRuntimeGroupPolicy, whatsappOutbound };