hyperclaw 4.0.2 → 5.0.1

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 (194) hide show
  1. package/README.md +246 -60
  2. package/dist/a2ui-protocol-CfBI44-Q.js +75 -0
  3. package/dist/agents-routing-ChHiZp36.js +327 -0
  4. package/dist/agents-routing-ChqZ6l2S.js +4 -0
  5. package/dist/api-keys-guide-BCcOl0Q7.js +149 -0
  6. package/dist/api-keys-guide-CGn5BSF7.js +149 -0
  7. package/dist/audit-BJohI_vC.js +441 -0
  8. package/dist/audit-BaIiyWFu.js +441 -0
  9. package/dist/bounty-tools-CY_i91DU.js +211 -0
  10. package/dist/bounty-tools-DWudyZie.js +211 -0
  11. package/dist/browser-tools-BsTeGMnX.js +5 -0
  12. package/dist/browser-tools-D8_rLe2p.js +179 -0
  13. package/dist/claw-tasks-CgTsiNE8.js +80 -0
  14. package/dist/claw-tasks-Cyzdbhz_.js +80 -0
  15. package/dist/connector-5N0-X_xs.js +194 -0
  16. package/dist/connector-B3v0qcXg.js +425 -0
  17. package/dist/connector-B8R3iBY1.js +280 -0
  18. package/dist/connector-BAM-08NN.js +189 -0
  19. package/dist/connector-BC8FIVu4.js +181 -0
  20. package/dist/connector-BDmwwaVc.js +213 -0
  21. package/dist/connector-BGjbBy69.js +225 -0
  22. package/dist/connector-BO2SRzfG.js +218 -0
  23. package/dist/connector-BfXky0L3.js +167 -0
  24. package/dist/connector-BiiSJpx3.js +192 -0
  25. package/dist/connector-BnDmIhIu.js +85 -0
  26. package/dist/connector-C1HSoUyk.js +189 -0
  27. package/dist/connector-CKQHZOXg.js +568 -0
  28. package/dist/connector-CRl-iidy.js +239 -0
  29. package/dist/connector-Ci9glMD-.js +340 -0
  30. package/dist/connector-CjtZIEDj.js +181 -0
  31. package/dist/connector-Ck6JtOsX.js +531 -0
  32. package/dist/connector-D8Kelee0.js +286 -0
  33. package/dist/connector-DAnRJ0oP.js +162 -0
  34. package/dist/connector-DXTp5PE8.js +508 -0
  35. package/dist/connector-Dih6dUPP.js +173 -0
  36. package/dist/connector-DqTH_tPX.js +182 -0
  37. package/dist/connector-DrnEiiyP.js +419 -0
  38. package/dist/connector-DtR5GGTX.js +167 -0
  39. package/dist/connector-Tky_qS_K.js +350 -0
  40. package/dist/connector-ZSc3oTTy.js +305 -0
  41. package/dist/connector-sW5yhU1m.js +498 -0
  42. package/dist/connector-u3ICd3Ic.js +552 -0
  43. package/dist/cost-tracker-Ca1UPZ33.js +103 -0
  44. package/dist/cost-tracker-DD9wtWsr.js +103 -0
  45. package/dist/credentials-store-C6ir0Dae.js +4 -0
  46. package/dist/credentials-store-CA8UtK0T.js +77 -0
  47. package/dist/credentials-store-Cm7DH-kh.js +4 -0
  48. package/dist/credentials-store-H13LqOwJ.js +77 -0
  49. package/dist/cron-tasks-Bli7Kzd2.js +82 -0
  50. package/dist/cron-tasks-_pqQCmxc.js +82 -0
  51. package/dist/daemon-7ViroziB.js +5 -0
  52. package/dist/daemon-BfyKmZhr.js +318 -0
  53. package/dist/daemon-Bg4GtCmc.js +318 -0
  54. package/dist/daemon-DhmwY8k4.js +5 -0
  55. package/dist/delivery-BmIYy9VQ.js +4 -0
  56. package/dist/delivery-DVHmv1IR.js +4 -0
  57. package/dist/delivery-DpMX0Yyc.js +95 -0
  58. package/dist/delivery-pWUPBp1F.js +95 -0
  59. package/dist/destructive-gate-D6vWOdEl.js +101 -0
  60. package/dist/destructive-gate-DZt71UZR.js +101 -0
  61. package/dist/developer-keys-CPWT7Q6S.js +8 -0
  62. package/dist/developer-keys-DrrcUqFa.js +127 -0
  63. package/dist/doctor-BvCe8BBk.js +230 -0
  64. package/dist/doctor-CxyPLYsJ.js +6 -0
  65. package/dist/engine-B0kLfRL0.js +256 -0
  66. package/dist/engine-BJUpRUOv.js +7 -0
  67. package/dist/engine-CEDSqXfw.js +256 -0
  68. package/dist/engine-Da4JMNpI.js +7 -0
  69. package/dist/env-resolve-17ekEU6p.js +10 -0
  70. package/dist/env-resolve-CiXbWYwe.js +10 -0
  71. package/dist/env-resolve-CmGWhWXJ.js +115 -0
  72. package/dist/env-resolve-Z2XF6leB.js +115 -0
  73. package/dist/extraction-tools-HOZstZ0y.js +91 -0
  74. package/dist/extraction-tools-m4lmAv7l.js +5 -0
  75. package/dist/form_data-Cz040rio.js +8657 -0
  76. package/dist/gmail-watch-setup-Du7DVV7S.js +40 -0
  77. package/dist/health-B-asI__D.js +6 -0
  78. package/dist/health-Ds2YlpTB.js +152 -0
  79. package/dist/heartbeat-engine-BYT5ayQH.js +83 -0
  80. package/dist/heartbeat-engine-Ut6pXBD6.js +83 -0
  81. package/dist/hub-9LaKnLjY.js +6 -0
  82. package/dist/hub-CfwUz9YW.js +515 -0
  83. package/dist/hub-D0XwdjM-.js +515 -0
  84. package/dist/hub-LiD5Iztb.js +6 -0
  85. package/dist/hyperclawbot-CBiDSKsa.js +505 -0
  86. package/dist/hyperclawbot-zvczQgKx.js +505 -0
  87. package/dist/inference-0mlFQqIm.js +922 -0
  88. package/dist/inference-BKVkBREb.js +6 -0
  89. package/dist/inference-DCXH4Q3x.js +922 -0
  90. package/dist/inference-SzqFe_nk.js +6 -0
  91. package/dist/knowledge-graph-DE5lSF02.js +131 -0
  92. package/dist/knowledge-graph-iBG76fvm.js +131 -0
  93. package/dist/loader-BkDi8MD9.js +400 -0
  94. package/dist/loader-CC45xGpC.js +4 -0
  95. package/dist/loader-CnEdOyjT.js +400 -0
  96. package/dist/loader-DI2qDRPC.js +4 -0
  97. package/dist/logger-Cp8wC7F8.js +83 -0
  98. package/dist/logger-ybOp7VOC.js +83 -0
  99. package/dist/manager-03ipO9R0.js +105 -0
  100. package/dist/manager-B2Gls5RG.js +218 -0
  101. package/dist/manager-BpDfbDjg.js +117 -0
  102. package/dist/manager-Bxl0sqlh.js +4 -0
  103. package/dist/manager-CWNSML5D.js +117 -0
  104. package/dist/manager-CrVDn6eN.js +6 -0
  105. package/dist/manager-FCgF1plu.js +218 -0
  106. package/dist/manager-SJe9gt-q.js +4 -0
  107. package/dist/manager-rgCsaWT1.js +40 -0
  108. package/dist/mcp-CfoSU4Uz.js +139 -0
  109. package/dist/mcp-loader-CvxRDtPC.js +94 -0
  110. package/dist/mcp-loader-DkRBsLpk.js +94 -0
  111. package/dist/memory-BlHL7JCO.js +4 -0
  112. package/dist/memory-DsS_eFvJ.js +270 -0
  113. package/dist/memory-auto-BkvtSFUw.js +5 -0
  114. package/dist/memory-auto-Bnz_-1wP.js +306 -0
  115. package/dist/memory-auto-CpQHZlEJ.js +306 -0
  116. package/dist/memory-auto-Z6LCf-iK.js +5 -0
  117. package/dist/memory-integration-cSYkZyEo.js +91 -0
  118. package/dist/memory-integration-g2vxwgoE.js +91 -0
  119. package/dist/moltbook-BtLDZTfM.js +81 -0
  120. package/dist/moltbook-Cl8cQfxJ.js +81 -0
  121. package/dist/node-Dw2Gi-cP.js +222 -0
  122. package/dist/nodes-registry-B8dmrlLv.js +52 -0
  123. package/dist/nodes-registry-C9dCFwjh.js +52 -0
  124. package/dist/oauth-flow-CeaaGAz0.js +150 -0
  125. package/dist/oauth-flow-DQPvMHRH.js +150 -0
  126. package/dist/oauth-provider-B4dzn56l.js +110 -0
  127. package/dist/oauth-provider-Uo4Nib_c.js +110 -0
  128. package/dist/observability-BV-Yx0V9.js +89 -0
  129. package/dist/observability-nZ3CBIxG.js +89 -0
  130. package/dist/onboard-0WoDxbv_.js +10 -0
  131. package/dist/onboard-BBBWcfhp.js +10 -0
  132. package/dist/onboard-BXNXCQp4.js +4070 -0
  133. package/dist/onboard-Bw28IRQ3.js +4070 -0
  134. package/dist/orchestrator-BovkM63z.js +6 -0
  135. package/dist/orchestrator-DSbpkP1X.js +189 -0
  136. package/dist/orchestrator-DmnEvMaL.js +189 -0
  137. package/dist/orchestrator-RI3bpqqc.js +6 -0
  138. package/dist/osint-B4_m3VHQ.js +277 -0
  139. package/dist/pairing-6iM27aD8.js +196 -0
  140. package/dist/pairing-dGoiGepK.js +4 -0
  141. package/dist/pc-access-CgCsYrpt.js +8 -0
  142. package/dist/pc-access-_iH2aorG.js +819 -0
  143. package/dist/pending-approval-BgNjjuI2.js +22 -0
  144. package/dist/pending-approval-CUXjysAo.js +22 -0
  145. package/dist/reminders-store-Drjed_-h.js +58 -0
  146. package/dist/renderer-BVQrd0_g.js +225 -0
  147. package/dist/rules-BE4GV6cV.js +103 -0
  148. package/dist/run-main.js +1639 -460
  149. package/dist/runner-CJFJUtPm.js +1271 -0
  150. package/dist/runner-DatMMYYE.js +1271 -0
  151. package/dist/sdk/index.js +2 -2
  152. package/dist/sdk/index.mjs +2 -2
  153. package/dist/security-BqNyT4ID.js +4 -0
  154. package/dist/security-tpgqPWWH.js +73 -0
  155. package/dist/server-Brl_HQUB.js +1255 -0
  156. package/dist/server-D4wVHiX9.js +4 -0
  157. package/dist/server-Dh3JlBFB.js +1255 -0
  158. package/dist/server-DhfipkwN.js +4 -0
  159. package/dist/session-store-BUiPz0Vv.js +5 -0
  160. package/dist/session-store-is4B6qmD.js +113 -0
  161. package/dist/sessions-tools-CbUTFe4i.js +5 -0
  162. package/dist/sessions-tools-CeqD7iil.js +95 -0
  163. package/dist/skill-loader-BaNLVmJy.js +7 -0
  164. package/dist/skill-loader-HgpF6Vqs.js +159 -0
  165. package/dist/skill-runtime-BXWd-Ktf.js +102 -0
  166. package/dist/skill-runtime-CJN24QPW.js +102 -0
  167. package/dist/skill-runtime-jgklm02e.js +5 -0
  168. package/dist/skill-runtime-w1ig_lcw.js +5 -0
  169. package/dist/src-Bhybpk1J.js +63 -0
  170. package/dist/src-BxPHKO5x.js +63 -0
  171. package/dist/src-DIc-L2IG.js +20 -0
  172. package/dist/src-DMJ4-uqk.js +458 -0
  173. package/dist/src-g_rNx5rh.js +458 -0
  174. package/dist/sub-agent-tools-CHQoHz9c.js +39 -0
  175. package/dist/sub-agent-tools-DHY-4WWM.js +39 -0
  176. package/dist/theme-DcxwcUgZ.js +180 -0
  177. package/dist/theme-cx0fkgWC.js +8 -0
  178. package/dist/tool-policy-CNT-mF2Z.js +189 -0
  179. package/dist/tool-policy-DZvF8xlQ.js +189 -0
  180. package/dist/tts-elevenlabs-BRosZv-f.js +61 -0
  181. package/dist/tts-elevenlabs-C06nUxMK.js +61 -0
  182. package/dist/update-check-C2Dz85wJ.js +81 -0
  183. package/dist/update-check-w4XuxVl7.js +81 -0
  184. package/dist/vision-BMmiIKy7.js +121 -0
  185. package/dist/vision-JOtOS1Br.js +121 -0
  186. package/dist/vision-tools-CB28ZCO_.js +5 -0
  187. package/dist/vision-tools-DVuYc17I.js +51 -0
  188. package/dist/vision-tools-U3YC4L-g.js +5 -0
  189. package/dist/vision-tools-vPPwQ-0N.js +51 -0
  190. package/dist/voice-transcription-B555DbWR.js +138 -0
  191. package/dist/voice-transcription-DBo5hXmu.js +138 -0
  192. package/dist/website-watch-tools-DFMrJU-R.js +139 -0
  193. package/dist/website-watch-tools-Du3W5sN7.js +5 -0
  194. package/package.json +1 -1
@@ -0,0 +1,1271 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ const require_paths = require('./paths-AIyBxIzm.js');
3
+ const require_paths$1 = require('./paths-DPovhojT.js');
4
+ const require_delivery = require('./delivery-DpMX0Yyc.js');
5
+ const fs_extra = require_chunk.__toESM(require("fs-extra"));
6
+ const path = require_chunk.__toESM(require("path"));
7
+ const http = require_chunk.__toESM(require("http"));
8
+
9
+ //#region src/routing/broadcast.ts
10
+ /**
11
+
12
+ * Check whether `peerId` is in the broadcast config.
13
+
14
+ * Returns the list of agent IDs and strategy, or null if not found.
15
+
16
+ *
17
+
18
+ * @param peerId WhatsApp JID, E.164 number, or other peer ID
19
+
20
+ * @param cfg The top-level `broadcast` config block
21
+
22
+ */
23
+ function resolveBroadcast(peerId, cfg) {
24
+ if (!cfg) return null;
25
+ const strategy = cfg.strategy === "sequential" ? "sequential" : "parallel";
26
+ const agentIds = cfg[peerId];
27
+ if (!Array.isArray(agentIds) || agentIds.length === 0) return null;
28
+ return {
29
+ agentIds,
30
+ strategy
31
+ };
32
+ }
33
+ /**
34
+
35
+ * Dispatch an inbound message to all agents in a broadcast group.
36
+
37
+ *
38
+
39
+ * - Parallel (default): all agents are invoked concurrently.
40
+
41
+ * - Sequential: agents run in array order; each waits for the previous.
42
+
43
+ *
44
+
45
+ * Agents fail independently — one failure does not stop others.
46
+
47
+ *
48
+
49
+ * @param message Raw inbound text to send to each agent.
50
+
51
+ * @param peerId Peer ID the message arrived in.
52
+
53
+ * @param channel Channel name (e.g. "whatsapp").
54
+
55
+ * @param target Resolved broadcast target (agentIds + strategy).
56
+
57
+ * @param sendFn Sends the message to one agent and returns its text response.
58
+
59
+ * @param replyFn Delivers the agent's response back to the peer.
60
+
61
+ * @returns Map of agentId → response (or error string).
62
+
63
+ */
64
+ async function dispatchBroadcast(message, peerId, channel, target, sendFn, replyFn) {
65
+ const results = /* @__PURE__ */ new Map();
66
+ const runAgent = async (agentId) => {
67
+ const sessionKey = buildBroadcastSessionKey(agentId, channel, peerId);
68
+ try {
69
+ const response = await sendFn(message, {
70
+ agentId,
71
+ peerId,
72
+ sessionKey,
73
+ channel
74
+ });
75
+ results.set(agentId, response);
76
+ if (response) await replyFn(peerId, agentId, response).catch((e) => console.error(`[broadcast] reply failed for agent "${agentId}": ${e.message}`));
77
+ } catch (e) {
78
+ const errMsg = `Error (${agentId}): ${e.message}`;
79
+ results.set(agentId, errMsg);
80
+ console.error(`[broadcast] agent "${agentId}" failed: ${e.message}`);
81
+ }
82
+ };
83
+ if (target.strategy === "sequential") for (const agentId of target.agentIds) await runAgent(agentId);
84
+ else await Promise.all(target.agentIds.map(runAgent));
85
+ return results;
86
+ }
87
+ /**
88
+
89
+ * Build a broadcast session key for one agent in a group.
90
+
91
+ *
92
+
93
+ * Format: agent:<agentId>:<channel>:group:<peerId>
94
+
95
+ * For DMs: agent:<agentId>:<channel>:dm:<peerId>
96
+
97
+ */
98
+ function buildBroadcastSessionKey(agentId, channel, peerId) {
99
+ const isDM = peerId.startsWith("+") || /^\d+$/.test(peerId);
100
+ const chatType = isDM ? "dm" : "group";
101
+ return `agent:${agentId}:${channel}:${chatType}:${peerId}`;
102
+ }
103
+ /**
104
+
105
+ * Extract the broadcast config from the full app config object.
106
+
107
+ * Accepts any config shape (config may not be typed at call sites).
108
+
109
+ */
110
+ function extractBroadcastConfig(cfg) {
111
+ if (!cfg || typeof cfg !== "object") return null;
112
+ const b = cfg.broadcast;
113
+ if (!b || typeof b !== "object") return null;
114
+ return b;
115
+ }
116
+
117
+ //#endregion
118
+ //#region src/routing/binding-resolver.ts
119
+ /**
120
+
121
+ * Resolve which agentId should handle an inbound message.
122
+
123
+ *
124
+
125
+ * @param ctx Inbound message context.
126
+
127
+ * @param bindings The `bindings` array from config.
128
+
129
+ * @param agents The `agents.list` array from config (for default resolution).
130
+
131
+ * @returns agentId string, or "main" as the ultimate fallback.
132
+
133
+ */
134
+ function resolveBinding(ctx, bindings, agents) {
135
+ if (bindings && bindings.length > 0) {
136
+ const peerExact = bindings.find((b) => matchChannel(b, ctx) && matchAccount(b, ctx) && b.match.peer?.id === ctx.peerId);
137
+ if (peerExact) return peerExact.agentId;
138
+ if (ctx.threadId) {
139
+ const parentId = ctx.peerId;
140
+ const parentMatch = bindings.find((b) => matchChannel(b, ctx) && matchAccount(b, ctx) && b.match.peer?.id === parentId);
141
+ if (parentMatch) return parentMatch.agentId;
142
+ }
143
+ if (ctx.guildId && ctx.senderRoles && ctx.senderRoles.length > 0) {
144
+ const guildRoles = bindings.find((b) => matchChannel(b, ctx) && b.match.guildId === ctx.guildId && b.match.roles && b.match.roles.every((r) => ctx.senderRoles.includes(r)));
145
+ if (guildRoles) return guildRoles.agentId;
146
+ }
147
+ if (ctx.guildId) {
148
+ const guildOnly = bindings.find((b) => matchChannel(b, ctx) && b.match.guildId === ctx.guildId && !b.match.roles);
149
+ if (guildOnly) return guildOnly.agentId;
150
+ }
151
+ if (ctx.teamId) {
152
+ const team = bindings.find((b) => matchChannel(b, ctx) && b.match.teamId === ctx.teamId);
153
+ if (team) return team.agentId;
154
+ }
155
+ if (ctx.accountId) {
156
+ const account = bindings.find((b) => matchChannel(b, ctx) && b.match.accountId === ctx.accountId && !b.match.peer);
157
+ if (account) return account.agentId;
158
+ }
159
+ const channelOnly = bindings.find((b) => b.match.channel === ctx.channel && !b.match.peer && !b.match.accountId && !b.match.guildId && !b.match.teamId);
160
+ if (channelOnly) return channelOnly.agentId;
161
+ const wildcard = bindings.find((b) => b.match.channel === "*" && !b.match.peer && !b.match.guildId && !b.match.teamId);
162
+ if (wildcard) return wildcard.agentId;
163
+ }
164
+ return resolveDefaultAgent(agents);
165
+ }
166
+ /** Resolve the default agentId from agents.list. */
167
+ function resolveDefaultAgent(agents) {
168
+ if (!agents || agents.length === 0) return "main";
169
+ const defaultAgent = agents.find((a) => a.default);
170
+ if (defaultAgent) return defaultAgent.id;
171
+ return agents[0].id;
172
+ }
173
+ function matchChannel(binding, ctx) {
174
+ const ch = binding.match.channel;
175
+ return !ch || ch === "*" || ch === ctx.channel;
176
+ }
177
+ function matchAccount(binding, ctx) {
178
+ const acc = binding.match.accountId;
179
+ return !acc || acc === "*" || acc === ctx.accountId;
180
+ }
181
+ /** Extract bindings array from raw config (tolerates untyped config objects). */
182
+ function extractBindings(cfg) {
183
+ if (!cfg || !Array.isArray(cfg.bindings)) return [];
184
+ return cfg.bindings;
185
+ }
186
+ /** Extract agents list from raw config. */
187
+ function extractAgentsList(cfg) {
188
+ if (!cfg?.agents?.list || !Array.isArray(cfg.agents.list)) return [];
189
+ return cfg.agents.list;
190
+ }
191
+ /** Build InboundContext from the message envelope emitted by a connector. */
192
+ function buildInboundContext(msg, channelId) {
193
+ const peerId = String(msg.chatId);
194
+ const chatType = msg.isDM ? "dm" : msg.isGroup ? "group" : "channel";
195
+ return {
196
+ channel: channelId,
197
+ accountId: msg.accountId,
198
+ peerId,
199
+ chatType,
200
+ threadId: msg.threadId,
201
+ guildId: msg.guildId,
202
+ teamId: msg.teamId,
203
+ senderRoles: msg.senderRoles
204
+ };
205
+ }
206
+
207
+ //#endregion
208
+ //#region src/routing/session-keys.ts
209
+ /**
210
+
211
+ * Build a session key based on the chat type and dmScope setting.
212
+
213
+ */
214
+ function buildSessionKey(opts) {
215
+ const { agentId, channel, chatType, peerId, accountId = "default", threadId, dmScope = "main", mainKey = "main" } = opts;
216
+ const effectivePeerId = opts.canonicalPeerId || peerId;
217
+ if (chatType === "group") {
218
+ const base = `agent:${agentId}:${channel}:group:${effectivePeerId}`;
219
+ if (threadId) return `${base}:topic:${threadId}`;
220
+ return base;
221
+ }
222
+ if (chatType === "channel") {
223
+ const base = `agent:${agentId}:${channel}:channel:${effectivePeerId}`;
224
+ if (threadId) return `${base}:thread:${threadId}`;
225
+ return base;
226
+ }
227
+ switch (dmScope) {
228
+ case "main": return `agent:${agentId}:${mainKey}`;
229
+ case "per-peer": return `agent:${agentId}:dm:${effectivePeerId}`;
230
+ case "per-channel-peer": return `agent:${agentId}:${channel}:dm:${effectivePeerId}`;
231
+ case "per-account-channel-peer": return `agent:${agentId}:${channel}:${accountId}:dm:${effectivePeerId}`;
232
+ default: return `agent:${agentId}:${mainKey}`;
233
+ }
234
+ }
235
+ /**
236
+
237
+ * Resolve a provider-prefixed peer ID to a canonical identity if a link exists.
238
+
239
+ *
240
+
241
+ * identityLinks shape:
242
+
243
+ * {
244
+
245
+ * "alice": ["telegram:123456789", "discord:987654321012345678"]
246
+
247
+ * }
248
+
249
+ *
250
+
251
+ * Returns the canonical identity key if found, otherwise returns the raw peerId.
252
+
253
+ */
254
+ function resolveIdentityLink(channel, peerId, identityLinks) {
255
+ if (!identityLinks) return peerId;
256
+ const providerPeerId = `${channel}:${peerId}`;
257
+ for (const [canonical, links] of Object.entries(identityLinks)) if (links.includes(providerPeerId)) return canonical;
258
+ return peerId;
259
+ }
260
+ /** Extract session config from raw config object. */
261
+ function extractSessionConfig(cfg) {
262
+ const session = cfg?.session || {};
263
+ return {
264
+ dmScope: session.dmScope || "main",
265
+ mainKey: session.mainKey || "main",
266
+ identityLinks: session.identityLinks || {}
267
+ };
268
+ }
269
+
270
+ //#endregion
271
+ //#region src/channels/runner.ts
272
+ require_paths$1.init_paths();
273
+ const HC_DIR = require_paths.getHyperClawDir();
274
+ const connectors = [];
275
+ let emailConnectorRef = null;
276
+ const webhookConnectors = {};
277
+ async function startChannelRunners(opts) {
278
+ const port = opts.port;
279
+ const baseUrl = `http://${opts.bind || "127.0.0.1"}:${port}`;
280
+ const authToken = opts.authToken || "";
281
+ let cfg = {};
282
+ try {
283
+ cfg = await fs_extra.default.readJson(require_paths.getConfigPath());
284
+ } catch {}
285
+ let channelConfigs = {};
286
+ let configChannels = [];
287
+ try {
288
+ const configPath = path.default.join(HC_DIR, "config.json");
289
+ if (await fs_extra.default.pathExists(configPath)) {
290
+ const c2 = await fs_extra.default.readJson(configPath);
291
+ channelConfigs = c2.channelConfigs || {};
292
+ configChannels = Array.isArray(c2.channels) ? c2.channels : [];
293
+ }
294
+ } catch {}
295
+ const enabledIds = (cfg.gateway?.enabledChannels?.length ? cfg.gateway.enabledChannels : configChannels) || [];
296
+ const ids = Array.isArray(enabledIds) ? enabledIds : [];
297
+ if (ids.length === 0) return { stop: async () => {} };
298
+ const broadcastCfg = extractBroadcastConfig(cfg);
299
+ const bindings = extractBindings(cfg);
300
+ const agentsList = extractAgentsList(cfg);
301
+ const sessionCfg = extractSessionConfig(cfg);
302
+ const wrap = (c) => {
303
+ const ty = c.sendTyping;
304
+ return {
305
+ sendMessage: (id, t) => c.sendMessage(String(id), t),
306
+ sendTyping: ty ? (id) => ty(String(id)) : void 0
307
+ };
308
+ };
309
+ /**
310
+
311
+ * Handles one inbound message from any channel connector.
312
+
313
+ * Supports broadcast groups (multi-agent) and binding resolution.
314
+
315
+ */
316
+ const handleMsg = async (msg, conn, channelId) => {
317
+ try {
318
+ conn.sendTyping?.(msg.chatId).catch(() => {});
319
+ const { enrichVoiceNote } = await Promise.resolve().then(() => require("./delivery-DVHmv1IR.js"));
320
+ const text = await enrichVoiceNote(msg);
321
+ const peerId = String(msg.chatId);
322
+ const broadcastTarget = resolveBroadcast(peerId, broadcastCfg);
323
+ if (broadcastTarget) {
324
+ await dispatchBroadcast(text, peerId, channelId, broadcastTarget, async (message, dispatchOpts) => {
325
+ return await require_delivery.withRetry(() => postChat(baseUrl, message, channelId, authToken, dispatchOpts.agentId, dispatchOpts.sessionKey), { onRetry: (n, err) => console.error(`[broadcast] ${dispatchOpts.agentId} retry ${n}: ${err.message}`) });
326
+ }, async (_peerId, _agentId, response$1) => {
327
+ const chunks$1 = require_delivery.chunkForChannel(response$1, channelId);
328
+ for (const chunk of chunks$1) await require_delivery.withRetry(() => conn.sendMessage(msg.chatId, chunk), { onRetry: (n, err) => console.error(`[broadcast] send retry ${n}: ${err.message}`) });
329
+ });
330
+ return;
331
+ }
332
+ const inboundCtx = buildInboundContext(msg, channelId);
333
+ const agentId = resolveBinding(inboundCtx, bindings, agentsList);
334
+ const canonicalPeerId = resolveIdentityLink(channelId, peerId, sessionCfg.identityLinks);
335
+ const sessionKey = buildSessionKey({
336
+ agentId,
337
+ channel: channelId,
338
+ chatType: inboundCtx.chatType,
339
+ peerId,
340
+ accountId: msg.accountId,
341
+ threadId: msg.threadId,
342
+ dmScope: sessionCfg.dmScope,
343
+ mainKey: sessionCfg.mainKey,
344
+ canonicalPeerId
345
+ });
346
+ const response = await require_delivery.withRetry(() => postChat(baseUrl, text, channelId, authToken, agentId, sessionKey), { onRetry: (n, err) => console.error(`[channels] ${channelId} agent retry ${n}: ${err.message}`) });
347
+ const chunks = require_delivery.chunkForChannel(response, channelId);
348
+ for (const chunk of chunks) await require_delivery.withRetry(() => conn.sendMessage(msg.chatId, chunk), { onRetry: (n, err) => console.error(`[channels] ${channelId} send retry ${n}: ${err.message}`) });
349
+ } catch (e) {
350
+ console.error(`[channels] ${channelId} error: ${e.message}`);
351
+ await conn.sendMessage(msg.chatId, `Error: ${e.message}`).catch(() => {});
352
+ }
353
+ };
354
+ for (const id of ids) {
355
+ const chCfg = cfg.channels?.[id] || channelConfigs[id];
356
+ const dmObj = chCfg?.dmPolicy;
357
+ const dmPolicy = (typeof dmObj === "object" ? dmObj?.policy : dmObj) || "pairing";
358
+ const allowFrom = chCfg?.allowFrom || (typeof dmObj === "object" ? dmObj?.allowFrom : []) || [];
359
+ const allowFromArr = Array.isArray(allowFrom) ? allowFrom : [];
360
+ if (id === "telegram") {
361
+ const token = chCfg?.token || chCfg?.botToken || process.env.TELEGRAM_BOT_TOKEN;
362
+ if (!token) continue;
363
+ const groupAllowFrom = Array.isArray(chCfg?.groupAllowFrom) ? chCfg.groupAllowFrom.map(String) : [];
364
+ const groupActivation = chCfg?.groupActivation === "always" ? "always" : "mention";
365
+ try {
366
+ const { TelegramConnector } = await Promise.resolve().then(() => require("./connector-B8R3iBY1.js"));
367
+ const conn = new TelegramConnector(token, {
368
+ dmPolicy,
369
+ allowFrom: allowFromArr,
370
+ groupAllowFrom,
371
+ groupActivation,
372
+ pendingPairings: {},
373
+ approvedPairings: []
374
+ });
375
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "telegram"));
376
+ await conn.connect();
377
+ connectors.push({ stop: async () => {
378
+ await conn.disconnect();
379
+ } });
380
+ } catch (e) {
381
+ console.error(`[channels] Telegram failed to start: ${e.message}`);
382
+ }
383
+ } else if (id === "discord") {
384
+ const token = chCfg?.token || process.env.DISCORD_BOT_TOKEN;
385
+ if (!token) continue;
386
+ try {
387
+ const { DiscordConnector } = await Promise.resolve().then(() => require("./connector-DrnEiiyP.js"));
388
+ const { PairingStore } = await Promise.resolve().then(() => require("./pairing-dGoiGepK.js"));
389
+ const discordStore = new PairingStore("discord");
390
+ const pairingBridge = {
391
+ isApproved: (senderId) => discordStore.isApproved(senderId),
392
+ createRequest: (senderId) => discordStore.createRequest(senderId),
393
+ verify: (code, senderId) => discordStore.verify(code, senderId)
394
+ };
395
+ const listenGuildIds = Array.isArray(chCfg?.listenGuildIds) ? chCfg.listenGuildIds : chCfg?.guilds ? Object.keys(chCfg.guilds) : [];
396
+ const requireMentionInGuild = chCfg?.requireMentionInGuild;
397
+ const conn = new DiscordConnector(token, {
398
+ dmPolicy,
399
+ allowFrom: allowFromArr,
400
+ pendingPairings: {},
401
+ approvedPairings: [],
402
+ pairingBridge,
403
+ listenGuildIds: listenGuildIds.filter(Boolean),
404
+ requireMentionInGuild: requireMentionInGuild === false ? false : true
405
+ });
406
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "discord"));
407
+ await conn.connect();
408
+ connectors.push({ stop: async () => {
409
+ await conn.disconnect();
410
+ } });
411
+ } catch (e) {
412
+ console.error(`[channels] Discord failed to start: ${e.message}`);
413
+ }
414
+ } else if (id === "slack") {
415
+ const botToken = chCfg?.botToken || chCfg?.token || process.env.SLACK_BOT_TOKEN;
416
+ const appToken = chCfg?.appToken || process.env.SLACK_APP_TOKEN;
417
+ const signingSecret = chCfg?.signingSecret || process.env.SLACK_SIGNING_SECRET;
418
+ const mode = chCfg?.mode || "socket";
419
+ if (!botToken) continue;
420
+ if (mode === "socket" && !appToken) {
421
+ console.error("[channels] Slack Socket Mode requires appToken (xapp-...). Set SLACK_APP_TOKEN or switch to mode: http");
422
+ continue;
423
+ }
424
+ if (mode === "http" && !signingSecret) {
425
+ console.error("[channels] Slack HTTP mode requires signingSecret. Set SLACK_SIGNING_SECRET or switch to mode: socket");
426
+ continue;
427
+ }
428
+ try {
429
+ const { SlackConnector } = await Promise.resolve().then(() => require("./connector-u3ICd3Ic.js"));
430
+ const conn = new SlackConnector({
431
+ botToken,
432
+ ...appToken ? { appToken } : {},
433
+ ...signingSecret ? { signingSecret } : {},
434
+ mode,
435
+ ...chCfg?.userToken ? { userToken: chCfg.userToken } : {},
436
+ userTokenReadOnly: chCfg?.userTokenReadOnly !== false,
437
+ dmPolicy: dmPolicy ?? "pairing",
438
+ allowFrom: allowFromArr,
439
+ dm: {
440
+ enabled: chCfg?.dm?.enabled !== false,
441
+ policy: chCfg?.dm?.policy ?? chCfg?.dmPolicy ?? dmPolicy ?? "pairing",
442
+ allowFrom: chCfg?.dm?.allowFrom ?? allowFromArr,
443
+ groupEnabled: chCfg?.dm?.groupEnabled === true,
444
+ groupChannels: chCfg?.dm?.groupChannels,
445
+ replyToMode: chCfg?.dm?.replyToMode
446
+ },
447
+ groupPolicy: chCfg?.groupPolicy || "allowlist",
448
+ channels: chCfg?.channels || {},
449
+ replyToMode: chCfg?.replyToMode || "off",
450
+ replyToModeByChatType: chCfg?.replyToModeByChatType,
451
+ thread: {
452
+ historyScope: chCfg?.thread?.historyScope || "thread",
453
+ inheritParent: chCfg?.thread?.inheritParent === true,
454
+ initialHistoryLimit: chCfg?.thread?.initialHistoryLimit ?? 20
455
+ },
456
+ textChunkLimit: chCfg?.textChunkLimit ? Number(chCfg.textChunkLimit) : void 0,
457
+ chunkMode: chCfg?.chunkMode || "length",
458
+ mediaMaxMb: chCfg?.mediaMaxMb ? Number(chCfg.mediaMaxMb) : void 0,
459
+ streaming: chCfg?.streaming || "partial",
460
+ nativeStreaming: chCfg?.nativeStreaming !== false,
461
+ ackReaction: chCfg?.ackReaction,
462
+ typingReaction: chCfg?.typingReaction,
463
+ actions: chCfg?.actions || {},
464
+ commands: chCfg?.commands || {},
465
+ slashCommand: chCfg?.slashCommand || {},
466
+ configWrites: chCfg?.configWrites !== false,
467
+ accounts: chCfg?.accounts || {},
468
+ approvedPairings: [],
469
+ pendingPairings: {}
470
+ });
471
+ conn.on("message", (msg) => {
472
+ const send = (id$1, t) => conn.sendMessage(String(id$1), t, msg.threadTs);
473
+ const typing = conn.sendTyping ? (id$1) => conn.sendTyping(String(id$1)) : void 0;
474
+ handleMsg({
475
+ chatId: msg.chatId,
476
+ text: msg.text
477
+ }, {
478
+ sendMessage: send,
479
+ sendTyping: typing
480
+ }, "slack");
481
+ });
482
+ await conn.connect();
483
+ if (mode === "http") webhookConnectors["slack"] = {
484
+ handleWebhook: async (body, opts$1) => await conn.handleWebhook(body, opts$1?.signature ?? "", opts$1?.timestamp ?? "") ?? void 0,
485
+ verifyWebhook: void 0
486
+ };
487
+ connectors.push({ stop: async () => {
488
+ conn.disconnect();
489
+ } });
490
+ } catch (e) {
491
+ console.error(`[channels] Slack failed to start: ${e.message}`);
492
+ }
493
+ } else if (id === "signal") {
494
+ const signalCliUrl = chCfg?.signalCliUrl || process.env.SIGNAL_CLI_URL || "http://localhost:8080";
495
+ const phoneNumber = chCfg?.phoneNumber || chCfg?.token || process.env.SIGNAL_PHONE_NUMBER;
496
+ if (!phoneNumber) continue;
497
+ try {
498
+ const { SignalConnector } = await Promise.resolve().then(() => require("./connector-DXTp5PE8.js"));
499
+ const conn = new SignalConnector({
500
+ httpUrl: signalCliUrl,
501
+ account: phoneNumber,
502
+ dmPolicy,
503
+ allowFrom: allowFromArr,
504
+ approvedPairings: [],
505
+ pendingPairings: {}
506
+ });
507
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "signal"));
508
+ await conn.connect();
509
+ connectors.push({ stop: async () => {
510
+ conn.disconnect();
511
+ } });
512
+ } catch (e) {
513
+ console.error(`[channels] Signal failed to start: ${e.message}`);
514
+ }
515
+ } else if (id === "matrix") {
516
+ const homeserver = chCfg?.homeserver || chCfg?.homeserverUrl || process.env.MATRIX_HOMESERVER;
517
+ const accessToken = chCfg?.accessToken || chCfg?.token || process.env.MATRIX_ACCESS_TOKEN;
518
+ const userId = chCfg?.userId || process.env.MATRIX_USER_ID;
519
+ const password = chCfg?.password || process.env.MATRIX_PASSWORD;
520
+ const hasAccounts = chCfg?.accounts && Object.keys(chCfg.accounts).length > 0;
521
+ if (!homeserver && !hasAccounts) continue;
522
+ if (!hasAccounts && !accessToken && !password) continue;
523
+ try {
524
+ const { MatrixConnector } = await Promise.resolve().then(() => require("./connector-sW5yhU1m.js"));
525
+ const conn = new MatrixConnector({
526
+ homeserver: homeserver || "",
527
+ ...accessToken ? { accessToken } : {},
528
+ ...userId ? { userId } : {},
529
+ ...password ? { password } : {},
530
+ ...chCfg?.deviceName ? { deviceName: chCfg.deviceName } : {},
531
+ encryption: chCfg?.encryption === true || chCfg?.encryption === "true",
532
+ dm: {
533
+ policy: chCfg?.dm?.policy ?? chCfg?.dmPolicy ?? dmPolicy ?? "pairing",
534
+ allowFrom: chCfg?.dm?.allowFrom ?? allowFromArr
535
+ },
536
+ groupPolicy: chCfg?.groupPolicy || "allowlist",
537
+ groupAllowFrom: Array.isArray(chCfg?.groupAllowFrom) ? chCfg.groupAllowFrom : [],
538
+ groups: chCfg?.groups || {},
539
+ rooms: chCfg?.rooms || {},
540
+ threadReplies: chCfg?.threadReplies || "inbound",
541
+ replyToMode: chCfg?.replyToMode || "off",
542
+ textChunkLimit: chCfg?.textChunkLimit ? Number(chCfg.textChunkLimit) : void 0,
543
+ chunkMode: chCfg?.chunkMode || "length",
544
+ mediaMaxMb: chCfg?.mediaMaxMb ? Number(chCfg.mediaMaxMb) : void 0,
545
+ autoJoin: chCfg?.autoJoin || "always",
546
+ autoJoinAllowlist: Array.isArray(chCfg?.autoJoinAllowlist) ? chCfg.autoJoinAllowlist : [],
547
+ accounts: chCfg?.accounts || {},
548
+ actions: chCfg?.actions || {},
549
+ approvedPairings: [],
550
+ pendingPairings: {}
551
+ });
552
+ conn.on("message", (msg) => {
553
+ const send = (id$1, t) => conn.sendMessage(String(id$1), t, msg.threadId);
554
+ handleMsg({
555
+ chatId: msg.chatId,
556
+ text: msg.text
557
+ }, { sendMessage: send }, "matrix");
558
+ });
559
+ await conn.connect();
560
+ connectors.push({ stop: async () => {
561
+ conn.disconnect();
562
+ } });
563
+ } catch (e) {
564
+ console.error(`[channels] Matrix failed to start: ${e.message}`);
565
+ }
566
+ } else if (id === "nostr") {
567
+ const privateKeyHex = chCfg?.privateKeyHex || process.env.NOSTR_PRIVATE_KEY;
568
+ const relays = chCfg?.relays || (process.env.NOSTR_RELAYS || "wss://relay.damus.io,wss://nos.lol").split(",");
569
+ if (!privateKeyHex || !Array.isArray(relays) || relays.length === 0) continue;
570
+ try {
571
+ const { NostrConnector } = await Promise.resolve().then(() => require("./connector-BiiSJpx3.js"));
572
+ const conn = new NostrConnector({
573
+ privateKeyHex,
574
+ relays,
575
+ dmPolicy,
576
+ allowFrom: allowFromArr,
577
+ approvedPairings: [],
578
+ pendingPairings: {}
579
+ });
580
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "nostr"));
581
+ await conn.connect();
582
+ connectors.push({ stop: async () => {
583
+ conn.disconnect();
584
+ } });
585
+ } catch (e) {
586
+ console.error(`[channels] Nostr failed to start: ${e.message}`);
587
+ }
588
+ } else if (id === "line") {
589
+ const channelAccessToken = chCfg?.channelAccessToken || chCfg?.token || process.env.LINE_CHANNEL_ACCESS_TOKEN;
590
+ const channelSecret = chCfg?.channelSecret || process.env.LINE_CHANNEL_SECRET;
591
+ const tokenFile = chCfg?.tokenFile;
592
+ const secretFile = chCfg?.secretFile;
593
+ const hasCredentials = channelAccessToken && channelSecret || tokenFile && secretFile;
594
+ if (!hasCredentials) continue;
595
+ try {
596
+ const { LINEConnector } = await Promise.resolve().then(() => require("./connector-Tky_qS_K.js"));
597
+ const conn = new LINEConnector({
598
+ ...channelAccessToken ? { channelAccessToken } : {},
599
+ ...channelSecret ? { channelSecret } : {},
600
+ ...tokenFile ? { tokenFile } : {},
601
+ ...secretFile ? { secretFile } : {},
602
+ ...chCfg?.webhookPath ? { webhookPath: chCfg.webhookPath } : {},
603
+ ...chCfg?.mediaMaxMb != null ? { mediaMaxMb: Number(chCfg.mediaMaxMb) } : {},
604
+ dmPolicy,
605
+ allowFrom: allowFromArr,
606
+ groupPolicy: chCfg?.groupPolicy || "allowlist",
607
+ groupAllowFrom: Array.isArray(chCfg?.groupAllowFrom) ? chCfg.groupAllowFrom : [],
608
+ groups: chCfg?.groups || {},
609
+ approvedPairings: [],
610
+ pendingPairings: {}
611
+ });
612
+ conn.on("message", async (msg) => {
613
+ const send = (id$1, t) => msg.replyToken ? conn.replyMessage(msg.replyToken, t) : conn.pushMessage(String(id$1), t);
614
+ await handleMsg({
615
+ chatId: msg.chatId,
616
+ text: msg.text
617
+ }, { sendMessage: send }, "line");
618
+ });
619
+ await conn.connect();
620
+ webhookConnectors["line"] = {
621
+ handleWebhook: (body, opts$1) => conn.handleWebhook(body, opts$1?.signature ?? ""),
622
+ verifyWebhook: void 0
623
+ };
624
+ connectors.push({ stop: async () => {
625
+ conn.disconnect();
626
+ } });
627
+ } catch (e) {
628
+ console.error(`[channels] LINE failed to start: ${e.message}`);
629
+ }
630
+ } else if (id === "feishu" || id === "lark") {
631
+ const appId = chCfg?.appId || process.env.FEISHU_APP_ID;
632
+ const appSecret = chCfg?.appSecret || process.env.FEISHU_APP_SECRET;
633
+ if (!appId || !appSecret) continue;
634
+ try {
635
+ const { FeishuConnector } = await Promise.resolve().then(() => require("./connector-BDmwwaVc.js"));
636
+ const conn = new FeishuConnector({
637
+ appId,
638
+ appSecret,
639
+ dmPolicy,
640
+ allowFrom: allowFromArr,
641
+ approvedPairings: [],
642
+ pendingPairings: {}
643
+ });
644
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "feishu"));
645
+ await conn.connect();
646
+ const feishuHandler = {
647
+ handleWebhook: async (body) => {
648
+ const ch = conn.handleChallenge?.(body);
649
+ if (ch) return ch;
650
+ await conn.handleWebhook(body);
651
+ },
652
+ verifyWebhook: void 0
653
+ };
654
+ webhookConnectors["feishu"] = feishuHandler;
655
+ if (id === "lark") webhookConnectors["lark"] = feishuHandler;
656
+ connectors.push({ stop: async () => {
657
+ conn.disconnect();
658
+ } });
659
+ } catch (e) {
660
+ console.error(`[channels] Feishu failed to start: ${e.message}`);
661
+ }
662
+ } else if (id === "msteams" || id === "teams") {
663
+ const appId = chCfg?.appId || process.env.MSTEAMS_APP_ID;
664
+ const appPassword = chCfg?.appPassword || chCfg?.password || process.env.MSTEAMS_APP_PASSWORD;
665
+ if (!appId || !appPassword) continue;
666
+ try {
667
+ const { MSTeamsConnector } = await Promise.resolve().then(() => require("./connector-BAM-08NN.js"));
668
+ const conn = new MSTeamsConnector({
669
+ appId,
670
+ appPassword,
671
+ dmPolicy,
672
+ allowFrom: allowFromArr,
673
+ approvedPairings: [],
674
+ pendingPairings: {}
675
+ });
676
+ conn.on("message", (msg) => {
677
+ const m = msg;
678
+ const send = (id$1, t) => conn.reply(m.serviceUrl, String(id$1), m.activity, t);
679
+ handleMsg(msg, { sendMessage: send }, "msteams");
680
+ });
681
+ await conn.connect();
682
+ webhookConnectors["msteams"] = {
683
+ handleWebhook: (body) => conn.handleWebhook(body),
684
+ verifyWebhook: void 0
685
+ };
686
+ connectors.push({ stop: async () => {
687
+ conn.disconnect();
688
+ } });
689
+ } catch (e) {
690
+ console.error(`[channels] MS Teams failed to start: ${e.message}`);
691
+ }
692
+ } else if (id === "bluebubbles" || id === "imessage") {
693
+ const serverUrl = chCfg?.serverUrl || process.env.BLUEBUBBLES_SERVER_URL;
694
+ const password = chCfg?.password || process.env.BLUEBUBBLES_PASSWORD;
695
+ if (!serverUrl || !password) continue;
696
+ try {
697
+ const { BlueBubblesConnector } = await Promise.resolve().then(() => require("./connector-BC8FIVu4.js"));
698
+ const conn = new BlueBubblesConnector({
699
+ serverUrl,
700
+ password,
701
+ dmPolicy,
702
+ allowFrom: allowFromArr,
703
+ approvedPairings: [],
704
+ pendingPairings: {}
705
+ });
706
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "bluebubbles"));
707
+ await conn.connect();
708
+ connectors.push({ stop: async () => {
709
+ conn.disconnect();
710
+ } });
711
+ } catch (e) {
712
+ console.error(`[channels] BlueBubbles failed to start: ${e.message}`);
713
+ }
714
+ } else if (id === "imessage-native" && process.platform === "darwin") try {
715
+ const { IMessageNativeConnector } = await Promise.resolve().then(() => require("./connector-BGjbBy69.js"));
716
+ const cliPath = chCfg?.cliPath || process.env.IMSG_PATH;
717
+ const dbPath = chCfg?.dbPath;
718
+ const conn = new IMessageNativeConnector({
719
+ ...cliPath ? { cliPath } : {},
720
+ ...dbPath ? { dbPath } : {},
721
+ dmPolicy,
722
+ allowFrom: allowFromArr,
723
+ approvedPairings: [],
724
+ pendingPairings: {}
725
+ });
726
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "imessage-native"));
727
+ await conn.connect();
728
+ connectors.push({ stop: async () => {
729
+ conn.disconnect();
730
+ } });
731
+ } catch (e) {
732
+ console.error(`[channels] imessage-native failed: ${e.message}. Install imsg (github.com/steipete/imsg) and grant Full Disk Access + Automation.`);
733
+ }
734
+ else if (id === "instagram") {
735
+ const pageAccessToken = chCfg?.pageAccessToken || chCfg?.token || process.env.INSTAGRAM_PAGE_ACCESS_TOKEN;
736
+ const instagramAccountId = chCfg?.instagramAccountId || chCfg?.instagramAccountID || process.env.INSTAGRAM_ACCOUNT_ID;
737
+ const verifyToken = chCfg?.verifyToken || process.env.INSTAGRAM_VERIFY_TOKEN || "hyperclaw";
738
+ if (!pageAccessToken || !instagramAccountId) continue;
739
+ try {
740
+ const { InstagramConnector } = await Promise.resolve().then(() => require("./connector-DAnRJ0oP.js"));
741
+ const conn = new InstagramConnector({
742
+ pageAccessToken,
743
+ instagramAccountId,
744
+ verifyToken,
745
+ dmPolicy,
746
+ allowFrom: allowFromArr,
747
+ approvedPairings: [],
748
+ pendingPairings: {}
749
+ });
750
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "instagram"));
751
+ await conn.connect();
752
+ webhookConnectors["instagram"] = {
753
+ handleWebhook: (body) => conn.handleWebhook(body),
754
+ verifyWebhook: (mode, token, challenge) => conn.verifyWebhook(mode, token, challenge)
755
+ };
756
+ connectors.push({ stop: async () => {
757
+ conn.disconnect();
758
+ } });
759
+ } catch (e) {
760
+ console.error(`[channels] Instagram failed: ${e.message}`);
761
+ }
762
+ } else if (id === "messenger") {
763
+ const pageAccessToken = chCfg?.pageAccessToken || chCfg?.token || process.env.MESSENGER_PAGE_ACCESS_TOKEN;
764
+ const verifyToken = chCfg?.verifyToken || process.env.MESSENGER_VERIFY_TOKEN || "hyperclaw";
765
+ const appSecret = chCfg?.appSecret || process.env.MESSENGER_APP_SECRET;
766
+ const pageId = chCfg?.pageId || chCfg?.page_id || process.env.MESSENGER_PAGE_ID;
767
+ if (!pageAccessToken || !verifyToken || !appSecret || !pageId) continue;
768
+ try {
769
+ const { MessengerConnector } = await Promise.resolve().then(() => require("./connector-Dih6dUPP.js"));
770
+ const conn = new MessengerConnector({
771
+ pageAccessToken,
772
+ verifyToken,
773
+ appSecret,
774
+ pageId,
775
+ dmPolicy,
776
+ allowFrom: allowFromArr,
777
+ approvedPairings: [],
778
+ pendingPairings: {}
779
+ });
780
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "messenger"));
781
+ await conn.connect();
782
+ webhookConnectors["messenger"] = {
783
+ handleWebhook: async (body, opts$1) => {
784
+ await conn.handleWebhook(body, opts$1?.signature ?? "");
785
+ },
786
+ verifyWebhook: (mode, token, challenge) => conn.verifyWebhook(mode, token, challenge)
787
+ };
788
+ connectors.push({ stop: async () => {
789
+ conn.disconnect();
790
+ } });
791
+ } catch (e) {
792
+ console.error(`[channels] Messenger failed: ${e.message}`);
793
+ }
794
+ } else if (id === "twitter") {
795
+ const bearerToken = chCfg?.bearerToken || process.env.TWITTER_BEARER_TOKEN;
796
+ const apiKey = chCfg?.apiKey || process.env.TWITTER_API_KEY;
797
+ const apiSecret = chCfg?.apiSecret || process.env.TWITTER_API_SECRET;
798
+ const accessToken = chCfg?.accessToken || process.env.TWITTER_ACCESS_TOKEN;
799
+ const accessTokenSecret = chCfg?.accessTokenSecret || process.env.TWITTER_ACCESS_TOKEN_SECRET;
800
+ if (!bearerToken || !apiKey || !apiSecret || !accessToken || !accessTokenSecret) continue;
801
+ try {
802
+ const { TwitterConnector } = await Promise.resolve().then(() => require("./connector-CjtZIEDj.js"));
803
+ const conn = new TwitterConnector({
804
+ bearerToken,
805
+ apiKey,
806
+ apiSecret,
807
+ accessToken,
808
+ accessTokenSecret,
809
+ dmPolicy,
810
+ allowFrom: allowFromArr,
811
+ approvedPairings: [],
812
+ pendingPairings: {}
813
+ });
814
+ conn.on("message", (msg) => handleMsg(msg, wrap({ sendMessage: (id$1, t) => conn.sendDM(id$1, t) }), "twitter"));
815
+ await conn.connect();
816
+ webhookConnectors["twitter"] = {
817
+ handleWebhook: (body) => conn.handleWebhook(body),
818
+ verifyWebhook: (mode, token) => conn.handleCRC ? conn.handleCRC(token) : null
819
+ };
820
+ connectors.push({ stop: async () => {
821
+ conn.disconnect();
822
+ } });
823
+ } catch (e) {
824
+ console.error(`[channels] Twitter failed: ${e.message}`);
825
+ }
826
+ } else if (id === "viber") {
827
+ const authToken$1 = chCfg?.authToken || chCfg?.token || process.env.VIBER_AUTH_TOKEN;
828
+ const botName = chCfg?.botName || chCfg?.bot_name || "HyperClaw";
829
+ const webhookUrl = chCfg?.webhookUrl || process.env.VIBER_WEBHOOK_URL || `${baseUrl}/webhook/viber`;
830
+ if (!authToken$1) continue;
831
+ try {
832
+ const { ViberConnector } = await Promise.resolve().then(() => require("./connector-DqTH_tPX.js"));
833
+ const conn = new ViberConnector({
834
+ authToken: authToken$1,
835
+ botName,
836
+ webhookUrl,
837
+ dmPolicy,
838
+ allowFrom: allowFromArr,
839
+ approvedPairings: [],
840
+ pendingPairings: {}
841
+ });
842
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "viber"));
843
+ await conn.connect();
844
+ webhookConnectors["viber"] = {
845
+ handleWebhook: async (body, opts$1) => {
846
+ await conn.handleWebhook(body, opts$1?.signature ?? "");
847
+ },
848
+ verifyWebhook: void 0
849
+ };
850
+ connectors.push({ stop: async () => {
851
+ conn.disconnect();
852
+ } });
853
+ } catch (e) {
854
+ console.error(`[channels] Viber failed: ${e.message}`);
855
+ }
856
+ } else if (id === "zalo-personal") {
857
+ const cookie = chCfg?.cookie || process.env.ZALO_PERSONAL_COOKIE;
858
+ if (!cookie) continue;
859
+ try {
860
+ const { ZaloPersonalConnector } = await Promise.resolve().then(() => require("./connector-BfXky0L3.js"));
861
+ const conn = new ZaloPersonalConnector({
862
+ cookie,
863
+ dmPolicy,
864
+ allowFrom: allowFromArr,
865
+ approvedPairings: [],
866
+ pendingPairings: {}
867
+ });
868
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "zalo-personal"));
869
+ await conn.connect();
870
+ connectors.push({ stop: async () => {
871
+ conn.disconnect();
872
+ } });
873
+ } catch (e) {
874
+ console.error(`[channels] Zalo Personal failed: ${e.message}`);
875
+ }
876
+ } else if (id === "zalo") {
877
+ const botToken = chCfg?.botToken || chCfg?.token || process.env.ZALO_BOT_TOKEN;
878
+ const tokenFile = chCfg?.tokenFile;
879
+ const hasAccounts = chCfg?.accounts && Object.keys(chCfg.accounts).length > 0;
880
+ if (!botToken && !tokenFile && !hasAccounts) continue;
881
+ try {
882
+ const { ZaloConnector } = await Promise.resolve().then(() => require("./connector-B3v0qcXg.js"));
883
+ const conn = new ZaloConnector({
884
+ ...botToken ? { botToken } : {},
885
+ ...tokenFile ? { tokenFile } : {},
886
+ dmPolicy: dmPolicy ?? "pairing",
887
+ allowFrom: allowFromArr,
888
+ groupPolicy: chCfg?.groupPolicy || "allowlist",
889
+ groupAllowFrom: Array.isArray(chCfg?.groupAllowFrom) ? chCfg.groupAllowFrom : [],
890
+ ...chCfg?.webhookUrl ? { webhookUrl: chCfg.webhookUrl } : {},
891
+ ...chCfg?.webhookSecret ? { webhookSecret: chCfg.webhookSecret } : {},
892
+ ...chCfg?.webhookPath ? { webhookPath: chCfg.webhookPath } : {},
893
+ mediaMaxMb: chCfg?.mediaMaxMb ? Number(chCfg.mediaMaxMb) : void 0,
894
+ ...chCfg?.proxy ? { proxy: chCfg.proxy } : {},
895
+ accounts: chCfg?.accounts || {},
896
+ approvedPairings: [],
897
+ pendingPairings: {},
898
+ pendingPairingTs: {}
899
+ });
900
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "zalo"));
901
+ await conn.connect();
902
+ if (chCfg?.webhookUrl) {
903
+ const wPath = chCfg?.webhookPath || new URL(chCfg.webhookUrl).pathname || "/zalo-webhook";
904
+ webhookConnectors[wPath] = {
905
+ handleWebhook: async (body, opts$1) => {
906
+ const secret = opts$1?.secret || opts$1?.signature || "";
907
+ await conn.handleWebhook(body, secret);
908
+ },
909
+ verifyWebhook: void 0
910
+ };
911
+ webhookConnectors["zalo"] = webhookConnectors[wPath];
912
+ }
913
+ connectors.push({ stop: async () => {
914
+ conn.disconnect();
915
+ } });
916
+ } catch (e) {
917
+ console.error(`[channels] Zalo failed to start: ${e.message}`);
918
+ }
919
+ } else if (id === "email") {
920
+ const imapHost = chCfg?.imapHost || process.env.EMAIL_IMAP_HOST;
921
+ const imapPort = chCfg?.imapPort ?? parseInt(process.env.EMAIL_IMAP_PORT || "993", 10);
922
+ const smtpHost = chCfg?.smtpHost || process.env.EMAIL_SMTP_HOST;
923
+ const smtpPort = chCfg?.smtpPort ?? parseInt(process.env.EMAIL_SMTP_PORT || "587", 10);
924
+ const username = chCfg?.username || process.env.EMAIL_USERNAME;
925
+ const password = chCfg?.password || process.env.EMAIL_PASSWORD;
926
+ if (!imapHost || !smtpHost || !username || !password) continue;
927
+ try {
928
+ const { EmailConnector } = await Promise.resolve().then(() => require("./connector-D8Kelee0.js"));
929
+ const conn = new EmailConnector({
930
+ imapHost,
931
+ imapPort,
932
+ smtpHost,
933
+ smtpPort,
934
+ username,
935
+ password,
936
+ pollIntervalMs: 3e4,
937
+ inboxFolder: "INBOX",
938
+ markAsRead: true,
939
+ subjectPrefix: "",
940
+ fromAllowlist: allowFromArr
941
+ });
942
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "email"));
943
+ await conn.connect();
944
+ emailConnectorRef = conn;
945
+ webhookConnectors["gmail-pubsub"] = {
946
+ handleWebhook: async (body) => {
947
+ try {
948
+ const json = JSON.parse(body || "{}");
949
+ if (json.message?.data) emailConnectorRef?.triggerPoll?.();
950
+ } catch {}
951
+ },
952
+ verifyWebhook: void 0
953
+ };
954
+ connectors.push({ stop: async () => {
955
+ conn.disconnect();
956
+ emailConnectorRef = null;
957
+ delete webhookConnectors["gmail-pubsub"];
958
+ } });
959
+ } catch (e) {
960
+ console.error(`[channels] Email failed to start: ${e.message}`);
961
+ }
962
+ } else if (id === "sms") {
963
+ const accountSid = chCfg?.accountSid || process.env.TWILIO_ACCOUNT_SID;
964
+ const authToken$1 = chCfg?.authToken || process.env.TWILIO_AUTH_TOKEN;
965
+ const fromNumber = chCfg?.fromNumber || process.env.TWILIO_FROM_NUMBER;
966
+ if (!accountSid || !authToken$1 || !fromNumber) continue;
967
+ try {
968
+ const { SMSConnector } = await Promise.resolve().then(() => require("./connector-C1HSoUyk.js"));
969
+ const conn = new SMSConnector({
970
+ accountSid,
971
+ authToken: authToken$1,
972
+ fromNumber,
973
+ dmPolicy,
974
+ allowFrom: allowFromArr,
975
+ approvedPairings: [],
976
+ pendingPairings: {}
977
+ });
978
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "sms"));
979
+ await conn.connect();
980
+ webhookConnectors["sms"] = {
981
+ handleWebhook: (body, opts$1) => conn.handleWebhook(body, opts$1?.twilioSignature ?? "", opts$1?.webhookUrl ?? ""),
982
+ verifyWebhook: void 0
983
+ };
984
+ connectors.push({ stop: async () => {
985
+ conn.disconnect();
986
+ } });
987
+ } catch (e) {
988
+ console.error(`[channels] SMS failed to start: ${e.message}`);
989
+ }
990
+ } else if (id === "whatsapp-baileys") try {
991
+ const { WhatsAppBaileysConnector } = await Promise.resolve().then(() => require("./connector-DtR5GGTX.js"));
992
+ const conn = new WhatsAppBaileysConnector({
993
+ dmPolicy,
994
+ allowFrom: allowFromArr,
995
+ approvedPairings: [],
996
+ pendingPairings: {}
997
+ });
998
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "whatsapp-baileys"));
999
+ await conn.connect();
1000
+ connectors.push({ stop: () => {
1001
+ conn.disconnect();
1002
+ return Promise.resolve();
1003
+ } });
1004
+ } catch (e) {
1005
+ console.error(`[channels] WhatsApp Baileys failed: ${e.message}. Install: npm install @whiskeysockets/baileys`);
1006
+ }
1007
+ else if (id === "whatsapp") {
1008
+ const phoneNumberId = chCfg?.phoneNumberId || process.env.WHATSAPP_PHONE_NUMBER_ID;
1009
+ const accessToken = chCfg?.accessToken || chCfg?.token || process.env.WHATSAPP_ACCESS_TOKEN;
1010
+ const verifyToken = chCfg?.verifyToken || process.env.WHATSAPP_VERIFY_TOKEN || "hyperclaw-verify";
1011
+ if (!phoneNumberId || !accessToken) continue;
1012
+ try {
1013
+ const { WhatsAppConnector } = await Promise.resolve().then(() => require("./connector-5N0-X_xs.js"));
1014
+ const conn = new WhatsAppConnector({
1015
+ phoneNumberId,
1016
+ accessToken,
1017
+ verifyToken,
1018
+ dmPolicy,
1019
+ allowFrom: allowFromArr
1020
+ });
1021
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "whatsapp"));
1022
+ await conn.connect();
1023
+ webhookConnectors["whatsapp"] = {
1024
+ handleWebhook: (body) => conn.handleWebhook(body),
1025
+ verifyWebhook: (mode, token, challenge) => conn.verifyWebhook(mode, token, challenge)
1026
+ };
1027
+ connectors.push({ stop: () => {
1028
+ conn.disconnect();
1029
+ return Promise.resolve();
1030
+ } });
1031
+ } catch (e) {
1032
+ console.error(`[channels] WhatsApp failed to start: ${e.message}`);
1033
+ }
1034
+ } else if (id === "irc") {
1035
+ const server = chCfg?.server || process.env.IRC_SERVER;
1036
+ const nick = chCfg?.nick || process.env.IRC_NICK || "hyperclaw";
1037
+ const channels = (chCfg?.channels || process.env.IRC_CHANNELS || "").split(",").filter(Boolean).map((c) => c.trim());
1038
+ if (!server) continue;
1039
+ try {
1040
+ const { IrcConnector } = await Promise.resolve().then(() => require("./connector-BO2SRzfG.js"));
1041
+ const conn = new IrcConnector({
1042
+ server,
1043
+ nick,
1044
+ channels,
1045
+ dmPolicy,
1046
+ allowFrom: allowFromArr
1047
+ });
1048
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "irc"));
1049
+ await conn.connect();
1050
+ connectors.push({ stop: async () => {
1051
+ await conn.disconnect();
1052
+ } });
1053
+ } catch (e) {
1054
+ console.error(`[channels] IRC failed to start: ${e.message}`);
1055
+ }
1056
+ } else if (id === "mattermost") {
1057
+ const serverUrl = chCfg?.serverUrl || process.env.MATTERMOST_SERVER_URL;
1058
+ const token = chCfg?.token || process.env.MATTERMOST_TOKEN;
1059
+ const webhookToken = chCfg?.webhookToken || process.env.MATTERMOST_WEBHOOK_TOKEN;
1060
+ if (!serverUrl || !token || !webhookToken) continue;
1061
+ try {
1062
+ const { MattermostConnector } = await Promise.resolve().then(() => require("./connector-Ck6JtOsX.js"));
1063
+ const conn = new MattermostConnector({
1064
+ baseUrl: serverUrl,
1065
+ botToken: token,
1066
+ dmPolicy,
1067
+ allowFrom: allowFromArr,
1068
+ approvedPairings: [],
1069
+ pendingPairings: {}
1070
+ });
1071
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "mattermost"));
1072
+ await conn.connect();
1073
+ webhookConnectors["mattermost"] = {
1074
+ handleWebhook: async (body, _opts) => {
1075
+ await conn.handleWebhook(body, webhookToken ?? "");
1076
+ },
1077
+ verifyWebhook: void 0
1078
+ };
1079
+ connectors.push({ stop: async () => {
1080
+ conn.disconnect();
1081
+ } });
1082
+ } catch (e) {
1083
+ console.error(`[channels] Mattermost failed to start: ${e.message}`);
1084
+ }
1085
+ } else if (id === "gchat" || id === "google-chat") try {
1086
+ const { GoogleChatConnector } = await Promise.resolve().then(() => require("./connector-BnDmIhIu.js"));
1087
+ const conn = new GoogleChatConnector({ baseUrl });
1088
+ await conn.connect();
1089
+ webhookConnectors["gchat"] = {
1090
+ handleWebhook: (body) => conn.handleWebhook(body),
1091
+ verifyWebhook: void 0
1092
+ };
1093
+ if (id === "google-chat") webhookConnectors["google-chat"] = webhookConnectors["gchat"];
1094
+ connectors.push({ stop: async () => {
1095
+ conn.disconnect();
1096
+ } });
1097
+ } catch (e) {
1098
+ console.error(`[channels] Google Chat failed to start: ${e.message}`);
1099
+ }
1100
+ else if (id === "nextcloud-talk" || id === "nextcloud") {
1101
+ const baseUrl$1 = chCfg?.baseUrl || chCfg?.serverUrl || chCfg?.token || process.env.NEXTCLOUD_TALK_BASE_URL;
1102
+ const botSecret = chCfg?.botSecret || process.env.NEXTCLOUD_TALK_BOT_SECRET;
1103
+ const botSecretFile = chCfg?.botSecretFile;
1104
+ if (!baseUrl$1 || !botSecret && !botSecretFile) continue;
1105
+ try {
1106
+ const { NextcloudTalkConnector } = await Promise.resolve().then(() => require("./connector-Ci9glMD-.js"));
1107
+ const conn = new NextcloudTalkConnector({
1108
+ baseUrl: baseUrl$1,
1109
+ ...botSecret ? { botSecret } : {},
1110
+ ...botSecretFile ? { botSecretFile } : {},
1111
+ ...chCfg?.apiUser ? { apiUser: chCfg.apiUser } : {},
1112
+ ...chCfg?.apiPassword ? { apiPassword: chCfg.apiPassword } : {},
1113
+ ...chCfg?.apiPasswordFile ? { apiPasswordFile: chCfg.apiPasswordFile } : {},
1114
+ ...chCfg?.webhookPort != null ? { webhookPort: Number(chCfg.webhookPort) } : {},
1115
+ ...chCfg?.webhookHost ? { webhookHost: chCfg.webhookHost } : {},
1116
+ ...chCfg?.webhookPath ? { webhookPath: chCfg.webhookPath } : {},
1117
+ ...chCfg?.webhookPublicUrl ? { webhookPublicUrl: chCfg.webhookPublicUrl } : {},
1118
+ dmPolicy: dmPolicy ?? "pairing",
1119
+ allowFrom: allowFromArr,
1120
+ groupPolicy: chCfg?.groupPolicy || "allowlist",
1121
+ groupAllowFrom: Array.isArray(chCfg?.groupAllowFrom) ? chCfg.groupAllowFrom : [],
1122
+ rooms: chCfg?.rooms || {},
1123
+ ...chCfg?.textChunkLimit != null ? { textChunkLimit: Number(chCfg.textChunkLimit) } : {},
1124
+ ...chCfg?.chunkMode ? { chunkMode: chCfg.chunkMode } : {},
1125
+ ...chCfg?.mediaMaxMb != null ? { mediaMaxMb: Number(chCfg.mediaMaxMb) } : {},
1126
+ approvedPairings: [],
1127
+ pendingPairings: {}
1128
+ });
1129
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "nextcloud-talk"));
1130
+ await conn.connect();
1131
+ connectors.push({ stop: async () => {
1132
+ conn.disconnect();
1133
+ } });
1134
+ } catch (e) {
1135
+ console.error(`[channels] Nextcloud Talk failed to start: ${e.message}`);
1136
+ }
1137
+ } else if (id === "synology-chat") {
1138
+ const incomingWebhookUrl = chCfg?.incomingWebhookUrl || chCfg?.token || process.env.SYNOLOGY_CHAT_WEBHOOK_URL;
1139
+ const webhookToken = chCfg?.webhookToken || process.env.SYNOLOGY_CHAT_OUTGOING_TOKEN;
1140
+ const webhookPort = chCfg?.webhookPort || process.env.SYNOLOGY_CHAT_WEBHOOK_PORT;
1141
+ if (!incomingWebhookUrl) continue;
1142
+ try {
1143
+ const { SynologyChatConnector } = await Promise.resolve().then(() => require("./connector-ZSc3oTTy.js"));
1144
+ const conn = new SynologyChatConnector({
1145
+ incomingUrl: incomingWebhookUrl,
1146
+ token: webhookToken,
1147
+ ...webhookPort ? { webhookPort: Number(webhookPort) } : {}
1148
+ });
1149
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "synology-chat"));
1150
+ await conn.connect();
1151
+ connectors.push({ stop: async () => {
1152
+ conn.disconnect();
1153
+ } });
1154
+ } catch (e) {
1155
+ console.error(`[channels] Synology Chat failed to start: ${e.message}`);
1156
+ }
1157
+ } else if (id === "twitch") {
1158
+ const username = chCfg?.username || process.env.TWITCH_BOT_USERNAME;
1159
+ const oauthToken = chCfg?.oauthToken || chCfg?.token || process.env.TWITCH_OAUTH_TOKEN;
1160
+ const channels = String(chCfg?.channels || process.env.TWITCH_CHANNELS || "").split(",").map((c) => c.trim()).filter(Boolean);
1161
+ if (!username || !oauthToken || channels.length === 0) continue;
1162
+ try {
1163
+ const { TwitchConnector } = await Promise.resolve().then(() => require("./connector-CRl-iidy.js"));
1164
+ const conn = new TwitchConnector({
1165
+ username,
1166
+ oauthToken,
1167
+ channels,
1168
+ dmPolicy,
1169
+ allowFrom: allowFromArr,
1170
+ commandPrefix: chCfg?.commandPrefix,
1171
+ whispers: chCfg?.whispers,
1172
+ modsBypass: chCfg?.modsBypass,
1173
+ approvedPairings: [],
1174
+ pendingPairings: {}
1175
+ });
1176
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "twitch"));
1177
+ await conn.connect();
1178
+ connectors.push({ stop: async () => {
1179
+ await conn.disconnect();
1180
+ } });
1181
+ } catch (e) {
1182
+ console.error(`[channels] Twitch failed to start: ${e.message}`);
1183
+ }
1184
+ } else if (id === "tlon") {
1185
+ const shipUrl = chCfg?.shipUrl || process.env.TLON_SHIP_URL;
1186
+ const ship = chCfg?.ship || process.env.TLON_SHIP;
1187
+ const code = chCfg?.code || chCfg?.token || process.env.TLON_CODE;
1188
+ const group = chCfg?.group || process.env.TLON_GROUP;
1189
+ if (!shipUrl || !ship || !code) continue;
1190
+ try {
1191
+ const { TlonConnector } = await Promise.resolve().then(() => require("./connector-CKQHZOXg.js"));
1192
+ const conn = new TlonConnector({
1193
+ url: shipUrl,
1194
+ ship,
1195
+ code,
1196
+ ...group ? { group } : {}
1197
+ });
1198
+ conn.on("message", (msg) => handleMsg(msg, wrap(conn), "tlon"));
1199
+ await conn.connect();
1200
+ connectors.push({ stop: async () => {
1201
+ conn.disconnect();
1202
+ } });
1203
+ } catch (e) {
1204
+ console.error(`[channels] Tlon failed to start: ${e.message}`);
1205
+ }
1206
+ }
1207
+ }
1208
+ return {
1209
+ stop: async () => {
1210
+ for (const c of connectors) await c.stop().catch(() => {});
1211
+ connectors.length = 0;
1212
+ emailConnectorRef = null;
1213
+ Object.keys(webhookConnectors).forEach((k) => delete webhookConnectors[k]);
1214
+ },
1215
+ handleWebhook: async (channelId, body, opts$1) => {
1216
+ const h = webhookConnectors[channelId];
1217
+ if (h) {
1218
+ const result = await h.handleWebhook(body, opts$1);
1219
+ return result;
1220
+ }
1221
+ },
1222
+ verifyWebhook: (channelId, mode, token, challenge) => {
1223
+ const h = webhookConnectors[channelId];
1224
+ return h?.verifyWebhook ? h.verifyWebhook(mode, token, challenge) : null;
1225
+ }
1226
+ };
1227
+ }
1228
+ function postChat(baseUrl, message, source, authToken, agentId, sessionKey) {
1229
+ return new Promise((resolve, reject) => {
1230
+ const body = { message };
1231
+ if (agentId) body.agentId = agentId;
1232
+ if (sessionKey) body.sessionKey = sessionKey;
1233
+ const payload = JSON.stringify(body);
1234
+ const headers = {
1235
+ "Content-Type": "application/json",
1236
+ "Content-Length": String(Buffer.byteLength(payload))
1237
+ };
1238
+ if (source) headers["X-HyperClaw-Source"] = source;
1239
+ if (authToken) headers["Authorization"] = `Bearer ${authToken}`;
1240
+ const url = new URL(`${baseUrl}/api/chat`);
1241
+ const req = http.default.request({
1242
+ hostname: url.hostname,
1243
+ port: url.port || 80,
1244
+ path: url.pathname,
1245
+ method: "POST",
1246
+ headers
1247
+ }, (res) => {
1248
+ let data = "";
1249
+ res.on("data", (c) => data += c);
1250
+ res.on("end", () => {
1251
+ try {
1252
+ const j = JSON.parse(data);
1253
+ if (j.error) reject(new Error(j.error));
1254
+ else resolve(j.response || "");
1255
+ } catch {
1256
+ reject(new Error("Invalid response"));
1257
+ }
1258
+ });
1259
+ });
1260
+ req.on("error", reject);
1261
+ req.setTimeout(6e4, () => {
1262
+ req.destroy();
1263
+ reject(new Error("Timeout"));
1264
+ });
1265
+ req.write(payload);
1266
+ req.end();
1267
+ });
1268
+ }
1269
+
1270
+ //#endregion
1271
+ exports.startChannelRunners = startChannelRunners;