hyperclaw 5.0.0 → 5.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/LICENSE +2 -1
  2. package/README.md +449 -99
  3. package/dist/a2ui-protocol-Gzm29Gaw.js +75 -0
  4. package/dist/agents-routing-Biy5ew4a.js +4 -0
  5. package/dist/agents-routing-CL3HQNoM.js +327 -0
  6. package/dist/api-keys-guide-CGn5BSF7.js +149 -0
  7. package/dist/api-keys-guide-ChbThbPj.js +149 -0
  8. package/dist/audit-BJohI_vC.js +441 -0
  9. package/dist/audit-NPIMmOSq.js +441 -0
  10. package/dist/bounty-tools-BUqUKjt0.js +211 -0
  11. package/dist/bounty-tools-CY_i91DU.js +211 -0
  12. package/dist/browser-tools-CxJY6pAn.js +5 -0
  13. package/dist/browser-tools-JZ9ji6AW.js +179 -0
  14. package/dist/chat-qVuqhlPu.js +258 -0
  15. package/dist/claw-tasks-B-8RRMdq.js +80 -0
  16. package/dist/claw-tasks-Cyzdbhz_.js +80 -0
  17. package/dist/connector-1x1rCBHz.js +162 -0
  18. package/dist/connector-B4jeCULG.js +305 -0
  19. package/dist/connector-B7qngfkT.js +286 -0
  20. package/dist/connector-B8BK0GBo.js +531 -0
  21. package/dist/connector-BE9eJs8-.js +182 -0
  22. package/dist/connector-BEe-DTGQ.js +189 -0
  23. package/dist/connector-BU7p5ZgB.js +167 -0
  24. package/dist/connector-BUzzq7Ij.js +568 -0
  25. package/dist/connector-BpDqLgnW.js +419 -0
  26. package/dist/connector-BpW88ut2.js +189 -0
  27. package/dist/connector-Bxv-gy8U.js +167 -0
  28. package/dist/connector-Bz14zcJv.js +213 -0
  29. package/dist/connector-C1zP5-5q.js +85 -0
  30. package/dist/connector-CAcpcovF.js +498 -0
  31. package/dist/connector-CJgVjS58.js +181 -0
  32. package/dist/connector-Cf53D6qV.js +425 -0
  33. package/dist/connector-CyHmlbNz.js +508 -0
  34. package/dist/connector-D22mJGVu.js +340 -0
  35. package/dist/connector-D6RtMmlL.js +225 -0
  36. package/dist/connector-D9EnT8A4.js +280 -0
  37. package/dist/connector-DNDwIh37.js +239 -0
  38. package/dist/connector-Di27MeO4.js +350 -0
  39. package/dist/connector-Do0BPiHt.js +194 -0
  40. package/dist/connector-DvLwOfJy.js +192 -0
  41. package/dist/connector-DvU83NSq.js +181 -0
  42. package/dist/connector-DxskpDc_.js +173 -0
  43. package/dist/connector-byy3eISx.js +552 -0
  44. package/dist/connector-vV89hsyd.js +218 -0
  45. package/dist/cost-tracker-Ca1UPZ33.js +103 -0
  46. package/dist/cost-tracker-fnaj_6M9.js +103 -0
  47. package/dist/credentials-store-BxijEirw.js +77 -0
  48. package/dist/credentials-store-CA8UtK0T.js +77 -0
  49. package/dist/credentials-store-CPkVO6-z.js +4 -0
  50. package/dist/credentials-store-Cm7DH-kh.js +4 -0
  51. package/dist/cron-tasks-L0mz1yyU.js +82 -0
  52. package/dist/cron-tasks-_pqQCmxc.js +82 -0
  53. package/dist/daemon-7ViroziB.js +5 -0
  54. package/dist/daemon-BfyKmZhr.js +318 -0
  55. package/dist/daemon-CNyunwkR.js +5 -0
  56. package/dist/daemon-CindY8OK.js +318 -0
  57. package/dist/delivery-DVHmv1IR.js +4 -0
  58. package/dist/delivery-DgiZcJBp.js +4 -0
  59. package/dist/delivery-DpMX0Yyc.js +95 -0
  60. package/dist/delivery-otAU4alM.js +95 -0
  61. package/dist/destructive-gate-CA0DtA5K.js +101 -0
  62. package/dist/destructive-gate-DZt71UZR.js +101 -0
  63. package/dist/developer-keys-Cnd1kswV.js +127 -0
  64. package/dist/developer-keys-DENo3ZA6.js +8 -0
  65. package/dist/doctor-Dgjoc3DG.js +230 -0
  66. package/dist/doctor-RwsOhtAl.js +6 -0
  67. package/dist/engine-B0kLfRL0.js +256 -0
  68. package/dist/engine-BJUpRUOv.js +7 -0
  69. package/dist/engine-D_VeoZHw.js +305 -0
  70. package/dist/engine-JjRnhlsE.js +7 -0
  71. package/dist/env-resolve-17ekEU6p.js +10 -0
  72. package/dist/env-resolve-BFJXWl94.js +115 -0
  73. package/dist/env-resolve-Z2XF6leB.js +115 -0
  74. package/dist/env-resolve-bDYssfih.js +10 -0
  75. package/dist/extraction-tools-DbxnxIco.js +5 -0
  76. package/dist/extraction-tools-Dg7AHS35.js +91 -0
  77. package/dist/form_data-CGAy4HE0.js +8657 -0
  78. package/dist/gmail-watch-setup-C3uSWznp.js +40 -0
  79. package/dist/health-DUjluWHQ.js +6 -0
  80. package/dist/health-DVfkpUQW.js +152 -0
  81. package/dist/heartbeat-engine-CrgL4mrP.js +83 -0
  82. package/dist/heartbeat-engine-Ut6pXBD6.js +83 -0
  83. package/dist/hub-9LaKnLjY.js +6 -0
  84. package/dist/hub-BO6bj8Yj.js +515 -0
  85. package/dist/hub-Bu52YZqW.js +6 -0
  86. package/dist/hub-CfwUz9YW.js +515 -0
  87. package/dist/hyperclawbot-BrcoYLOp.js +505 -0
  88. package/dist/hyperclawbot-CBiDSKsa.js +505 -0
  89. package/dist/inference-0mlFQqIm.js +922 -0
  90. package/dist/inference-DHR82Gh7.js +6 -0
  91. package/dist/inference-DhA8jpfH.js +2692 -0
  92. package/dist/inference-SzqFe_nk.js +6 -0
  93. package/dist/knowledge-graph-BrYpSgxW.js +131 -0
  94. package/dist/knowledge-graph-DE5lSF02.js +131 -0
  95. package/dist/loader-9JqY6Nlq.js +4 -0
  96. package/dist/loader-BkDi8MD9.js +400 -0
  97. package/dist/loader-Cjdd1kw4.js +400 -0
  98. package/dist/loader-DI2qDRPC.js +4 -0
  99. package/dist/logger-Cp8wC7F8.js +83 -0
  100. package/dist/logger-DCT2l9GV.js +83 -0
  101. package/dist/manager-3cq3DydI.js +4 -0
  102. package/dist/manager-B2Gls5RG.js +218 -0
  103. package/dist/manager-BUrFrPuq.js +117 -0
  104. package/dist/manager-Bi9UYyVR.js +105 -0
  105. package/dist/manager-Biz9ixWJ.js +40 -0
  106. package/dist/manager-CBUHJiY7.js +6 -0
  107. package/dist/manager-CVLLaKmq.js +218 -0
  108. package/dist/manager-CWNSML5D.js +117 -0
  109. package/dist/manager-SJe9gt-q.js +4 -0
  110. package/dist/mcp-CUoTCMw-.js +139 -0
  111. package/dist/mcp-loader-BIz-450x.js +94 -0
  112. package/dist/mcp-loader-CvxRDtPC.js +94 -0
  113. package/dist/memory-OL77OMOr.js +270 -0
  114. package/dist/memory-auto-CpQHZlEJ.js +306 -0
  115. package/dist/memory-auto-D-L2q21G.js +306 -0
  116. package/dist/memory-auto-DTcy5VBy.js +5 -0
  117. package/dist/memory-auto-Z6LCf-iK.js +5 -0
  118. package/dist/memory-gUi4VaIf.js +4 -0
  119. package/dist/memory-integration-B8RSN4pr.js +91 -0
  120. package/dist/memory-integration-g2vxwgoE.js +91 -0
  121. package/dist/moltbook-B-40gQOL.js +81 -0
  122. package/dist/moltbook-Cl8cQfxJ.js +81 -0
  123. package/dist/node-TWxRm84k.js +222 -0
  124. package/dist/nodes-registry-C9dCFwjh.js +52 -0
  125. package/dist/nodes-registry-DKRtsbNg.js +52 -0
  126. package/dist/oauth-flow-CeaaGAz0.js +150 -0
  127. package/dist/oauth-flow-JCfporKq.js +150 -0
  128. package/dist/oauth-provider-4R0EJlsT.js +110 -0
  129. package/dist/oauth-provider-B4dzn56l.js +110 -0
  130. package/dist/observability-CDZmeHfa.js +89 -0
  131. package/dist/observability-nZ3CBIxG.js +89 -0
  132. package/dist/onboard-BBBWcfhp.js +10 -0
  133. package/dist/onboard-BVOtKQdh.js +3641 -0
  134. package/dist/onboard-Bw28IRQ3.js +4070 -0
  135. package/dist/onboard-CGNIw27w.js +11 -0
  136. package/dist/orchestrator-BovkM63z.js +6 -0
  137. package/dist/orchestrator-CcKx1Ovk.js +189 -0
  138. package/dist/orchestrator-DSbpkP1X.js +189 -0
  139. package/dist/orchestrator-DcFfDLTX.js +6 -0
  140. package/dist/osint-B4_m3VHQ.js +277 -0
  141. package/dist/osint-B6BZKQAD.js +277 -0
  142. package/dist/pairing-B6RArWhD.js +196 -0
  143. package/dist/pairing-BsQ08DLq.js +4 -0
  144. package/dist/pc-access-B0KocJNe.js +819 -0
  145. package/dist/pc-access-DkzmugZ7.js +8 -0
  146. package/dist/pending-approval-BgNjjuI2.js +22 -0
  147. package/dist/pending-approval-C_HkX1QL.js +22 -0
  148. package/dist/providers-DxiamZSL.js +5 -0
  149. package/dist/providers-Dy15rDb7.js +657 -0
  150. package/dist/reminders-store-CzUY0zYx.js +58 -0
  151. package/dist/renderer-ANNfXsHn.js +225 -0
  152. package/dist/rules-BSQwwAYC.js +103 -0
  153. package/dist/run-main.js +142 -132
  154. package/dist/runner-BHRSOPEU.js +1271 -0
  155. package/dist/runner-CJFJUtPm.js +1271 -0
  156. package/dist/sdk/index.js +2 -2
  157. package/dist/sdk/index.mjs +2 -2
  158. package/dist/security--oQObeJO.js +4 -0
  159. package/dist/security-wBOg0TA8.js +73 -0
  160. package/dist/server-Brl_HQUB.js +1255 -0
  161. package/dist/server-CbTTpB5m.js +1255 -0
  162. package/dist/server-DP_bPzvI.js +4 -0
  163. package/dist/server-DhfipkwN.js +4 -0
  164. package/dist/session-store-B09r5HgB.js +5 -0
  165. package/dist/session-store-DCTQIVur.js +113 -0
  166. package/dist/sessions-tools-BdlN6Pb6.js +95 -0
  167. package/dist/sessions-tools-JVLDKSJ_.js +5 -0
  168. package/dist/skill-loader-B5oeliGu.js +7 -0
  169. package/dist/skill-loader-Wf3brNOj.js +160 -0
  170. package/dist/skill-runtime-BGlvly2s.js +102 -0
  171. package/dist/skill-runtime-BXWd-Ktf.js +102 -0
  172. package/dist/skill-runtime-DhL2T76p.js +5 -0
  173. package/dist/skill-runtime-jgklm02e.js +5 -0
  174. package/dist/src-BbPa6Q8p.js +63 -0
  175. package/dist/src-BeXtfkK2.js +458 -0
  176. package/dist/src-Bhybpk1J.js +63 -0
  177. package/dist/src-CGQjRI4N.js +20 -0
  178. package/dist/src-DMJ4-uqk.js +458 -0
  179. package/dist/sub-agent-tools-CmE345s_.js +39 -0
  180. package/dist/sub-agent-tools-DHY-4WWM.js +39 -0
  181. package/dist/theme-D0smfC_l.js +8 -0
  182. package/dist/theme-DajRRZbA.js +180 -0
  183. package/dist/tool-policy-DZvF8xlQ.js +189 -0
  184. package/dist/tool-policy-DgNqFWYn.js +189 -0
  185. package/dist/tts-elevenlabs-C06nUxMK.js +61 -0
  186. package/dist/tts-elevenlabs-JeFaGNJU.js +61 -0
  187. package/dist/update-check-BVEqHhFY.js +83 -0
  188. package/dist/update-check-w4XuxVl7.js +81 -0
  189. package/dist/vision-JOtOS1Br.js +121 -0
  190. package/dist/vision-fky3elEo.js +121 -0
  191. package/dist/vision-tools-C8B3776g.js +5 -0
  192. package/dist/vision-tools-CB28ZCO_.js +5 -0
  193. package/dist/vision-tools-dwn9p4el.js +51 -0
  194. package/dist/vision-tools-vPPwQ-0N.js +51 -0
  195. package/dist/voice-transcription-B6RtplmN.js +138 -0
  196. package/dist/voice-transcription-DBo5hXmu.js +138 -0
  197. package/dist/website-watch-tools-B-jRAeTe.js +139 -0
  198. package/dist/website-watch-tools-BC9xAL67.js +5 -0
  199. package/package.json +1 -1
@@ -0,0 +1,552 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ const chalk = require_chunk.__toESM(require("chalk"));
3
+ const fs_extra = require_chunk.__toESM(require("fs-extra"));
4
+ const path = require_chunk.__toESM(require("path"));
5
+ const os = require_chunk.__toESM(require("os"));
6
+ const crypto = require_chunk.__toESM(require("crypto"));
7
+ const https = require_chunk.__toESM(require("https"));
8
+ const events = require_chunk.__toESM(require("events"));
9
+
10
+ //#region extensions/slack/src/connector.ts
11
+ const STATE_BASE = path.default.join(os.default.homedir(), ".hyperclaw");
12
+ const DEFAULT_CHUNK = 3e3;
13
+ function slackApi(token, method, body = {}) {
14
+ return new Promise((resolve, reject) => {
15
+ const payload = JSON.stringify(body);
16
+ const req = https.default.request({
17
+ hostname: "slack.com",
18
+ port: 443,
19
+ path: `/api/${method}`,
20
+ method: "POST",
21
+ headers: {
22
+ Authorization: `Bearer ${token}`,
23
+ "Content-Type": "application/json; charset=utf-8",
24
+ "Content-Length": Buffer.byteLength(payload)
25
+ }
26
+ }, (res) => {
27
+ let data = "";
28
+ res.on("data", (c) => data += c);
29
+ res.on("end", () => {
30
+ try {
31
+ const r = JSON.parse(data);
32
+ if (!r.ok) reject(new Error(r.error || "Slack API error"));
33
+ else resolve(r);
34
+ } catch {
35
+ reject(new Error("Slack: invalid JSON"));
36
+ }
37
+ });
38
+ });
39
+ req.on("error", reject);
40
+ req.setTimeout(3e4, () => {
41
+ req.destroy();
42
+ reject(new Error("Slack API timeout"));
43
+ });
44
+ req.write(payload);
45
+ req.end();
46
+ });
47
+ }
48
+ function chunkText(text, limit, mode) {
49
+ if (mode === "newline") {
50
+ const paras = text.split(/\n\n+/);
51
+ const chunks$1 = [];
52
+ let cur = "";
53
+ for (const p of paras) if ((cur + "\n\n" + p).length > limit && cur) {
54
+ chunks$1.push(cur.trim());
55
+ cur = p;
56
+ } else cur = cur ? cur + "\n\n" + p : p;
57
+ if (cur) chunks$1.push(cur.trim());
58
+ return chunks$1.filter(Boolean);
59
+ }
60
+ const chunks = [];
61
+ for (let i = 0; i < text.length; i += limit) chunks.push(text.slice(i, i + limit));
62
+ return chunks.length ? chunks : [""];
63
+ }
64
+ function generateCode() {
65
+ return Array.from({ length: 6 }, () => "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"[Math.floor(Math.random() * 32)]).join("");
66
+ }
67
+ var SlackAccount = class extends events.EventEmitter {
68
+ cfg;
69
+ accountId;
70
+ botUserId = "";
71
+ teamName = "";
72
+ running = false;
73
+ wsReconnectDelay = 1e3;
74
+ constructor(accountId, cfg) {
75
+ super();
76
+ this.accountId = accountId;
77
+ this.cfg = {
78
+ mode: "socket",
79
+ userTokenReadOnly: true,
80
+ textChunkLimit: DEFAULT_CHUNK,
81
+ chunkMode: "length",
82
+ streaming: "partial",
83
+ nativeStreaming: true,
84
+ dmPolicy: "pairing",
85
+ allowFrom: [],
86
+ groupPolicy: "allowlist",
87
+ channels: {},
88
+ replyToMode: "off",
89
+ thread: {
90
+ historyScope: "thread",
91
+ inheritParent: false,
92
+ initialHistoryLimit: 20
93
+ },
94
+ actions: {
95
+ messages: true,
96
+ reactions: true,
97
+ pins: true,
98
+ memberInfo: true,
99
+ emojiList: true
100
+ },
101
+ ...cfg
102
+ };
103
+ }
104
+ async authenticate() {
105
+ const token = this.cfg.botToken;
106
+ const auth = await slackApi(token, "auth.test");
107
+ this.botUserId = auth.user_id;
108
+ this.teamName = auth.team;
109
+ console.log(chalk.default.green(` 💼 Slack [${this.accountId}]: @${auth.user} in ${auth.team}`));
110
+ }
111
+ async connect() {
112
+ await this.loadState();
113
+ await this.authenticate();
114
+ this.running = true;
115
+ this.emit("connected", {
116
+ userId: this.botUserId,
117
+ team: this.teamName,
118
+ accountId: this.accountId
119
+ });
120
+ const mode = this.cfg.mode ?? "socket";
121
+ if (mode === "socket") this.connectSocketMode();
122
+ }
123
+ disconnect() {
124
+ this.running = false;
125
+ }
126
+ async connectSocketMode() {
127
+ if (!this.cfg.appToken) {
128
+ console.error(`[slack:${this.accountId}] Socket Mode requires appToken (xapp-...)`);
129
+ return;
130
+ }
131
+ let WebSocketImpl;
132
+ try {
133
+ WebSocketImpl = await import("ws");
134
+ } catch {
135
+ console.error(`[slack:${this.accountId}] ws package not found — install: npm i ws`);
136
+ return;
137
+ }
138
+ while (this.running) try {
139
+ const resp = await slackApi(this.cfg.appToken, "apps.connections.open");
140
+ const wsUrl = resp.url;
141
+ await new Promise((resolve) => {
142
+ const WS = WebSocketImpl.default ?? WebSocketImpl;
143
+ const ws = new WS(wsUrl);
144
+ ws.on("open", () => {
145
+ this.wsReconnectDelay = 1e3;
146
+ });
147
+ ws.on("message", (raw) => {
148
+ let envelope;
149
+ try {
150
+ envelope = JSON.parse(raw.toString());
151
+ } catch {
152
+ return;
153
+ }
154
+ if (envelope.envelope_id) ws.send(JSON.stringify({ envelope_id: envelope.envelope_id }));
155
+ this.handleSocketEnvelope(envelope);
156
+ });
157
+ ws.on("close", () => resolve());
158
+ ws.on("error", () => resolve());
159
+ });
160
+ if (!this.running) break;
161
+ await new Promise((r) => setTimeout(r, this.wsReconnectDelay));
162
+ this.wsReconnectDelay = Math.min(this.wsReconnectDelay * 2, 3e4);
163
+ } catch (e) {
164
+ if (this.running) {
165
+ console.log(chalk.default.yellow(` ⚠ Slack [${this.accountId}] socket: ${e.message}`));
166
+ await new Promise((r) => setTimeout(r, this.wsReconnectDelay));
167
+ this.wsReconnectDelay = Math.min(this.wsReconnectDelay * 2, 3e4);
168
+ }
169
+ }
170
+ }
171
+ async handleSocketEnvelope(envelope) {
172
+ const type = envelope.type || "";
173
+ switch (type) {
174
+ case "hello": break;
175
+ case "disconnect": break;
176
+ case "events_api": {
177
+ const payload = envelope.payload || {};
178
+ if (payload.type === "event_callback") await this.handleEvent(payload.event, payload);
179
+ break;
180
+ }
181
+ case "slash_commands": {
182
+ const p = envelope.payload || {};
183
+ if (p.command || p.user_id) await this.handleSlashCommand(p);
184
+ break;
185
+ }
186
+ case "block_actions":
187
+ case "interactive": {
188
+ const p = envelope.payload || {};
189
+ this.emit("interaction", {
190
+ accountId: this.accountId,
191
+ type,
192
+ payload: p
193
+ });
194
+ break;
195
+ }
196
+ }
197
+ }
198
+ async handleWebhook(body, signature, timestamp) {
199
+ if (!this.verifySignature(body, signature, timestamp)) {
200
+ console.log(chalk.default.yellow(` ⚠ Slack [${this.accountId}]: invalid signature`));
201
+ return null;
202
+ }
203
+ let payload;
204
+ try {
205
+ payload = JSON.parse(body);
206
+ } catch {
207
+ return null;
208
+ }
209
+ if (payload.type === "url_verification") return payload.challenge;
210
+ if (payload.type === "event_callback") await this.handleEvent(payload.event, payload);
211
+ return null;
212
+ }
213
+ verifySignature(body, signature, timestamp) {
214
+ if (!this.cfg.signingSecret) return false;
215
+ const ts = parseInt(timestamp);
216
+ if (Math.abs(Date.now() / 1e3 - ts) > 300) return false;
217
+ const baseString = `v0:${timestamp}:${body}`;
218
+ const hash = "v0=" + crypto.default.createHmac("sha256", this.cfg.signingSecret).update(baseString).digest("hex");
219
+ try {
220
+ return crypto.default.timingSafeEqual(Buffer.from(hash), Buffer.from(signature));
221
+ } catch {
222
+ return false;
223
+ }
224
+ }
225
+ async handleEvent(event, _outer) {
226
+ if (!event) return;
227
+ if (event.bot_id || event.user === this.botUserId) return;
228
+ const evType = event.type || "";
229
+ if (["reaction_added", "reaction_removed"].includes(evType)) {
230
+ this.emit("system_event", {
231
+ accountId: this.accountId,
232
+ type: evType,
233
+ event
234
+ });
235
+ return;
236
+ }
237
+ if ([
238
+ "member_joined_channel",
239
+ "member_left_channel",
240
+ "channel_rename",
241
+ "pin_added",
242
+ "pin_removed"
243
+ ].includes(evType)) {
244
+ this.emit("system_event", {
245
+ accountId: this.accountId,
246
+ type: evType,
247
+ event
248
+ });
249
+ return;
250
+ }
251
+ if (evType !== "message" && evType !== "app_mention") return;
252
+ if (!event.text || !event.user || !event.channel) return;
253
+ if (event.subtype && event.subtype !== "file_share") return;
254
+ const channelType = event.channel_type || "";
255
+ const isDM = channelType === "im";
256
+ const isGroup = channelType === "mpim";
257
+ const isChannel = !isDM && !isGroup;
258
+ const isAppMention = evType === "app_mention";
259
+ const threadTs = event.thread_ts;
260
+ const ts = event.ts || "";
261
+ const text = event.text.replace(/<@[A-Z0-9]+>/g, "").trim();
262
+ if (isDM) {
263
+ const dmEnabled = this.cfg.dm?.enabled !== false;
264
+ if (!dmEnabled) return;
265
+ const allowed = await this.checkDMPolicy(event.user, event.channel, text, ts);
266
+ if (!allowed) return;
267
+ } else if (isGroup) {
268
+ const groupEnabled = this.cfg.dm?.groupEnabled === true;
269
+ if (!groupEnabled) return;
270
+ const groupChannels = this.cfg.dm?.groupChannels;
271
+ if (groupChannels?.length && !groupChannels.includes(event.channel)) return;
272
+ } else if (!this.checkChannelPolicy(event.channel, event.user, text, isAppMention)) return;
273
+ this.addReaction(this.resolveAckReaction(), event.channel, ts);
274
+ const chatType = isDM ? "direct" : isGroup ? "group" : "channel";
275
+ const replyToMode = this.resolveReplyToMode(chatType);
276
+ this.emit("message", {
277
+ channelId: "slack",
278
+ accountId: this.accountId,
279
+ chatId: event.channel,
280
+ from: event.user,
281
+ text,
282
+ ts,
283
+ threadTs,
284
+ isDM,
285
+ isGroup,
286
+ isChannel,
287
+ chatType,
288
+ replyToMode
289
+ });
290
+ }
291
+ async handleSlashCommand(payload) {
292
+ const text = [payload.command, payload.text].filter(Boolean).join(" ");
293
+ const userId = payload.user_id || "";
294
+ const channelId = payload.channel_id || "";
295
+ if (!userId || !channelId) return;
296
+ this.emit("message", {
297
+ channelId: "slack",
298
+ accountId: this.accountId,
299
+ chatId: channelId,
300
+ from: userId,
301
+ text,
302
+ isDM: false,
303
+ isSlashCommand: true,
304
+ ephemeral: this.cfg.slashCommand?.ephemeral !== false
305
+ });
306
+ }
307
+ async checkDMPolicy(userId, channelId, text, ts) {
308
+ const policy = this.cfg.dm?.policy ?? this.cfg.dmPolicy ?? "pairing";
309
+ const allowFrom = this.cfg.allowFrom ?? this.cfg.dm?.allowFrom ?? [];
310
+ switch (policy) {
311
+ case "disabled": return false;
312
+ case "open": return true;
313
+ case "allowlist":
314
+ if (allowFrom.includes(userId) || allowFrom.includes("*")) return true;
315
+ await this.sendMessage(channelId, "HyperClaw: Not on allowlist.");
316
+ return false;
317
+ case "pairing": {
318
+ if (this.cfg.approvedPairings.includes(userId)) return true;
319
+ const upper = text.trim().toUpperCase().match(/[A-Z0-9]{6}/)?.[0];
320
+ if (upper && this.cfg.pendingPairings[upper]) {
321
+ this.cfg.approvedPairings.push(userId);
322
+ delete this.cfg.pendingPairings[upper];
323
+ await this.saveState();
324
+ await this.sendMessage(channelId, "Paired! You can now send messages.");
325
+ this.emit("pairing:approved", {
326
+ userId,
327
+ channelId: "slack",
328
+ accountId: this.accountId
329
+ });
330
+ return true;
331
+ }
332
+ const code = generateCode();
333
+ this.cfg.pendingPairings[code] = userId;
334
+ await this.saveState();
335
+ await this.sendMessage(channelId, `*HyperClaw Pairing*\n\nCode: \`${code}\`\nApprove: \`hyperclaw pairing approve slack ${code}\``);
336
+ return false;
337
+ }
338
+ }
339
+ return false;
340
+ }
341
+ checkChannelPolicy(channelId, userId, text, isAppMention) {
342
+ const policy = this.cfg.groupPolicy ?? "allowlist";
343
+ if (policy === "disabled") return false;
344
+ const chCfg = this.cfg.channels?.[channelId] || {};
345
+ if (policy === "open") {
346
+ if (chCfg.allowFrom?.length && !chCfg.allowFrom.includes(userId)) return false;
347
+ if (chCfg.users?.length && !chCfg.users.includes(userId)) return false;
348
+ return true;
349
+ }
350
+ if (!this.cfg.channels?.[channelId]) return isAppMention;
351
+ if (chCfg.allowFrom?.length && !chCfg.allowFrom.includes(userId)) return false;
352
+ if (chCfg.users?.length && !chCfg.users.includes(userId)) return false;
353
+ if (chCfg.requireMention !== false && !isAppMention) return false;
354
+ return true;
355
+ }
356
+ resolveAckReaction() {
357
+ return this.cfg.ackReaction ?? "";
358
+ }
359
+ resolveTypingReaction() {
360
+ return this.cfg.typingReaction ?? "";
361
+ }
362
+ resolveReplyToMode(chatType) {
363
+ const byType = this.cfg.replyToModeByChatType;
364
+ if (byType) {
365
+ if (chatType === "direct" && byType.direct) return byType.direct;
366
+ if (chatType === "group" && byType.group) return byType.group;
367
+ if (chatType === "channel" && byType.channel) return byType.channel;
368
+ }
369
+ return this.cfg.replyToMode ?? "off";
370
+ }
371
+ async addReaction(emoji, channel, timestamp) {
372
+ if (!emoji || !channel || !timestamp) return;
373
+ const name = emoji.replace(/:/g, "");
374
+ await slackApi(this.cfg.botToken, "reactions.add", {
375
+ channel,
376
+ timestamp,
377
+ name
378
+ }).catch(() => {});
379
+ }
380
+ async removeReaction(emoji, channel, timestamp) {
381
+ if (!emoji || !channel || !timestamp) return;
382
+ const name = emoji.replace(/:/g, "");
383
+ await slackApi(this.cfg.botToken, "reactions.remove", {
384
+ channel,
385
+ timestamp,
386
+ name
387
+ }).catch(() => {});
388
+ }
389
+ async sendMessage(channel, text, threadTs, opts = {}) {
390
+ const limit = this.cfg.textChunkLimit ?? DEFAULT_CHUNK;
391
+ const mode = this.cfg.chunkMode ?? "length";
392
+ const chunks = chunkText(text, limit, mode);
393
+ const replyThread = threadTs && this.resolveReplyToMode("channel") !== "off";
394
+ for (const chunk of chunks) {
395
+ const payload = {
396
+ channel,
397
+ text: chunk,
398
+ mrkdwn: true,
399
+ ...replyThread ? { thread_ts: threadTs } : {}
400
+ };
401
+ if (opts.ephemeral && opts.userId) await slackApi(this.cfg.botToken, "chat.postEphemeral", {
402
+ ...payload,
403
+ user: opts.userId
404
+ });
405
+ else await slackApi(this.cfg.botToken, "chat.postMessage", payload);
406
+ }
407
+ }
408
+ async sendTyping(channelId) {}
409
+ async startStream(channel, threadTs) {
410
+ if (this.cfg.streaming === "off" || !this.cfg.nativeStreaming) return null;
411
+ try {
412
+ const r = await slackApi(this.cfg.botToken, "chat.startStream", {
413
+ channel,
414
+ ...threadTs ? { thread_ts: threadTs } : {}
415
+ });
416
+ return r.stream_ts || null;
417
+ } catch {
418
+ return null;
419
+ }
420
+ }
421
+ async appendStream(streamTs, text) {
422
+ await slackApi(this.cfg.botToken, "chat.appendStream", {
423
+ stream_ts: streamTs,
424
+ text
425
+ }).catch(() => {});
426
+ }
427
+ async stopStream(streamTs, text) {
428
+ await slackApi(this.cfg.botToken, "chat.stopStream", {
429
+ stream_ts: streamTs,
430
+ text
431
+ }).catch(() => {});
432
+ }
433
+ async setAssistantStatus(channelId, threadTs, status) {
434
+ await slackApi(this.cfg.botToken, "assistant.threads.setStatus", {
435
+ channel_id: channelId,
436
+ thread_ts: threadTs,
437
+ status
438
+ }).catch(() => {});
439
+ }
440
+ approvePairing(code) {
441
+ const upper = code.toUpperCase();
442
+ if (!this.cfg.pendingPairings[upper]) return false;
443
+ this.cfg.approvedPairings.push(this.cfg.pendingPairings[upper]);
444
+ delete this.cfg.pendingPairings[upper];
445
+ this.saveState();
446
+ return true;
447
+ }
448
+ async openDM(userId) {
449
+ const r = await slackApi(this.cfg.botToken, "conversations.open", { users: userId });
450
+ return r.channel.id;
451
+ }
452
+ async sendDM(userId, text) {
453
+ const channelId = await this.openDM(userId);
454
+ await this.sendMessage(channelId, text);
455
+ }
456
+ stateFile() {
457
+ return path.default.join(STATE_BASE, `slack-state-${this.accountId}.json`);
458
+ }
459
+ async loadState() {
460
+ try {
461
+ const s = await fs_extra.default.readJson(this.stateFile());
462
+ if (s.p) this.cfg.pendingPairings = s.p;
463
+ if (s.a) this.cfg.approvedPairings = s.a;
464
+ } catch {}
465
+ }
466
+ async saveState() {
467
+ await fs_extra.default.ensureDir(STATE_BASE);
468
+ await fs_extra.default.writeJson(this.stateFile(), {
469
+ p: this.cfg.pendingPairings,
470
+ a: this.cfg.approvedPairings
471
+ }, { spaces: 2 });
472
+ }
473
+ isRunning() {
474
+ return this.running;
475
+ }
476
+ };
477
+ var SlackConnector = class extends events.EventEmitter {
478
+ config;
479
+ accounts = [];
480
+ constructor(config) {
481
+ super();
482
+ this.config = config;
483
+ }
484
+ async connect() {
485
+ const sharedState = {
486
+ approvedPairings: this.config.approvedPairings ?? [],
487
+ pendingPairings: this.config.pendingPairings ?? {}
488
+ };
489
+ const accountEntries = Object.entries(this.config.accounts || {});
490
+ if (accountEntries.length === 0) {
491
+ const acct = new SlackAccount("default", {
492
+ ...this.config,
493
+ ...sharedState
494
+ });
495
+ this.wire(acct);
496
+ await acct.connect();
497
+ this.accounts.push(acct);
498
+ } else for (const [id, acctCfg] of accountEntries) {
499
+ const merged = {
500
+ ...this.config,
501
+ ...acctCfg,
502
+ botToken: acctCfg.botToken || this.config.botToken,
503
+ ...sharedState
504
+ };
505
+ if (!merged.botToken) {
506
+ console.error(`[slack] Account "${id}" has no botToken — skipping`);
507
+ continue;
508
+ }
509
+ const acct = new SlackAccount(id, merged);
510
+ this.wire(acct);
511
+ try {
512
+ await acct.connect();
513
+ this.accounts.push(acct);
514
+ } catch (e) {
515
+ console.error(`[slack] Account "${id}" failed: ${e.message}`);
516
+ }
517
+ }
518
+ }
519
+ wire(acct) {
520
+ acct.on("message", (msg) => this.emit("message", msg));
521
+ acct.on("connected", (info) => this.emit("connected", info));
522
+ acct.on("pairing:approved", (info) => this.emit("pairing:approved", info));
523
+ acct.on("system_event", (ev) => this.emit("system_event", ev));
524
+ acct.on("interaction", (ev) => this.emit("interaction", ev));
525
+ }
526
+ async sendMessage(channel, text, threadTs) {
527
+ const acct = this.accounts[0];
528
+ if (!acct) throw new Error("Slack: no connected account");
529
+ await acct.sendMessage(channel, text, threadTs);
530
+ }
531
+ async sendTyping(channelId) {}
532
+ async handleWebhook(body, signature, timestamp) {
533
+ for (const acct of this.accounts) {
534
+ const r = await acct.handleWebhook(body, signature, timestamp);
535
+ if (r != null) return r;
536
+ }
537
+ return null;
538
+ }
539
+ approvePairing(code) {
540
+ return this.accounts.some((a) => a.approvePairing(code));
541
+ }
542
+ disconnect() {
543
+ for (const a of this.accounts) a.disconnect();
544
+ this.accounts = [];
545
+ }
546
+ isRunning() {
547
+ return this.accounts.some((a) => a.isRunning());
548
+ }
549
+ };
550
+
551
+ //#endregion
552
+ exports.SlackConnector = SlackConnector;