@hanzo/bot 2026.3.8 → 2026.3.10

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 (161) hide show
  1. package/dist/{audio-preflight-D_s-peid.js → audio-preflight-BnfuyvxO.js} +4 -4
  2. package/dist/{audio-preflight-BEc8i-bS.js → audio-preflight-CpAXC_Ct.js} +4 -4
  3. package/dist/{audio-transcription-runner-X1KzI7dF.js → audio-transcription-runner-CAOjjGxN.js} +1 -1
  4. package/dist/{audio-transcription-runner-BePCnZfw.js → audio-transcription-runner-GcMnO6sT.js} +1 -1
  5. package/dist/build-info.json +3 -3
  6. package/dist/bundled/boot-md/handler.js +6 -6
  7. package/dist/bundled/session-memory/handler.js +6 -6
  8. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  9. package/dist/{chrome-B24-8NDM.js → chrome--CFg5C_H.js} +8 -8
  10. package/dist/{chrome-C7OwLtx9.js → chrome-jCt9JCU8.js} +8 -8
  11. package/dist/{cloud-connect-CknfBF39.js → cloud-connect-6kdj8st_.js} +1 -1
  12. package/dist/{deliver-D8dBbzpu.js → deliver-BVtVDxwX.js} +1 -1
  13. package/dist/{deliver-DudaV86i.js → deliver-DmfS4khs.js} +1 -1
  14. package/dist/{deliver-runtime-C76IMU4W.js → deliver-runtime-G0G5orrZ.js} +3 -3
  15. package/dist/{deliver-runtime-qDmQqiF-.js → deliver-runtime-PxJvVUhh.js} +3 -3
  16. package/dist/{deps-send-whatsapp.runtime-Cv_awFtm.js → deps-send-whatsapp.runtime-8bLqjmui.js} +7 -7
  17. package/dist/{deps-send-whatsapp.runtime-Cq-TLsJw.js → deps-send-whatsapp.runtime-CrzuaVhC.js} +7 -7
  18. package/dist/entry.js +15 -8
  19. package/dist/extensionAPI.js +6 -6
  20. package/dist/{image-nUHQF6BX.js → image-BdZcUz8M.js} +1 -1
  21. package/dist/{image-BOybyCis.js → image-DSK1hSSV.js} +1 -1
  22. package/dist/{image-runtime-B5M_-diF.js → image-runtime-ueqmfx1a.js} +3 -3
  23. package/dist/{image-runtime-y4msd5bn.js → image-runtime-xqxW2PQA.js} +3 -3
  24. package/dist/llm-slug-generator.js +6 -6
  25. package/dist/{local-launch-C2RER-G3.js → local-launch-BJpBAIR5.js} +37 -33
  26. package/dist/{pi-embedded-BHXPs-Ix.js → pi-embedded-DBn841N-.js} +24 -24
  27. package/dist/{pi-embedded-DvWHP6Nn.js → pi-embedded-DYc6emwb.js} +24 -24
  28. package/dist/{pi-embedded-helpers-xIXwvwuE.js → pi-embedded-helpers-BtnBVL-4.js} +3 -3
  29. package/dist/{pi-embedded-helpers-Ck1qEeMH.js → pi-embedded-helpers-DLm1Mtr2.js} +3 -3
  30. package/dist/plugin-sdk/accounts-B8qv93DH.js +35 -0
  31. package/dist/plugin-sdk/accounts-D2p8t4UO.js +288 -0
  32. package/dist/plugin-sdk/accounts-D96D1U9M.js +46 -0
  33. package/dist/plugin-sdk/active-listener-Mha1rAbh.js +50 -0
  34. package/dist/plugin-sdk/api-key-rotation-D0aZfxXH.js +181 -0
  35. package/dist/plugin-sdk/audio-preflight-D3y8mHJa.js +69 -0
  36. package/dist/plugin-sdk/audio-transcription-runner-j0mQXKSH.js +2205 -0
  37. package/dist/plugin-sdk/audit-membership-runtime-D-Ni2WDc.js +58 -0
  38. package/dist/plugin-sdk/channel-activity-VpA3MxPb.js +94 -0
  39. package/dist/plugin-sdk/channel-web-BP3vDdim.js +2256 -0
  40. package/dist/plugin-sdk/chrome-5jJIDTj0.js +2447 -0
  41. package/dist/plugin-sdk/commands-registry-BVKCdwN_.js +1125 -0
  42. package/dist/plugin-sdk/config-CudVTZDi.js +18200 -0
  43. package/dist/plugin-sdk/deliver-4NrmrRKu.js +1744 -0
  44. package/dist/plugin-sdk/deliver-runtime-CB4wXMTH.js +32 -0
  45. package/dist/plugin-sdk/deps-send-discord.runtime-Di8ELKED.js +23 -0
  46. package/dist/plugin-sdk/deps-send-imessage.runtime-CWWtApbz.js +22 -0
  47. package/dist/plugin-sdk/deps-send-signal.runtime-C6BGyoIY.js +21 -0
  48. package/dist/plugin-sdk/deps-send-slack.runtime-DgtITBuc.js +19 -0
  49. package/dist/plugin-sdk/deps-send-telegram.runtime-DyY4XRxh.js +24 -0
  50. package/dist/plugin-sdk/deps-send-whatsapp.runtime-LKiQNFcF.js +57 -0
  51. package/dist/plugin-sdk/diagnostic-DCPixRez.js +319 -0
  52. package/dist/plugin-sdk/errors-D5bA02--.js +54 -0
  53. package/dist/plugin-sdk/fetch-guard-n0LVdzZL.js +156 -0
  54. package/dist/plugin-sdk/fs-safe-IQ0H7rVD.js +352 -0
  55. package/dist/plugin-sdk/image-n-R2HcNg.js +2314 -0
  56. package/dist/plugin-sdk/image-ops-BpYDXC6N.js +584 -0
  57. package/dist/plugin-sdk/image-runtime-CbCl82B8.js +25 -0
  58. package/dist/plugin-sdk/index.js +50 -50
  59. package/dist/plugin-sdk/ir-DsMX3GcS.js +1296 -0
  60. package/dist/plugin-sdk/local-roots-DR-lR22p.js +186 -0
  61. package/dist/plugin-sdk/logger-2A0UE34q.js +1163 -0
  62. package/dist/plugin-sdk/login-CxFTtHEi.js +57 -0
  63. package/dist/plugin-sdk/login-qr-BCkrf1Zx.js +320 -0
  64. package/dist/plugin-sdk/manager-ClUgSFkG.js +3943 -0
  65. package/dist/plugin-sdk/manager-runtime-MWzYCRyH.js +15 -0
  66. package/dist/plugin-sdk/outbound-Dqs8L8QW.js +212 -0
  67. package/dist/plugin-sdk/outbound-attachment-CPfpUcdI.js +19 -0
  68. package/dist/plugin-sdk/path-alias-guards-LILr7Hrs.js +43 -0
  69. package/dist/plugin-sdk/paths-CfGmXu9A.js +166 -0
  70. package/dist/plugin-sdk/pi-embedded-helpers-CeC8GbRi.js +9731 -0
  71. package/dist/plugin-sdk/pi-model-discovery-DycOMKYh.js +134 -0
  72. package/dist/plugin-sdk/pi-model-discovery-runtime-C64BYe5F.js +8 -0
  73. package/dist/plugin-sdk/pi-tools.before-tool-call.runtime-C-HNtPSw.js +354 -0
  74. package/dist/plugin-sdk/plugins-2gQWMmUN.js +1205 -0
  75. package/dist/plugin-sdk/proxy-fetch-sX3-xzX1.js +38 -0
  76. package/dist/plugin-sdk/pw-ai-D7FTxM3C.js +1938 -0
  77. package/dist/plugin-sdk/qmd-manager-Da3Jq30m.js +1608 -0
  78. package/dist/plugin-sdk/query-expansion-B5Z0In1U.js +1014 -0
  79. package/dist/plugin-sdk/redact-85H1J7mo.js +319 -0
  80. package/dist/plugin-sdk/reply-DmCyOPxV.js +102224 -0
  81. package/dist/plugin-sdk/resolve-outbound-target-y0Sp7gsM.js +40 -0
  82. package/dist/plugin-sdk/run-with-concurrency-CFRxflYW.js +1994 -0
  83. package/dist/plugin-sdk/runtime-whatsapp-login.runtime-fgm84Rdh.js +10 -0
  84. package/dist/plugin-sdk/runtime-whatsapp-outbound.runtime-DpMuLd_h.js +19 -0
  85. package/dist/plugin-sdk/send-BQvcPd54.js +3135 -0
  86. package/dist/plugin-sdk/send-Bplfz7UW.js +540 -0
  87. package/dist/plugin-sdk/send-C8gdhoLP.js +414 -0
  88. package/dist/plugin-sdk/send-CTOVZqmi.js +2602 -0
  89. package/dist/plugin-sdk/send-Cld7xlxq.js +503 -0
  90. package/dist/plugin-sdk/session-D4k86ARy.js +169 -0
  91. package/dist/plugin-sdk/signal.js +2 -2
  92. package/dist/plugin-sdk/skill-commands-BfHvtJx2.js +353 -0
  93. package/dist/plugin-sdk/skills-BrE5Yb5o.js +1428 -0
  94. package/dist/plugin-sdk/slash-commands.runtime-UpSrdY-a.js +13 -0
  95. package/dist/plugin-sdk/slash-dispatch.runtime-C-Ymizf2.js +52 -0
  96. package/dist/plugin-sdk/slash-skill-commands.runtime-Bb9wo3w0.js +16 -0
  97. package/dist/plugin-sdk/ssrf-CbvrROKN.js +202 -0
  98. package/dist/plugin-sdk/store-8XS_isi_.js +81 -0
  99. package/dist/plugin-sdk/subagent-registry-runtime-Cl3jJKM1.js +52 -0
  100. package/dist/plugin-sdk/tables-BhfDBQ58.js +55 -0
  101. package/dist/plugin-sdk/target-errors-0DW3k-Ae.js +195 -0
  102. package/dist/plugin-sdk/thinking-DE2FCBnv.js +1209 -0
  103. package/dist/plugin-sdk/tokens-C2tJ8uXs.js +52 -0
  104. package/dist/plugin-sdk/tool-images-B1I6LEp7.js +274 -0
  105. package/dist/plugin-sdk/web-BHzDLmns.js +56 -0
  106. package/dist/plugin-sdk/whatsapp-actions-BoAH0BAS.js +80 -0
  107. package/dist/{pw-ai-DweqbnMJ.js → pw-ai-C-Sy12jT.js} +1 -1
  108. package/dist/{pw-ai-DsYmOxCp.js → pw-ai-pJMhS79V.js} +1 -1
  109. package/dist/{run-main-CgFUs81l.js → run-main-JI9-1g4u.js} +2 -2
  110. package/dist/{slash-dispatch.runtime-D28-UnsO.js → slash-dispatch.runtime-DLP2IeNv.js} +6 -6
  111. package/dist/{slash-dispatch.runtime-DzpJjr3K.js → slash-dispatch.runtime-Vp6IDoCc.js} +6 -6
  112. package/dist/{subagent-registry-runtime-a7xfwPB8.js → subagent-registry-runtime-BlAI3eqU.js} +6 -6
  113. package/dist/{subagent-registry-runtime-Bt-LYyrB.js → subagent-registry-runtime-COKZwsHd.js} +6 -6
  114. package/dist/{web-CREcqhe9.js → web-BEuMJbx-.js} +6 -6
  115. package/dist/{web-IBqHOVI2.js → web-BvId86u4.js} +6 -6
  116. package/extensions/acpx/package.json +1 -1
  117. package/extensions/bluebubbles/package.json +1 -1
  118. package/extensions/ci-fix-loop/package.json +1 -1
  119. package/extensions/continuous-learning/package.json +1 -1
  120. package/extensions/copilot-proxy/package.json +1 -1
  121. package/extensions/diagnostics-otel/package.json +1 -1
  122. package/extensions/diffs/package.json +1 -1
  123. package/extensions/discord/package.json +1 -1
  124. package/extensions/feishu/package.json +1 -1
  125. package/extensions/flow/package.json +1 -1
  126. package/extensions/google-antigravity-auth/package.json +1 -1
  127. package/extensions/google-gemini-cli-auth/package.json +1 -1
  128. package/extensions/googlechat/package.json +1 -1
  129. package/extensions/imessage/package.json +1 -1
  130. package/extensions/irc/package.json +1 -1
  131. package/extensions/line/package.json +1 -1
  132. package/extensions/llm-task/package.json +1 -1
  133. package/extensions/lobster/package.json +1 -1
  134. package/extensions/matrix/CHANGELOG.md +10 -0
  135. package/extensions/matrix/package.json +1 -1
  136. package/extensions/mattermost/package.json +1 -1
  137. package/extensions/memory-core/package.json +1 -1
  138. package/extensions/memory-lancedb/package.json +1 -1
  139. package/extensions/minimax-portal-auth/package.json +1 -1
  140. package/extensions/msteams/CHANGELOG.md +10 -0
  141. package/extensions/msteams/package.json +1 -1
  142. package/extensions/nextcloud-talk/package.json +1 -1
  143. package/extensions/nostr/CHANGELOG.md +10 -0
  144. package/extensions/nostr/package.json +1 -1
  145. package/extensions/open-prose/package.json +1 -1
  146. package/extensions/self-improvement/package.json +1 -1
  147. package/extensions/signal/package.json +1 -1
  148. package/extensions/slack/package.json +1 -1
  149. package/extensions/synology-chat/package.json +1 -1
  150. package/extensions/telegram/package.json +1 -1
  151. package/extensions/tlon/package.json +1 -1
  152. package/extensions/twitch/CHANGELOG.md +10 -0
  153. package/extensions/twitch/package.json +1 -1
  154. package/extensions/voice-call/CHANGELOG.md +10 -0
  155. package/extensions/voice-call/package.json +1 -1
  156. package/extensions/whatsapp/package.json +1 -1
  157. package/extensions/zalo/CHANGELOG.md +10 -0
  158. package/extensions/zalo/package.json +1 -1
  159. package/extensions/zalouser/CHANGELOG.md +10 -0
  160. package/extensions/zalouser/package.json +1 -1
  161. package/package.json +2 -1
@@ -0,0 +1,1205 @@
1
+ import { $ as normalizeAgentId, at as DEFAULT_ACCOUNT_ID, l as resolveDefaultAgentId, ot as normalizeAccountId, st as normalizeOptionalAccountId } from "./run-with-concurrency-CFRxflYW.js";
2
+ import { i as resolveWhatsAppAccount, v as resolveAccountEntry, y as createAccountListHelpers } from "./accounts-D2p8t4UO.js";
3
+ import { Ct as normalizeChatChannelId, Dt as requireActivePluginRegistry, Et as getActivePluginRegistryVersion, Jr as normalizeSecretInputString, Wr as hasConfiguredSecretInput, ii as isTruthyEnvValue, qr as normalizeResolvedSecretInputString, vt as CHAT_CHANNEL_ORDER, xt as normalizeAnyChannelId } from "./config-CudVTZDi.js";
4
+ import { S as normalizeE164, a as createSubsystemLogger } from "./logger-2A0UE34q.js";
5
+ import fs from "node:fs";
6
+ import util from "node:util";
7
+
8
+ //#region src/channels/chat-type.ts
9
+ function normalizeChatType(raw) {
10
+ const value = raw?.trim().toLowerCase();
11
+ if (!value) return;
12
+ if (value === "direct" || value === "dm") return "direct";
13
+ if (value === "group") return "group";
14
+ if (value === "channel") return "channel";
15
+ }
16
+
17
+ //#endregion
18
+ //#region src/channels/plugins/account-action-gate.ts
19
+ function createAccountActionGate(params) {
20
+ return (key, defaultValue = true) => {
21
+ const accountValue = params.accountActions?.[key];
22
+ if (accountValue !== void 0) return accountValue;
23
+ const baseValue = params.baseActions?.[key];
24
+ if (baseValue !== void 0) return baseValue;
25
+ return defaultValue;
26
+ };
27
+ }
28
+
29
+ //#endregion
30
+ //#region src/discord/token.ts
31
+ function normalizeDiscordToken(raw, path) {
32
+ const trimmed = normalizeResolvedSecretInputString({
33
+ value: raw,
34
+ path
35
+ });
36
+ if (!trimmed) return;
37
+ return trimmed.replace(/^Bot\s+/i, "");
38
+ }
39
+ function resolveDiscordToken(cfg, opts = {}) {
40
+ const accountId = normalizeAccountId(opts.accountId);
41
+ const discordCfg = cfg?.channels?.discord;
42
+ const resolveAccountCfg = (id) => {
43
+ const accounts = discordCfg?.accounts;
44
+ if (!accounts || typeof accounts !== "object" || Array.isArray(accounts)) return;
45
+ const direct = accounts[id];
46
+ if (direct) return direct;
47
+ const matchKey = Object.keys(accounts).find((key) => normalizeAccountId(key) === id);
48
+ return matchKey ? accounts[matchKey] : void 0;
49
+ };
50
+ const accountCfg = resolveAccountCfg(accountId);
51
+ const hasAccountToken = Boolean(accountCfg && Object.prototype.hasOwnProperty.call(accountCfg, "token"));
52
+ const accountToken = normalizeDiscordToken(accountCfg?.token ?? void 0, `channels.discord.accounts.${accountId}.token`);
53
+ if (accountToken) return {
54
+ token: accountToken,
55
+ source: "config"
56
+ };
57
+ if (hasAccountToken) return {
58
+ token: "",
59
+ source: "none"
60
+ };
61
+ const configToken = normalizeDiscordToken(discordCfg?.token ?? void 0, "channels.discord.token");
62
+ if (configToken) return {
63
+ token: configToken,
64
+ source: "config"
65
+ };
66
+ const envToken = accountId === DEFAULT_ACCOUNT_ID ? normalizeDiscordToken(opts.envToken ?? process.env.DISCORD_BOT_TOKEN, "DISCORD_BOT_TOKEN") : void 0;
67
+ if (envToken) return {
68
+ token: envToken,
69
+ source: "env"
70
+ };
71
+ return {
72
+ token: "",
73
+ source: "none"
74
+ };
75
+ }
76
+
77
+ //#endregion
78
+ //#region src/discord/accounts.ts
79
+ const { listAccountIds: listAccountIds$1, resolveDefaultAccountId: resolveDefaultAccountId$1 } = createAccountListHelpers("discord");
80
+ const listDiscordAccountIds = listAccountIds$1;
81
+ const resolveDefaultDiscordAccountId = resolveDefaultAccountId$1;
82
+ function resolveAccountConfig$2(cfg, accountId) {
83
+ return resolveAccountEntry(cfg.channels?.discord?.accounts, accountId);
84
+ }
85
+ function mergeDiscordAccountConfig$1(cfg, accountId) {
86
+ const { accounts: _ignored, ...base } = cfg.channels?.discord ?? {};
87
+ const account = resolveAccountConfig$2(cfg, accountId) ?? {};
88
+ return {
89
+ ...base,
90
+ ...account
91
+ };
92
+ }
93
+ function createDiscordActionGate(params) {
94
+ const accountId = normalizeAccountId(params.accountId);
95
+ return createAccountActionGate({
96
+ baseActions: params.cfg.channels?.discord?.actions,
97
+ accountActions: resolveAccountConfig$2(params.cfg, accountId)?.actions
98
+ });
99
+ }
100
+ function resolveDiscordAccount(params) {
101
+ const accountId = normalizeAccountId(params.accountId);
102
+ const baseEnabled = params.cfg.channels?.discord?.enabled !== false;
103
+ const merged = mergeDiscordAccountConfig$1(params.cfg, accountId);
104
+ const accountEnabled = merged.enabled !== false;
105
+ const enabled = baseEnabled && accountEnabled;
106
+ const tokenResolution = resolveDiscordToken(params.cfg, { accountId });
107
+ return {
108
+ accountId,
109
+ enabled,
110
+ name: merged.name?.trim() || void 0,
111
+ token: tokenResolution.token,
112
+ tokenSource: tokenResolution.source,
113
+ config: merged
114
+ };
115
+ }
116
+ function listEnabledDiscordAccounts(cfg) {
117
+ return listDiscordAccountIds(cfg).map((accountId) => resolveDiscordAccount({
118
+ cfg,
119
+ accountId
120
+ })).filter((account) => account.enabled);
121
+ }
122
+
123
+ //#endregion
124
+ //#region src/discord/account-inspect.ts
125
+ function resolveDiscordAccountConfig(cfg, accountId) {
126
+ return resolveAccountEntry(cfg.channels?.discord?.accounts, accountId);
127
+ }
128
+ function mergeDiscordAccountConfig(cfg, accountId) {
129
+ const { accounts: _ignored, ...base } = cfg.channels?.discord ?? {};
130
+ const account = resolveDiscordAccountConfig(cfg, accountId) ?? {};
131
+ return {
132
+ ...base,
133
+ ...account
134
+ };
135
+ }
136
+ function inspectDiscordTokenValue(value) {
137
+ const normalized = normalizeSecretInputString(value);
138
+ if (normalized) return {
139
+ token: normalized.replace(/^Bot\s+/i, ""),
140
+ tokenSource: "config",
141
+ tokenStatus: "available"
142
+ };
143
+ if (hasConfiguredSecretInput(value)) return {
144
+ token: "",
145
+ tokenSource: "config",
146
+ tokenStatus: "configured_unavailable"
147
+ };
148
+ return null;
149
+ }
150
+ function inspectDiscordAccount(params) {
151
+ const accountId = normalizeAccountId(params.accountId ?? resolveDefaultDiscordAccountId(params.cfg));
152
+ const merged = mergeDiscordAccountConfig(params.cfg, accountId);
153
+ const enabled = params.cfg.channels?.discord?.enabled !== false && merged.enabled !== false;
154
+ const accountConfig = resolveDiscordAccountConfig(params.cfg, accountId);
155
+ const hasAccountToken = Boolean(accountConfig && Object.prototype.hasOwnProperty.call(accountConfig, "token"));
156
+ const accountToken = inspectDiscordTokenValue(accountConfig?.token);
157
+ if (accountToken) return {
158
+ accountId,
159
+ enabled,
160
+ name: merged.name?.trim() || void 0,
161
+ token: accountToken.token,
162
+ tokenSource: accountToken.tokenSource,
163
+ tokenStatus: accountToken.tokenStatus,
164
+ configured: true,
165
+ config: merged
166
+ };
167
+ if (hasAccountToken) return {
168
+ accountId,
169
+ enabled,
170
+ name: merged.name?.trim() || void 0,
171
+ token: "",
172
+ tokenSource: "none",
173
+ tokenStatus: "missing",
174
+ configured: false,
175
+ config: merged
176
+ };
177
+ const channelToken = inspectDiscordTokenValue(params.cfg.channels?.discord?.token);
178
+ if (channelToken) return {
179
+ accountId,
180
+ enabled,
181
+ name: merged.name?.trim() || void 0,
182
+ token: channelToken.token,
183
+ tokenSource: channelToken.tokenSource,
184
+ tokenStatus: channelToken.tokenStatus,
185
+ configured: true,
186
+ config: merged
187
+ };
188
+ const envToken = accountId === DEFAULT_ACCOUNT_ID ? normalizeSecretInputString(params.envToken ?? process.env.DISCORD_BOT_TOKEN) : void 0;
189
+ if (envToken) return {
190
+ accountId,
191
+ enabled,
192
+ name: merged.name?.trim() || void 0,
193
+ token: envToken.replace(/^Bot\s+/i, ""),
194
+ tokenSource: "env",
195
+ tokenStatus: "available",
196
+ configured: true,
197
+ config: merged
198
+ };
199
+ return {
200
+ accountId,
201
+ enabled,
202
+ name: merged.name?.trim() || void 0,
203
+ token: "",
204
+ tokenSource: "none",
205
+ tokenStatus: "missing",
206
+ configured: false,
207
+ config: merged
208
+ };
209
+ }
210
+
211
+ //#endregion
212
+ //#region src/whatsapp/normalize.ts
213
+ const WHATSAPP_USER_JID_RE = /^(\d+)(?::\d+)?@s\.whatsapp\.net$/i;
214
+ const WHATSAPP_LID_RE = /^(\d+)@lid$/i;
215
+ function stripWhatsAppTargetPrefixes(value) {
216
+ let candidate = value.trim();
217
+ for (;;) {
218
+ const before = candidate;
219
+ candidate = candidate.replace(/^whatsapp:/i, "").trim();
220
+ if (candidate === before) return candidate;
221
+ }
222
+ }
223
+ function isWhatsAppGroupJid(value) {
224
+ const candidate = stripWhatsAppTargetPrefixes(value);
225
+ if (!candidate.toLowerCase().endsWith("@g.us")) return false;
226
+ const localPart = candidate.slice(0, candidate.length - 5);
227
+ if (!localPart || localPart.includes("@")) return false;
228
+ return /^[0-9]+(-[0-9]+)*$/.test(localPart);
229
+ }
230
+ /**
231
+ * Check if value looks like a WhatsApp user target (e.g. "41796666864:0@s.whatsapp.net" or "123@lid").
232
+ */
233
+ function isWhatsAppUserTarget(value) {
234
+ const candidate = stripWhatsAppTargetPrefixes(value);
235
+ return WHATSAPP_USER_JID_RE.test(candidate) || WHATSAPP_LID_RE.test(candidate);
236
+ }
237
+ /**
238
+ * Extract the phone number from a WhatsApp user JID.
239
+ * "41796666864:0@s.whatsapp.net" -> "41796666864"
240
+ * "123456@lid" -> "123456"
241
+ */
242
+ function extractUserJidPhone(jid) {
243
+ const userMatch = jid.match(WHATSAPP_USER_JID_RE);
244
+ if (userMatch) return userMatch[1];
245
+ const lidMatch = jid.match(WHATSAPP_LID_RE);
246
+ if (lidMatch) return lidMatch[1];
247
+ return null;
248
+ }
249
+ function normalizeWhatsAppTarget(value) {
250
+ const candidate = stripWhatsAppTargetPrefixes(value);
251
+ if (!candidate) return null;
252
+ if (isWhatsAppGroupJid(candidate)) return `${candidate.slice(0, candidate.length - 5)}@g.us`;
253
+ if (isWhatsAppUserTarget(candidate)) {
254
+ const phone = extractUserJidPhone(candidate);
255
+ if (!phone) return null;
256
+ const normalized = normalizeE164(phone);
257
+ return normalized.length > 1 ? normalized : null;
258
+ }
259
+ if (candidate.includes("@")) return null;
260
+ const normalized = normalizeE164(candidate);
261
+ return normalized.length > 1 ? normalized : null;
262
+ }
263
+
264
+ //#endregion
265
+ //#region src/slack/token.ts
266
+ function resolveSlackBotToken(raw, path = "channels.slack.botToken") {
267
+ return normalizeResolvedSecretInputString({
268
+ value: raw,
269
+ path
270
+ });
271
+ }
272
+ function resolveSlackAppToken(raw, path = "channels.slack.appToken") {
273
+ return normalizeResolvedSecretInputString({
274
+ value: raw,
275
+ path
276
+ });
277
+ }
278
+ function resolveSlackUserToken(raw, path = "channels.slack.userToken") {
279
+ return normalizeResolvedSecretInputString({
280
+ value: raw,
281
+ path
282
+ });
283
+ }
284
+
285
+ //#endregion
286
+ //#region src/slack/accounts.ts
287
+ const { listAccountIds, resolveDefaultAccountId } = createAccountListHelpers("slack");
288
+ const listSlackAccountIds = listAccountIds;
289
+ const resolveDefaultSlackAccountId = resolveDefaultAccountId;
290
+ function resolveAccountConfig$1(cfg, accountId) {
291
+ return resolveAccountEntry(cfg.channels?.slack?.accounts, accountId);
292
+ }
293
+ function mergeSlackAccountConfig$1(cfg, accountId) {
294
+ const { accounts: _ignored, ...base } = cfg.channels?.slack ?? {};
295
+ const account = resolveAccountConfig$1(cfg, accountId) ?? {};
296
+ return {
297
+ ...base,
298
+ ...account
299
+ };
300
+ }
301
+ function resolveSlackAccount(params) {
302
+ const accountId = normalizeAccountId(params.accountId);
303
+ const baseEnabled = params.cfg.channels?.slack?.enabled !== false;
304
+ const merged = mergeSlackAccountConfig$1(params.cfg, accountId);
305
+ const accountEnabled = merged.enabled !== false;
306
+ const enabled = baseEnabled && accountEnabled;
307
+ const allowEnv = accountId === DEFAULT_ACCOUNT_ID;
308
+ const envBot = allowEnv ? resolveSlackBotToken(process.env.SLACK_BOT_TOKEN) : void 0;
309
+ const envApp = allowEnv ? resolveSlackAppToken(process.env.SLACK_APP_TOKEN) : void 0;
310
+ const envUser = allowEnv ? resolveSlackUserToken(process.env.SLACK_USER_TOKEN) : void 0;
311
+ const configBot = resolveSlackBotToken(merged.botToken, `channels.slack.accounts.${accountId}.botToken`);
312
+ const configApp = resolveSlackAppToken(merged.appToken, `channels.slack.accounts.${accountId}.appToken`);
313
+ const configUser = resolveSlackUserToken(merged.userToken, `channels.slack.accounts.${accountId}.userToken`);
314
+ const botToken = configBot ?? envBot;
315
+ const appToken = configApp ?? envApp;
316
+ const userToken = configUser ?? envUser;
317
+ const botTokenSource = configBot ? "config" : envBot ? "env" : "none";
318
+ const appTokenSource = configApp ? "config" : envApp ? "env" : "none";
319
+ const userTokenSource = configUser ? "config" : envUser ? "env" : "none";
320
+ return {
321
+ accountId,
322
+ enabled,
323
+ name: merged.name?.trim() || void 0,
324
+ botToken,
325
+ appToken,
326
+ userToken,
327
+ botTokenSource,
328
+ appTokenSource,
329
+ userTokenSource,
330
+ config: merged,
331
+ groupPolicy: merged.groupPolicy,
332
+ textChunkLimit: merged.textChunkLimit,
333
+ mediaMaxMb: merged.mediaMaxMb,
334
+ reactionNotifications: merged.reactionNotifications,
335
+ reactionAllowlist: merged.reactionAllowlist,
336
+ replyToMode: merged.replyToMode,
337
+ replyToModeByChatType: merged.replyToModeByChatType,
338
+ actions: merged.actions,
339
+ slashCommand: merged.slashCommand,
340
+ dm: merged.dm,
341
+ channels: merged.channels
342
+ };
343
+ }
344
+ function listEnabledSlackAccounts(cfg) {
345
+ return listSlackAccountIds(cfg).map((accountId) => resolveSlackAccount({
346
+ cfg,
347
+ accountId
348
+ })).filter((account) => account.enabled);
349
+ }
350
+ function resolveSlackReplyToMode(account, chatType) {
351
+ const normalized = normalizeChatType(chatType ?? void 0);
352
+ if (normalized && account.replyToModeByChatType?.[normalized] !== void 0) return account.replyToModeByChatType[normalized] ?? "off";
353
+ if (normalized === "direct" && account.dm?.replyToMode !== void 0) return account.dm.replyToMode;
354
+ return account.replyToMode ?? "off";
355
+ }
356
+
357
+ //#endregion
358
+ //#region src/slack/account-inspect.ts
359
+ function resolveSlackAccountConfig(cfg, accountId) {
360
+ return resolveAccountEntry(cfg.channels?.slack?.accounts, accountId);
361
+ }
362
+ function mergeSlackAccountConfig(cfg, accountId) {
363
+ const { accounts: _ignored, ...base } = cfg.channels?.slack ?? {};
364
+ const account = resolveSlackAccountConfig(cfg, accountId) ?? {};
365
+ return {
366
+ ...base,
367
+ ...account
368
+ };
369
+ }
370
+ function inspectSlackToken(value) {
371
+ const token = normalizeSecretInputString(value);
372
+ if (token) return {
373
+ token,
374
+ source: "config",
375
+ status: "available"
376
+ };
377
+ if (hasConfiguredSecretInput(value)) return {
378
+ source: "config",
379
+ status: "configured_unavailable"
380
+ };
381
+ return {
382
+ source: "none",
383
+ status: "missing"
384
+ };
385
+ }
386
+ function inspectSlackAccount(params) {
387
+ const accountId = normalizeAccountId(params.accountId ?? resolveDefaultSlackAccountId(params.cfg));
388
+ const merged = mergeSlackAccountConfig(params.cfg, accountId);
389
+ const enabled = params.cfg.channels?.slack?.enabled !== false && merged.enabled !== false;
390
+ const allowEnv = accountId === DEFAULT_ACCOUNT_ID;
391
+ const mode = merged.mode ?? "socket";
392
+ const isHttpMode = mode === "http";
393
+ const configBot = inspectSlackToken(merged.botToken);
394
+ const configApp = inspectSlackToken(merged.appToken);
395
+ const configSigningSecret = inspectSlackToken(merged.signingSecret);
396
+ const configUser = inspectSlackToken(merged.userToken);
397
+ const envBot = allowEnv ? normalizeSecretInputString(params.envBotToken ?? process.env.SLACK_BOT_TOKEN) : void 0;
398
+ const envApp = allowEnv ? normalizeSecretInputString(params.envAppToken ?? process.env.SLACK_APP_TOKEN) : void 0;
399
+ const envUser = allowEnv ? normalizeSecretInputString(params.envUserToken ?? process.env.SLACK_USER_TOKEN) : void 0;
400
+ const botToken = configBot.token ?? envBot;
401
+ const appToken = configApp.token ?? envApp;
402
+ const signingSecret = configSigningSecret.token;
403
+ const userToken = configUser.token ?? envUser;
404
+ const botTokenSource = configBot.token ? "config" : configBot.status === "configured_unavailable" ? "config" : envBot ? "env" : "none";
405
+ const appTokenSource = configApp.token ? "config" : configApp.status === "configured_unavailable" ? "config" : envApp ? "env" : "none";
406
+ const signingSecretSource = configSigningSecret.token ? "config" : configSigningSecret.status === "configured_unavailable" ? "config" : "none";
407
+ const userTokenSource = configUser.token ? "config" : configUser.status === "configured_unavailable" ? "config" : envUser ? "env" : "none";
408
+ return {
409
+ accountId,
410
+ enabled,
411
+ name: merged.name?.trim() || void 0,
412
+ mode,
413
+ botToken,
414
+ appToken,
415
+ ...isHttpMode ? { signingSecret } : {},
416
+ userToken,
417
+ botTokenSource,
418
+ appTokenSource,
419
+ ...isHttpMode ? { signingSecretSource } : {},
420
+ userTokenSource,
421
+ botTokenStatus: configBot.token ? "available" : configBot.status === "configured_unavailable" ? "configured_unavailable" : envBot ? "available" : "missing",
422
+ appTokenStatus: configApp.token ? "available" : configApp.status === "configured_unavailable" ? "configured_unavailable" : envApp ? "available" : "missing",
423
+ ...isHttpMode ? { signingSecretStatus: configSigningSecret.token ? "available" : configSigningSecret.status === "configured_unavailable" ? "configured_unavailable" : "missing" } : {},
424
+ userTokenStatus: configUser.token ? "available" : configUser.status === "configured_unavailable" ? "configured_unavailable" : envUser ? "available" : "missing",
425
+ configured: isHttpMode ? (configBot.status !== "missing" || Boolean(envBot)) && configSigningSecret.status !== "missing" : (configBot.status !== "missing" || Boolean(envBot)) && (configApp.status !== "missing" || Boolean(envApp)),
426
+ config: merged,
427
+ groupPolicy: merged.groupPolicy,
428
+ textChunkLimit: merged.textChunkLimit,
429
+ mediaMaxMb: merged.mediaMaxMb,
430
+ reactionNotifications: merged.reactionNotifications,
431
+ reactionAllowlist: merged.reactionAllowlist,
432
+ replyToMode: merged.replyToMode,
433
+ replyToModeByChatType: merged.replyToModeByChatType,
434
+ actions: merged.actions,
435
+ slashCommand: merged.slashCommand,
436
+ dm: merged.dm,
437
+ channels: merged.channels
438
+ };
439
+ }
440
+
441
+ //#endregion
442
+ //#region src/plugin-sdk/account-resolution.ts
443
+ function resolveAccountWithDefaultFallback(params) {
444
+ const hasExplicitAccountId = Boolean(params.accountId?.trim());
445
+ const normalizedAccountId = params.normalizeAccountId(params.accountId);
446
+ const primary = params.resolvePrimary(normalizedAccountId);
447
+ if (hasExplicitAccountId || params.hasCredential(primary)) return primary;
448
+ const fallbackId = params.resolveDefaultAccountId();
449
+ if (fallbackId === normalizedAccountId) return primary;
450
+ const fallback = params.resolvePrimary(fallbackId);
451
+ if (!params.hasCredential(fallback)) return primary;
452
+ return fallback;
453
+ }
454
+ function listConfiguredAccountIds$1(params) {
455
+ if (!params.accounts) return [];
456
+ const ids = /* @__PURE__ */ new Set();
457
+ for (const key of Object.keys(params.accounts)) {
458
+ if (!key) continue;
459
+ ids.add(params.normalizeAccountId(key));
460
+ }
461
+ return [...ids];
462
+ }
463
+
464
+ //#endregion
465
+ //#region src/config/bindings.ts
466
+ function normalizeBindingType(binding) {
467
+ return binding.type === "acp" ? "acp" : "route";
468
+ }
469
+ function isRouteBinding(binding) {
470
+ return normalizeBindingType(binding) === "route";
471
+ }
472
+ function isAcpBinding(binding) {
473
+ return normalizeBindingType(binding) === "acp";
474
+ }
475
+ function listConfiguredBindings(cfg) {
476
+ return Array.isArray(cfg.bindings) ? cfg.bindings : [];
477
+ }
478
+ function listRouteBindings(cfg) {
479
+ return listConfiguredBindings(cfg).filter(isRouteBinding);
480
+ }
481
+ function listAcpBindings(cfg) {
482
+ return listConfiguredBindings(cfg).filter(isAcpBinding);
483
+ }
484
+
485
+ //#endregion
486
+ //#region src/routing/bindings.ts
487
+ function normalizeBindingChannelId(raw) {
488
+ const normalized = normalizeChatChannelId(raw);
489
+ if (normalized) return normalized;
490
+ return (raw ?? "").trim().toLowerCase() || null;
491
+ }
492
+ function listBindings(cfg) {
493
+ return listRouteBindings(cfg);
494
+ }
495
+ function resolveNormalizedBindingMatch(binding) {
496
+ if (!binding || typeof binding !== "object") return null;
497
+ const match = binding.match;
498
+ if (!match || typeof match !== "object") return null;
499
+ const channelId = normalizeBindingChannelId(match.channel);
500
+ if (!channelId) return null;
501
+ const accountId = typeof match.accountId === "string" ? match.accountId.trim() : "";
502
+ if (!accountId || accountId === "*") return null;
503
+ return {
504
+ agentId: normalizeAgentId(binding.agentId),
505
+ accountId: normalizeAccountId(accountId),
506
+ channelId
507
+ };
508
+ }
509
+ function listBoundAccountIds(cfg, channelId) {
510
+ const normalizedChannel = normalizeBindingChannelId(channelId);
511
+ if (!normalizedChannel) return [];
512
+ const ids = /* @__PURE__ */ new Set();
513
+ for (const binding of listBindings(cfg)) {
514
+ const resolved = resolveNormalizedBindingMatch(binding);
515
+ if (!resolved || resolved.channelId !== normalizedChannel) continue;
516
+ ids.add(resolved.accountId);
517
+ }
518
+ return Array.from(ids).toSorted((a, b) => a.localeCompare(b));
519
+ }
520
+ function resolveDefaultAgentBoundAccountId(cfg, channelId) {
521
+ const normalizedChannel = normalizeBindingChannelId(channelId);
522
+ if (!normalizedChannel) return null;
523
+ const defaultAgentId = normalizeAgentId(resolveDefaultAgentId(cfg));
524
+ for (const binding of listBindings(cfg)) {
525
+ const resolved = resolveNormalizedBindingMatch(binding);
526
+ if (!resolved || resolved.channelId !== normalizedChannel || resolved.agentId !== defaultAgentId) continue;
527
+ return resolved.accountId;
528
+ }
529
+ return null;
530
+ }
531
+ function buildChannelAccountBindings(cfg) {
532
+ const map = /* @__PURE__ */ new Map();
533
+ for (const binding of listBindings(cfg)) {
534
+ const resolved = resolveNormalizedBindingMatch(binding);
535
+ if (!resolved) continue;
536
+ const byAgent = map.get(resolved.channelId) ?? /* @__PURE__ */ new Map();
537
+ const list = byAgent.get(resolved.agentId) ?? [];
538
+ if (!list.includes(resolved.accountId)) list.push(resolved.accountId);
539
+ byAgent.set(resolved.agentId, list);
540
+ map.set(resolved.channelId, byAgent);
541
+ }
542
+ return map;
543
+ }
544
+
545
+ //#endregion
546
+ //#region src/routing/default-account-warnings.ts
547
+ function formatChannelDefaultAccountPath(channelKey) {
548
+ return `channels.${channelKey}.defaultAccount`;
549
+ }
550
+ function formatChannelAccountsDefaultPath(channelKey) {
551
+ return `channels.${channelKey}.accounts.default`;
552
+ }
553
+ function formatSetExplicitDefaultInstruction(channelKey) {
554
+ return `Set ${formatChannelDefaultAccountPath(channelKey)} or add ${formatChannelAccountsDefaultPath(channelKey)}`;
555
+ }
556
+
557
+ //#endregion
558
+ //#region src/telegram/token.ts
559
+ function resolveTelegramToken(cfg, opts = {}) {
560
+ const accountId = normalizeAccountId(opts.accountId);
561
+ const telegramCfg = cfg?.channels?.telegram;
562
+ const resolveAccountCfg = (id) => {
563
+ const accounts = telegramCfg?.accounts;
564
+ if (!accounts || typeof accounts !== "object" || Array.isArray(accounts)) return;
565
+ const direct = accounts[id];
566
+ if (direct) return direct;
567
+ const matchKey = Object.keys(accounts).find((key) => normalizeAccountId(key) === id);
568
+ return matchKey ? accounts[matchKey] : void 0;
569
+ };
570
+ const accountCfg = resolveAccountCfg(accountId !== DEFAULT_ACCOUNT_ID ? accountId : DEFAULT_ACCOUNT_ID);
571
+ const accountTokenFile = accountCfg?.tokenFile?.trim();
572
+ if (accountTokenFile) {
573
+ if (!fs.existsSync(accountTokenFile)) {
574
+ opts.logMissingFile?.(`channels.telegram.accounts.${accountId}.tokenFile not found: ${accountTokenFile}`);
575
+ return {
576
+ token: "",
577
+ source: "none"
578
+ };
579
+ }
580
+ try {
581
+ const token = fs.readFileSync(accountTokenFile, "utf-8").trim();
582
+ if (token) return {
583
+ token,
584
+ source: "tokenFile"
585
+ };
586
+ } catch (err) {
587
+ opts.logMissingFile?.(`channels.telegram.accounts.${accountId}.tokenFile read failed: ${String(err)}`);
588
+ return {
589
+ token: "",
590
+ source: "none"
591
+ };
592
+ }
593
+ return {
594
+ token: "",
595
+ source: "none"
596
+ };
597
+ }
598
+ const accountToken = normalizeResolvedSecretInputString({
599
+ value: accountCfg?.botToken,
600
+ path: `channels.telegram.accounts.${accountId}.botToken`
601
+ });
602
+ if (accountToken) return {
603
+ token: accountToken,
604
+ source: "config"
605
+ };
606
+ const allowEnv = accountId === DEFAULT_ACCOUNT_ID;
607
+ const tokenFile = telegramCfg?.tokenFile?.trim();
608
+ if (tokenFile) {
609
+ if (!fs.existsSync(tokenFile)) {
610
+ opts.logMissingFile?.(`channels.telegram.tokenFile not found: ${tokenFile}`);
611
+ return {
612
+ token: "",
613
+ source: "none"
614
+ };
615
+ }
616
+ try {
617
+ const token = fs.readFileSync(tokenFile, "utf-8").trim();
618
+ if (token) return {
619
+ token,
620
+ source: "tokenFile"
621
+ };
622
+ } catch (err) {
623
+ opts.logMissingFile?.(`channels.telegram.tokenFile read failed: ${String(err)}`);
624
+ return {
625
+ token: "",
626
+ source: "none"
627
+ };
628
+ }
629
+ }
630
+ const configToken = normalizeResolvedSecretInputString({
631
+ value: telegramCfg?.botToken,
632
+ path: "channels.telegram.botToken"
633
+ });
634
+ if (configToken) return {
635
+ token: configToken,
636
+ source: "config"
637
+ };
638
+ const envToken = allowEnv ? (opts.envToken ?? process.env.TELEGRAM_BOT_TOKEN)?.trim() : "";
639
+ if (envToken) return {
640
+ token: envToken,
641
+ source: "env"
642
+ };
643
+ return {
644
+ token: "",
645
+ source: "none"
646
+ };
647
+ }
648
+
649
+ //#endregion
650
+ //#region src/telegram/accounts.ts
651
+ const log = createSubsystemLogger("telegram/accounts");
652
+ function formatDebugArg(value) {
653
+ if (typeof value === "string") return value;
654
+ if (value instanceof Error) return value.stack ?? value.message;
655
+ return util.inspect(value, {
656
+ colors: false,
657
+ depth: null,
658
+ compact: true,
659
+ breakLength: Infinity
660
+ });
661
+ }
662
+ const debugAccounts = (...args) => {
663
+ if (isTruthyEnvValue(process.env.OPENCLAW_DEBUG_TELEGRAM_ACCOUNTS)) {
664
+ const parts = args.map((arg) => formatDebugArg(arg));
665
+ log.warn(parts.join(" ").trim());
666
+ }
667
+ };
668
+ function listConfiguredAccountIds(cfg) {
669
+ return listConfiguredAccountIds$1({
670
+ accounts: cfg.channels?.telegram?.accounts,
671
+ normalizeAccountId
672
+ });
673
+ }
674
+ function listTelegramAccountIds(cfg) {
675
+ const ids = Array.from(new Set([...listConfiguredAccountIds(cfg), ...listBoundAccountIds(cfg, "telegram")]));
676
+ debugAccounts("listTelegramAccountIds", ids);
677
+ if (ids.length === 0) return [DEFAULT_ACCOUNT_ID];
678
+ return ids.toSorted((a, b) => a.localeCompare(b));
679
+ }
680
+ let emittedMissingDefaultWarn = false;
681
+ function resolveDefaultTelegramAccountId(cfg) {
682
+ const boundDefault = resolveDefaultAgentBoundAccountId(cfg, "telegram");
683
+ if (boundDefault) return boundDefault;
684
+ const preferred = normalizeOptionalAccountId(cfg.channels?.telegram?.defaultAccount);
685
+ if (preferred && listTelegramAccountIds(cfg).some((accountId) => normalizeAccountId(accountId) === preferred)) return preferred;
686
+ const ids = listTelegramAccountIds(cfg);
687
+ if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID;
688
+ if (ids.length > 1 && !emittedMissingDefaultWarn) {
689
+ emittedMissingDefaultWarn = true;
690
+ log.warn(`channels.telegram: accounts.default is missing; falling back to "${ids[0]}". ${formatSetExplicitDefaultInstruction("telegram")} to avoid routing surprises in multi-account setups.`);
691
+ }
692
+ return ids[0] ?? DEFAULT_ACCOUNT_ID;
693
+ }
694
+ function resolveAccountConfig(cfg, accountId) {
695
+ const normalized = normalizeAccountId(accountId);
696
+ return resolveAccountEntry(cfg.channels?.telegram?.accounts, normalized);
697
+ }
698
+ function mergeTelegramAccountConfig$1(cfg, accountId) {
699
+ const { accounts: _ignored, defaultAccount: _ignoredDefaultAccount, groups: channelGroups, ...base } = cfg.channels?.telegram ?? {};
700
+ const account = resolveAccountConfig(cfg, accountId) ?? {};
701
+ const isMultiAccount = Object.keys(cfg.channels?.telegram?.accounts ?? {}).length > 1;
702
+ const groups = account.groups ?? (isMultiAccount ? void 0 : channelGroups);
703
+ return {
704
+ ...base,
705
+ ...account,
706
+ groups
707
+ };
708
+ }
709
+ function createTelegramActionGate(params) {
710
+ const accountId = normalizeAccountId(params.accountId);
711
+ return createAccountActionGate({
712
+ baseActions: params.cfg.channels?.telegram?.actions,
713
+ accountActions: resolveAccountConfig(params.cfg, accountId)?.actions
714
+ });
715
+ }
716
+ function resolveTelegramPollActionGateState(isActionEnabled) {
717
+ const sendMessageEnabled = isActionEnabled("sendMessage");
718
+ const pollEnabled = isActionEnabled("poll");
719
+ return {
720
+ sendMessageEnabled,
721
+ pollEnabled,
722
+ enabled: sendMessageEnabled && pollEnabled
723
+ };
724
+ }
725
+ function resolveTelegramAccount(params) {
726
+ const baseEnabled = params.cfg.channels?.telegram?.enabled !== false;
727
+ const resolve = (accountId) => {
728
+ const merged = mergeTelegramAccountConfig$1(params.cfg, accountId);
729
+ const accountEnabled = merged.enabled !== false;
730
+ const enabled = baseEnabled && accountEnabled;
731
+ const tokenResolution = resolveTelegramToken(params.cfg, { accountId });
732
+ debugAccounts("resolve", {
733
+ accountId,
734
+ enabled,
735
+ tokenSource: tokenResolution.source
736
+ });
737
+ return {
738
+ accountId,
739
+ enabled,
740
+ name: merged.name?.trim() || void 0,
741
+ token: tokenResolution.token,
742
+ tokenSource: tokenResolution.source,
743
+ config: merged
744
+ };
745
+ };
746
+ return resolveAccountWithDefaultFallback({
747
+ accountId: params.accountId,
748
+ normalizeAccountId,
749
+ resolvePrimary: resolve,
750
+ hasCredential: (account) => account.tokenSource !== "none",
751
+ resolveDefaultAccountId: () => resolveDefaultTelegramAccountId(params.cfg)
752
+ });
753
+ }
754
+ function listEnabledTelegramAccounts(cfg) {
755
+ return listTelegramAccountIds(cfg).map((accountId) => resolveTelegramAccount({
756
+ cfg,
757
+ accountId
758
+ })).filter((account) => account.enabled);
759
+ }
760
+
761
+ //#endregion
762
+ //#region src/telegram/account-inspect.ts
763
+ function resolveTelegramAccountConfig(cfg, accountId) {
764
+ const normalized = normalizeAccountId(accountId);
765
+ return resolveAccountEntry(cfg.channels?.telegram?.accounts, normalized);
766
+ }
767
+ function mergeTelegramAccountConfig(cfg, accountId) {
768
+ const { accounts: _ignored, defaultAccount: _ignoredDefaultAccount, groups: channelGroups, ...base } = cfg.channels?.telegram ?? {};
769
+ const account = resolveTelegramAccountConfig(cfg, accountId) ?? {};
770
+ const isMultiAccount = Object.keys(cfg.channels?.telegram?.accounts ?? {}).length > 1;
771
+ const groups = account.groups ?? (isMultiAccount ? void 0 : channelGroups);
772
+ return {
773
+ ...base,
774
+ ...account,
775
+ groups
776
+ };
777
+ }
778
+ function inspectTokenFile(pathValue) {
779
+ const tokenFile = typeof pathValue === "string" ? pathValue.trim() : "";
780
+ if (!tokenFile) return null;
781
+ if (!fs.existsSync(tokenFile)) return {
782
+ token: "",
783
+ tokenSource: "tokenFile",
784
+ tokenStatus: "configured_unavailable"
785
+ };
786
+ try {
787
+ const token = fs.readFileSync(tokenFile, "utf-8").trim();
788
+ return {
789
+ token,
790
+ tokenSource: "tokenFile",
791
+ tokenStatus: token ? "available" : "configured_unavailable"
792
+ };
793
+ } catch {
794
+ return {
795
+ token: "",
796
+ tokenSource: "tokenFile",
797
+ tokenStatus: "configured_unavailable"
798
+ };
799
+ }
800
+ }
801
+ function inspectTokenValue(value) {
802
+ const token = normalizeSecretInputString(value);
803
+ if (token) return {
804
+ token,
805
+ tokenSource: "config",
806
+ tokenStatus: "available"
807
+ };
808
+ if (hasConfiguredSecretInput(value)) return {
809
+ token: "",
810
+ tokenSource: "config",
811
+ tokenStatus: "configured_unavailable"
812
+ };
813
+ return null;
814
+ }
815
+ function inspectTelegramAccountPrimary(params) {
816
+ const accountId = normalizeAccountId(params.accountId);
817
+ const merged = mergeTelegramAccountConfig(params.cfg, accountId);
818
+ const enabled = params.cfg.channels?.telegram?.enabled !== false && merged.enabled !== false;
819
+ const accountConfig = resolveTelegramAccountConfig(params.cfg, accountId);
820
+ const accountTokenFile = inspectTokenFile(accountConfig?.tokenFile);
821
+ if (accountTokenFile) return {
822
+ accountId,
823
+ enabled,
824
+ name: merged.name?.trim() || void 0,
825
+ token: accountTokenFile.token,
826
+ tokenSource: accountTokenFile.tokenSource,
827
+ tokenStatus: accountTokenFile.tokenStatus,
828
+ configured: accountTokenFile.tokenStatus !== "missing",
829
+ config: merged
830
+ };
831
+ const accountToken = inspectTokenValue(accountConfig?.botToken);
832
+ if (accountToken) return {
833
+ accountId,
834
+ enabled,
835
+ name: merged.name?.trim() || void 0,
836
+ token: accountToken.token,
837
+ tokenSource: accountToken.tokenSource,
838
+ tokenStatus: accountToken.tokenStatus,
839
+ configured: accountToken.tokenStatus !== "missing",
840
+ config: merged
841
+ };
842
+ const channelTokenFile = inspectTokenFile(params.cfg.channels?.telegram?.tokenFile);
843
+ if (channelTokenFile) return {
844
+ accountId,
845
+ enabled,
846
+ name: merged.name?.trim() || void 0,
847
+ token: channelTokenFile.token,
848
+ tokenSource: channelTokenFile.tokenSource,
849
+ tokenStatus: channelTokenFile.tokenStatus,
850
+ configured: channelTokenFile.tokenStatus !== "missing",
851
+ config: merged
852
+ };
853
+ const channelToken = inspectTokenValue(params.cfg.channels?.telegram?.botToken);
854
+ if (channelToken) return {
855
+ accountId,
856
+ enabled,
857
+ name: merged.name?.trim() || void 0,
858
+ token: channelToken.token,
859
+ tokenSource: channelToken.tokenSource,
860
+ tokenStatus: channelToken.tokenStatus,
861
+ configured: channelToken.tokenStatus !== "missing",
862
+ config: merged
863
+ };
864
+ const envToken = accountId === DEFAULT_ACCOUNT_ID ? (params.envToken ?? process.env.TELEGRAM_BOT_TOKEN)?.trim() : "";
865
+ if (envToken) return {
866
+ accountId,
867
+ enabled,
868
+ name: merged.name?.trim() || void 0,
869
+ token: envToken,
870
+ tokenSource: "env",
871
+ tokenStatus: "available",
872
+ configured: true,
873
+ config: merged
874
+ };
875
+ return {
876
+ accountId,
877
+ enabled,
878
+ name: merged.name?.trim() || void 0,
879
+ token: "",
880
+ tokenSource: "none",
881
+ tokenStatus: "missing",
882
+ configured: false,
883
+ config: merged
884
+ };
885
+ }
886
+ function inspectTelegramAccount(params) {
887
+ return resolveAccountWithDefaultFallback({
888
+ accountId: params.accountId,
889
+ normalizeAccountId,
890
+ resolvePrimary: (accountId) => inspectTelegramAccountPrimary({
891
+ cfg: params.cfg,
892
+ accountId,
893
+ envToken: params.envToken
894
+ }),
895
+ hasCredential: (account) => account.tokenSource !== "none",
896
+ resolveDefaultAccountId: () => resolveDefaultTelegramAccountId(params.cfg)
897
+ });
898
+ }
899
+
900
+ //#endregion
901
+ //#region src/channels/targets.ts
902
+ function normalizeTargetId(kind, id) {
903
+ return `${kind}:${id}`.toLowerCase();
904
+ }
905
+ function buildMessagingTarget(kind, id, raw) {
906
+ return {
907
+ kind,
908
+ id,
909
+ raw,
910
+ normalized: normalizeTargetId(kind, id)
911
+ };
912
+ }
913
+ function ensureTargetId(params) {
914
+ if (!params.pattern.test(params.candidate)) throw new Error(params.errorMessage);
915
+ return params.candidate;
916
+ }
917
+ function parseTargetMention(params) {
918
+ const match = params.raw.match(params.mentionPattern);
919
+ if (!match?.[1]) return;
920
+ return buildMessagingTarget(params.kind, match[1], params.raw);
921
+ }
922
+ function parseTargetPrefix(params) {
923
+ if (!params.raw.startsWith(params.prefix)) return;
924
+ const id = params.raw.slice(params.prefix.length).trim();
925
+ return id ? buildMessagingTarget(params.kind, id, params.raw) : void 0;
926
+ }
927
+ function parseTargetPrefixes(params) {
928
+ for (const entry of params.prefixes) {
929
+ const parsed = parseTargetPrefix({
930
+ raw: params.raw,
931
+ prefix: entry.prefix,
932
+ kind: entry.kind
933
+ });
934
+ if (parsed) return parsed;
935
+ }
936
+ }
937
+ function parseAtUserTarget(params) {
938
+ if (!params.raw.startsWith("@")) return;
939
+ return buildMessagingTarget("user", ensureTargetId({
940
+ candidate: params.raw.slice(1).trim(),
941
+ pattern: params.pattern,
942
+ errorMessage: params.errorMessage
943
+ }), params.raw);
944
+ }
945
+ function parseMentionPrefixOrAtUserTarget(params) {
946
+ const mentionTarget = parseTargetMention({
947
+ raw: params.raw,
948
+ mentionPattern: params.mentionPattern,
949
+ kind: "user"
950
+ });
951
+ if (mentionTarget) return mentionTarget;
952
+ const prefixedTarget = parseTargetPrefixes({
953
+ raw: params.raw,
954
+ prefixes: params.prefixes
955
+ });
956
+ if (prefixedTarget) return prefixedTarget;
957
+ return parseAtUserTarget({
958
+ raw: params.raw,
959
+ pattern: params.atUserPattern,
960
+ errorMessage: params.atUserErrorMessage
961
+ });
962
+ }
963
+ function requireTargetKind(params) {
964
+ const kindLabel = params.kind;
965
+ if (!params.target) throw new Error(`${params.platform} ${kindLabel} id is required.`);
966
+ if (params.target.kind !== params.kind) throw new Error(`${params.platform} ${kindLabel} id is required (use ${kindLabel}:<id>).`);
967
+ return params.target.id;
968
+ }
969
+
970
+ //#endregion
971
+ //#region src/slack/targets.ts
972
+ function parseSlackTarget(raw, options = {}) {
973
+ const trimmed = raw.trim();
974
+ if (!trimmed) return;
975
+ const userTarget = parseMentionPrefixOrAtUserTarget({
976
+ raw: trimmed,
977
+ mentionPattern: /^<@([A-Z0-9]+)>$/i,
978
+ prefixes: [
979
+ {
980
+ prefix: "user:",
981
+ kind: "user"
982
+ },
983
+ {
984
+ prefix: "channel:",
985
+ kind: "channel"
986
+ },
987
+ {
988
+ prefix: "slack:",
989
+ kind: "user"
990
+ }
991
+ ],
992
+ atUserPattern: /^[A-Z0-9]+$/i,
993
+ atUserErrorMessage: "Slack DMs require a user id (use user:<id> or <@id>)"
994
+ });
995
+ if (userTarget) return userTarget;
996
+ if (trimmed.startsWith("#")) return buildMessagingTarget("channel", ensureTargetId({
997
+ candidate: trimmed.slice(1).trim(),
998
+ pattern: /^[A-Z0-9]+$/i,
999
+ errorMessage: "Slack channels require a channel id (use channel:<id>)"
1000
+ }), trimmed);
1001
+ if (options.defaultKind) return buildMessagingTarget(options.defaultKind, trimmed, trimmed);
1002
+ return buildMessagingTarget("channel", trimmed, trimmed);
1003
+ }
1004
+ function resolveSlackChannelId(raw) {
1005
+ return requireTargetKind({
1006
+ platform: "Slack",
1007
+ target: parseSlackTarget(raw, { defaultKind: "channel" }),
1008
+ kind: "channel"
1009
+ });
1010
+ }
1011
+
1012
+ //#endregion
1013
+ //#region src/channels/plugins/normalize/slack.ts
1014
+ function normalizeSlackMessagingTarget(raw) {
1015
+ return parseSlackTarget(raw, { defaultKind: "channel" })?.normalized;
1016
+ }
1017
+ function looksLikeSlackTargetId(raw) {
1018
+ const trimmed = raw.trim();
1019
+ if (!trimmed) return false;
1020
+ if (/^<@([A-Z0-9]+)>$/i.test(trimmed)) return true;
1021
+ if (/^(user|channel):/i.test(trimmed)) return true;
1022
+ if (/^slack:/i.test(trimmed)) return true;
1023
+ if (/^[@#]/.test(trimmed)) return true;
1024
+ return /^[CUWGD][A-Z0-9]{8,}$/i.test(trimmed);
1025
+ }
1026
+
1027
+ //#endregion
1028
+ //#region src/channels/plugins/directory-config.ts
1029
+ function addAllowFromAndDmsIds(ids, allowFrom, dms) {
1030
+ for (const entry of allowFrom ?? []) {
1031
+ const raw = String(entry).trim();
1032
+ if (!raw || raw === "*") continue;
1033
+ ids.add(raw);
1034
+ }
1035
+ addTrimmedEntries(ids, Object.keys(dms ?? {}));
1036
+ }
1037
+ function addTrimmedId(ids, value) {
1038
+ const trimmed = String(value).trim();
1039
+ if (trimmed) ids.add(trimmed);
1040
+ }
1041
+ function addTrimmedEntries(ids, values) {
1042
+ for (const value of values) addTrimmedId(ids, value);
1043
+ }
1044
+ function normalizeTrimmedSet(ids, normalize) {
1045
+ return Array.from(ids).map((raw) => raw.trim()).filter(Boolean).map((raw) => normalize(raw)).filter((id) => Boolean(id));
1046
+ }
1047
+ function resolveDirectoryQuery(query) {
1048
+ return query?.trim().toLowerCase() || "";
1049
+ }
1050
+ function resolveDirectoryLimit(limit) {
1051
+ return typeof limit === "number" && limit > 0 ? limit : void 0;
1052
+ }
1053
+ function applyDirectoryQueryAndLimit(ids, params) {
1054
+ const q = resolveDirectoryQuery(params.query);
1055
+ const limit = resolveDirectoryLimit(params.limit);
1056
+ const filtered = ids.filter((id) => q ? id.toLowerCase().includes(q) : true);
1057
+ return typeof limit === "number" ? filtered.slice(0, limit) : filtered;
1058
+ }
1059
+ function toDirectoryEntries(kind, ids) {
1060
+ return ids.map((id) => ({
1061
+ kind,
1062
+ id
1063
+ }));
1064
+ }
1065
+ async function listSlackDirectoryPeersFromConfig(params) {
1066
+ const account = inspectSlackAccount({
1067
+ cfg: params.cfg,
1068
+ accountId: params.accountId
1069
+ });
1070
+ const ids = /* @__PURE__ */ new Set();
1071
+ addAllowFromAndDmsIds(ids, account.config.allowFrom ?? account.dm?.allowFrom, account.config.dms);
1072
+ for (const channel of Object.values(account.config.channels ?? {})) addTrimmedEntries(ids, channel.users ?? []);
1073
+ return toDirectoryEntries("user", applyDirectoryQueryAndLimit(normalizeTrimmedSet(ids, (raw) => {
1074
+ const normalizedUserId = (raw.match(/^<@([A-Z0-9]+)>$/i)?.[1] ?? raw).replace(/^(slack|user):/i, "").trim();
1075
+ if (!normalizedUserId) return null;
1076
+ const target = `user:${normalizedUserId}`;
1077
+ return normalizeSlackMessagingTarget(target) ?? target.toLowerCase();
1078
+ }).filter((id) => id.startsWith("user:")), params));
1079
+ }
1080
+ async function listSlackDirectoryGroupsFromConfig(params) {
1081
+ const account = inspectSlackAccount({
1082
+ cfg: params.cfg,
1083
+ accountId: params.accountId
1084
+ });
1085
+ return toDirectoryEntries("group", applyDirectoryQueryAndLimit(Object.keys(account.config.channels ?? {}).map((raw) => raw.trim()).filter(Boolean).map((raw) => normalizeSlackMessagingTarget(raw) ?? raw.toLowerCase()).filter((id) => id.startsWith("channel:")), params));
1086
+ }
1087
+ async function listDiscordDirectoryPeersFromConfig(params) {
1088
+ const account = inspectDiscordAccount({
1089
+ cfg: params.cfg,
1090
+ accountId: params.accountId
1091
+ });
1092
+ const ids = /* @__PURE__ */ new Set();
1093
+ addAllowFromAndDmsIds(ids, account.config.allowFrom ?? account.config.dm?.allowFrom, account.config.dms);
1094
+ for (const guild of Object.values(account.config.guilds ?? {})) {
1095
+ addTrimmedEntries(ids, guild.users ?? []);
1096
+ for (const channel of Object.values(guild.channels ?? {})) addTrimmedEntries(ids, channel.users ?? []);
1097
+ }
1098
+ return toDirectoryEntries("user", applyDirectoryQueryAndLimit(normalizeTrimmedSet(ids, (raw) => {
1099
+ const cleaned = (raw.match(/^<@!?(\d+)>$/)?.[1] ?? raw).replace(/^(discord|user):/i, "").trim();
1100
+ if (!/^\d+$/.test(cleaned)) return null;
1101
+ return `user:${cleaned}`;
1102
+ }), params));
1103
+ }
1104
+ async function listDiscordDirectoryGroupsFromConfig(params) {
1105
+ const account = inspectDiscordAccount({
1106
+ cfg: params.cfg,
1107
+ accountId: params.accountId
1108
+ });
1109
+ const ids = /* @__PURE__ */ new Set();
1110
+ for (const guild of Object.values(account.config.guilds ?? {})) addTrimmedEntries(ids, Object.keys(guild.channels ?? {}));
1111
+ return toDirectoryEntries("group", applyDirectoryQueryAndLimit(normalizeTrimmedSet(ids, (raw) => {
1112
+ const cleaned = (raw.match(/^<#(\d+)>$/)?.[1] ?? raw).replace(/^(discord|channel|group):/i, "").trim();
1113
+ if (!/^\d+$/.test(cleaned)) return null;
1114
+ return `channel:${cleaned}`;
1115
+ }), params));
1116
+ }
1117
+ async function listTelegramDirectoryPeersFromConfig(params) {
1118
+ const account = inspectTelegramAccount({
1119
+ cfg: params.cfg,
1120
+ accountId: params.accountId
1121
+ });
1122
+ const raw = [...(account.config.allowFrom ?? []).map((entry) => String(entry)), ...Object.keys(account.config.dms ?? {})];
1123
+ return toDirectoryEntries("user", applyDirectoryQueryAndLimit(Array.from(new Set(raw.map((entry) => entry.trim()).filter(Boolean).map((entry) => entry.replace(/^(telegram|tg):/i, "")))).map((entry) => {
1124
+ const trimmed = entry.trim();
1125
+ if (!trimmed) return null;
1126
+ if (/^-?\d+$/.test(trimmed)) return trimmed;
1127
+ return trimmed.startsWith("@") ? trimmed : `@${trimmed}`;
1128
+ }).filter((id) => Boolean(id)), params));
1129
+ }
1130
+ async function listTelegramDirectoryGroupsFromConfig(params) {
1131
+ const account = inspectTelegramAccount({
1132
+ cfg: params.cfg,
1133
+ accountId: params.accountId
1134
+ });
1135
+ return toDirectoryEntries("group", applyDirectoryQueryAndLimit(Object.keys(account.config.groups ?? {}).map((id) => id.trim()).filter((id) => Boolean(id) && id !== "*"), params));
1136
+ }
1137
+ async function listWhatsAppDirectoryPeersFromConfig(params) {
1138
+ return toDirectoryEntries("user", applyDirectoryQueryAndLimit((resolveWhatsAppAccount({
1139
+ cfg: params.cfg,
1140
+ accountId: params.accountId
1141
+ }).allowFrom ?? []).map((entry) => String(entry).trim()).filter((entry) => Boolean(entry) && entry !== "*").map((entry) => normalizeWhatsAppTarget(entry) ?? "").filter(Boolean).filter((id) => !isWhatsAppGroupJid(id)), params));
1142
+ }
1143
+ async function listWhatsAppDirectoryGroupsFromConfig(params) {
1144
+ const account = resolveWhatsAppAccount({
1145
+ cfg: params.cfg,
1146
+ accountId: params.accountId
1147
+ });
1148
+ return toDirectoryEntries("group", applyDirectoryQueryAndLimit(Object.keys(account.groups ?? {}).map((id) => id.trim()).filter((id) => Boolean(id) && id !== "*"), params));
1149
+ }
1150
+
1151
+ //#endregion
1152
+ //#region src/channels/plugins/index.ts
1153
+ function dedupeChannels(channels) {
1154
+ const seen = /* @__PURE__ */ new Set();
1155
+ const resolved = [];
1156
+ for (const plugin of channels) {
1157
+ const id = String(plugin.id).trim();
1158
+ if (!id || seen.has(id)) continue;
1159
+ seen.add(id);
1160
+ resolved.push(plugin);
1161
+ }
1162
+ return resolved;
1163
+ }
1164
+ let cachedChannelPlugins = {
1165
+ registryVersion: -1,
1166
+ sorted: [],
1167
+ byId: /* @__PURE__ */ new Map()
1168
+ };
1169
+ function resolveCachedChannelPlugins() {
1170
+ const registry = requireActivePluginRegistry();
1171
+ const registryVersion = getActivePluginRegistryVersion();
1172
+ const cached = cachedChannelPlugins;
1173
+ if (cached.registryVersion === registryVersion) return cached;
1174
+ const sorted = dedupeChannels(registry.channels.map((entry) => entry.plugin)).toSorted((a, b) => {
1175
+ const indexA = CHAT_CHANNEL_ORDER.indexOf(a.id);
1176
+ const indexB = CHAT_CHANNEL_ORDER.indexOf(b.id);
1177
+ const orderA = a.meta.order ?? (indexA === -1 ? 999 : indexA);
1178
+ const orderB = b.meta.order ?? (indexB === -1 ? 999 : indexB);
1179
+ if (orderA !== orderB) return orderA - orderB;
1180
+ return a.id.localeCompare(b.id);
1181
+ });
1182
+ const byId = /* @__PURE__ */ new Map();
1183
+ for (const plugin of sorted) byId.set(plugin.id, plugin);
1184
+ const next = {
1185
+ registryVersion,
1186
+ sorted,
1187
+ byId
1188
+ };
1189
+ cachedChannelPlugins = next;
1190
+ return next;
1191
+ }
1192
+ function listChannelPlugins() {
1193
+ return resolveCachedChannelPlugins().sorted.slice();
1194
+ }
1195
+ function getChannelPlugin(id) {
1196
+ const resolvedId = String(id).trim();
1197
+ if (!resolvedId) return;
1198
+ return resolveCachedChannelPlugins().byId.get(resolvedId);
1199
+ }
1200
+ function normalizeChannelId(raw) {
1201
+ return normalizeAnyChannelId(raw);
1202
+ }
1203
+
1204
+ //#endregion
1205
+ export { listConfiguredAccountIds$1 as A, isWhatsAppGroupJid as B, resolveDefaultTelegramAccountId as C, buildChannelAccountBindings as D, resolveTelegramToken as E, resolveDefaultSlackAccountId as F, listEnabledDiscordAccounts as G, inspectDiscordAccount as H, resolveSlackAccount as I, normalizeDiscordToken as J, resolveDefaultDiscordAccountId as K, resolveSlackReplyToMode as L, inspectSlackAccount as M, listEnabledSlackAccounts as N, listBindings as O, listSlackAccountIds as P, resolveSlackAppToken as R, listTelegramAccountIds as S, resolveTelegramPollActionGateState as T, createDiscordActionGate as U, normalizeWhatsAppTarget as V, listDiscordAccountIds as W, normalizeChatType as Y, parseMentionPrefixOrAtUserTarget as _, listDiscordDirectoryPeersFromConfig as a, createTelegramActionGate as b, listTelegramDirectoryGroupsFromConfig as c, listWhatsAppDirectoryPeersFromConfig as d, looksLikeSlackTargetId as f, buildMessagingTarget as g, resolveSlackChannelId as h, listDiscordDirectoryGroupsFromConfig as i, resolveAccountWithDefaultFallback as j, listAcpBindings as k, listTelegramDirectoryPeersFromConfig as l, parseSlackTarget as m, listChannelPlugins as n, listSlackDirectoryGroupsFromConfig as o, normalizeSlackMessagingTarget as p, resolveDiscordAccount as q, normalizeChannelId as r, listSlackDirectoryPeersFromConfig as s, getChannelPlugin as t, listWhatsAppDirectoryGroupsFromConfig as u, requireTargetKind as v, resolveTelegramAccount as w, listEnabledTelegramAccounts as x, inspectTelegramAccount as y, resolveSlackBotToken as z };