hyperclaw 4.0.2 → 5.0.0

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 (134) hide show
  1. package/README.md +54 -3
  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/audit-BaIiyWFu.js +441 -0
  7. package/dist/bounty-tools-DWudyZie.js +211 -0
  8. package/dist/browser-tools-BsTeGMnX.js +5 -0
  9. package/dist/browser-tools-D8_rLe2p.js +179 -0
  10. package/dist/claw-tasks-CgTsiNE8.js +80 -0
  11. package/dist/connector-5N0-X_xs.js +194 -0
  12. package/dist/connector-B3v0qcXg.js +425 -0
  13. package/dist/connector-B8R3iBY1.js +280 -0
  14. package/dist/connector-BAM-08NN.js +189 -0
  15. package/dist/connector-BC8FIVu4.js +181 -0
  16. package/dist/connector-BDmwwaVc.js +213 -0
  17. package/dist/connector-BGjbBy69.js +225 -0
  18. package/dist/connector-BO2SRzfG.js +218 -0
  19. package/dist/connector-BfXky0L3.js +167 -0
  20. package/dist/connector-BiiSJpx3.js +192 -0
  21. package/dist/connector-BnDmIhIu.js +85 -0
  22. package/dist/connector-C1HSoUyk.js +189 -0
  23. package/dist/connector-CKQHZOXg.js +568 -0
  24. package/dist/connector-CRl-iidy.js +239 -0
  25. package/dist/connector-Ci9glMD-.js +340 -0
  26. package/dist/connector-CjtZIEDj.js +181 -0
  27. package/dist/connector-Ck6JtOsX.js +531 -0
  28. package/dist/connector-D8Kelee0.js +286 -0
  29. package/dist/connector-DAnRJ0oP.js +162 -0
  30. package/dist/connector-DXTp5PE8.js +508 -0
  31. package/dist/connector-Dih6dUPP.js +173 -0
  32. package/dist/connector-DqTH_tPX.js +182 -0
  33. package/dist/connector-DrnEiiyP.js +419 -0
  34. package/dist/connector-DtR5GGTX.js +167 -0
  35. package/dist/connector-Tky_qS_K.js +350 -0
  36. package/dist/connector-ZSc3oTTy.js +305 -0
  37. package/dist/connector-sW5yhU1m.js +498 -0
  38. package/dist/connector-u3ICd3Ic.js +552 -0
  39. package/dist/cost-tracker-DD9wtWsr.js +103 -0
  40. package/dist/credentials-store-C6ir0Dae.js +4 -0
  41. package/dist/credentials-store-H13LqOwJ.js +77 -0
  42. package/dist/cron-tasks-Bli7Kzd2.js +82 -0
  43. package/dist/daemon-Bg4GtCmc.js +318 -0
  44. package/dist/daemon-DhmwY8k4.js +5 -0
  45. package/dist/delivery-BmIYy9VQ.js +4 -0
  46. package/dist/delivery-pWUPBp1F.js +95 -0
  47. package/dist/destructive-gate-D6vWOdEl.js +101 -0
  48. package/dist/developer-keys-CPWT7Q6S.js +8 -0
  49. package/dist/developer-keys-DrrcUqFa.js +127 -0
  50. package/dist/doctor-BvCe8BBk.js +230 -0
  51. package/dist/doctor-CxyPLYsJ.js +6 -0
  52. package/dist/engine-CEDSqXfw.js +256 -0
  53. package/dist/engine-Da4JMNpI.js +7 -0
  54. package/dist/env-resolve-CiXbWYwe.js +10 -0
  55. package/dist/env-resolve-CmGWhWXJ.js +115 -0
  56. package/dist/extraction-tools-HOZstZ0y.js +91 -0
  57. package/dist/extraction-tools-m4lmAv7l.js +5 -0
  58. package/dist/form_data-Cz040rio.js +8657 -0
  59. package/dist/gmail-watch-setup-Du7DVV7S.js +40 -0
  60. package/dist/health-B-asI__D.js +6 -0
  61. package/dist/health-Ds2YlpTB.js +152 -0
  62. package/dist/heartbeat-engine-BYT5ayQH.js +83 -0
  63. package/dist/hub-D0XwdjM-.js +515 -0
  64. package/dist/hub-LiD5Iztb.js +6 -0
  65. package/dist/hyperclawbot-zvczQgKx.js +505 -0
  66. package/dist/inference-BKVkBREb.js +6 -0
  67. package/dist/inference-DCXH4Q3x.js +922 -0
  68. package/dist/knowledge-graph-iBG76fvm.js +131 -0
  69. package/dist/loader-CC45xGpC.js +4 -0
  70. package/dist/loader-CnEdOyjT.js +400 -0
  71. package/dist/logger-ybOp7VOC.js +83 -0
  72. package/dist/manager-03ipO9R0.js +105 -0
  73. package/dist/manager-BpDfbDjg.js +117 -0
  74. package/dist/manager-Bxl0sqlh.js +4 -0
  75. package/dist/manager-CrVDn6eN.js +6 -0
  76. package/dist/manager-FCgF1plu.js +218 -0
  77. package/dist/manager-rgCsaWT1.js +40 -0
  78. package/dist/mcp-CfoSU4Uz.js +139 -0
  79. package/dist/mcp-loader-DkRBsLpk.js +94 -0
  80. package/dist/memory-BlHL7JCO.js +4 -0
  81. package/dist/memory-DsS_eFvJ.js +270 -0
  82. package/dist/memory-auto-BkvtSFUw.js +5 -0
  83. package/dist/memory-auto-Bnz_-1wP.js +306 -0
  84. package/dist/memory-integration-cSYkZyEo.js +91 -0
  85. package/dist/moltbook-BtLDZTfM.js +81 -0
  86. package/dist/node-Dw2Gi-cP.js +222 -0
  87. package/dist/nodes-registry-B8dmrlLv.js +52 -0
  88. package/dist/oauth-flow-DQPvMHRH.js +150 -0
  89. package/dist/oauth-provider-Uo4Nib_c.js +110 -0
  90. package/dist/observability-BV-Yx0V9.js +89 -0
  91. package/dist/onboard-0WoDxbv_.js +10 -0
  92. package/dist/onboard-BXNXCQp4.js +4070 -0
  93. package/dist/orchestrator-DmnEvMaL.js +189 -0
  94. package/dist/orchestrator-RI3bpqqc.js +6 -0
  95. package/dist/pairing-6iM27aD8.js +196 -0
  96. package/dist/pairing-dGoiGepK.js +4 -0
  97. package/dist/pc-access-CgCsYrpt.js +8 -0
  98. package/dist/pc-access-_iH2aorG.js +819 -0
  99. package/dist/pending-approval-CUXjysAo.js +22 -0
  100. package/dist/reminders-store-Drjed_-h.js +58 -0
  101. package/dist/renderer-BVQrd0_g.js +225 -0
  102. package/dist/rules-BE4GV6cV.js +103 -0
  103. package/dist/run-main.js +1607 -443
  104. package/dist/runner-DatMMYYE.js +1271 -0
  105. package/dist/sdk/index.js +2 -2
  106. package/dist/sdk/index.mjs +2 -2
  107. package/dist/security-BqNyT4ID.js +4 -0
  108. package/dist/security-tpgqPWWH.js +73 -0
  109. package/dist/server-D4wVHiX9.js +4 -0
  110. package/dist/server-Dh3JlBFB.js +1255 -0
  111. package/dist/session-store-BUiPz0Vv.js +5 -0
  112. package/dist/session-store-is4B6qmD.js +113 -0
  113. package/dist/sessions-tools-CbUTFe4i.js +5 -0
  114. package/dist/sessions-tools-CeqD7iil.js +95 -0
  115. package/dist/skill-loader-BaNLVmJy.js +7 -0
  116. package/dist/skill-loader-HgpF6Vqs.js +159 -0
  117. package/dist/skill-runtime-CJN24QPW.js +102 -0
  118. package/dist/skill-runtime-w1ig_lcw.js +5 -0
  119. package/dist/src-BxPHKO5x.js +63 -0
  120. package/dist/src-DIc-L2IG.js +20 -0
  121. package/dist/src-g_rNx5rh.js +458 -0
  122. package/dist/sub-agent-tools-CHQoHz9c.js +39 -0
  123. package/dist/theme-DcxwcUgZ.js +180 -0
  124. package/dist/theme-cx0fkgWC.js +8 -0
  125. package/dist/tool-policy-CNT-mF2Z.js +189 -0
  126. package/dist/tts-elevenlabs-BRosZv-f.js +61 -0
  127. package/dist/update-check-C2Dz85wJ.js +81 -0
  128. package/dist/vision-BMmiIKy7.js +121 -0
  129. package/dist/vision-tools-DVuYc17I.js +51 -0
  130. package/dist/vision-tools-U3YC4L-g.js +5 -0
  131. package/dist/voice-transcription-B555DbWR.js +138 -0
  132. package/dist/website-watch-tools-DFMrJU-R.js +139 -0
  133. package/dist/website-watch-tools-Du3W5sN7.js +5 -0
  134. package/package.json +1 -1
@@ -0,0 +1,498 @@
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 http = require_chunk.__toESM(require("http"));
8
+ const https = require_chunk.__toESM(require("https"));
9
+ const events = require_chunk.__toESM(require("events"));
10
+
11
+ //#region extensions/matrix/src/connector.ts
12
+ const HC_DIR = path.default.join(os.default.homedir(), ".hyperclaw");
13
+ const CREDS_BASE = path.default.join(HC_DIR, "credentials", "matrix");
14
+ const STATE_BASE = path.default.join(HC_DIR, "matrix", "accounts");
15
+ const DEFAULT_CHUNK = 16e3;
16
+ function matrixReq(homeserver, token, method, apiPath, body, query = {}) {
17
+ return new Promise((resolve, reject) => {
18
+ const url = new URL(homeserver);
19
+ const isHttps = url.protocol === "https:";
20
+ const mod = isHttps ? https.default : http.default;
21
+ const payload = body ? JSON.stringify(body) : null;
22
+ const qs = new URLSearchParams({
23
+ access_token: token,
24
+ ...query
25
+ }).toString();
26
+ const reqPath = `/_matrix/client/v3${apiPath}?${qs}`;
27
+ const req = mod.request({
28
+ hostname: url.hostname,
29
+ port: url.port || (isHttps ? 443 : 80),
30
+ path: reqPath,
31
+ method,
32
+ headers: {
33
+ Authorization: `Bearer ${token}`,
34
+ ...payload ? {
35
+ "Content-Type": "application/json",
36
+ "Content-Length": Buffer.byteLength(payload)
37
+ } : {}
38
+ }
39
+ }, (res) => {
40
+ let data = "";
41
+ res.on("data", (c) => data += c);
42
+ res.on("end", () => {
43
+ try {
44
+ const r = JSON.parse(data);
45
+ if (r.errcode) reject(new Error(r.error || r.errcode));
46
+ else resolve(r);
47
+ } catch {
48
+ reject(new Error("Matrix: invalid JSON response"));
49
+ }
50
+ });
51
+ });
52
+ req.on("error", reject);
53
+ req.setTimeout(6e4, () => {
54
+ req.destroy();
55
+ reject(new Error("Matrix: request timeout"));
56
+ });
57
+ if (payload) req.write(payload);
58
+ req.end();
59
+ });
60
+ }
61
+ function matrixLogin(homeserver, userId, password, deviceName) {
62
+ return new Promise((resolve, reject) => {
63
+ const url = new URL(homeserver);
64
+ const isHttps = url.protocol === "https:";
65
+ const mod = isHttps ? https.default : http.default;
66
+ const body = JSON.stringify({
67
+ type: "m.login.password",
68
+ identifier: {
69
+ type: "m.id.user",
70
+ user: userId.replace(/^@/, "").split(":")[0]
71
+ },
72
+ password,
73
+ ...deviceName ? { initial_device_display_name: deviceName } : {}
74
+ });
75
+ const req = mod.request({
76
+ hostname: url.hostname,
77
+ port: url.port || (isHttps ? 443 : 80),
78
+ path: "/_matrix/client/v3/login",
79
+ method: "POST",
80
+ headers: {
81
+ "Content-Type": "application/json",
82
+ "Content-Length": Buffer.byteLength(body)
83
+ }
84
+ }, (res) => {
85
+ let data = "";
86
+ res.on("data", (c) => data += c);
87
+ res.on("end", () => {
88
+ try {
89
+ resolve(JSON.parse(data));
90
+ } catch {
91
+ reject(new Error("Matrix login: invalid response"));
92
+ }
93
+ });
94
+ });
95
+ req.on("error", reject);
96
+ req.write(body);
97
+ req.end();
98
+ });
99
+ }
100
+ function chunkText(text, limit, mode) {
101
+ if (mode === "newline") {
102
+ const paragraphs = text.split(/\n\n+/);
103
+ const chunks$1 = [];
104
+ let current = "";
105
+ for (const p of paragraphs) if ((current + "\n\n" + p).length > limit && current) {
106
+ chunks$1.push(current.trim());
107
+ current = p;
108
+ } else current = current ? current + "\n\n" + p : p;
109
+ if (current) chunks$1.push(current.trim());
110
+ return chunks$1.filter(Boolean);
111
+ }
112
+ const chunks = [];
113
+ for (let i = 0; i < text.length; i += limit) chunks.push(text.slice(i, i + limit));
114
+ return chunks.length ? chunks : [""];
115
+ }
116
+ var MatrixAccount = class extends events.EventEmitter {
117
+ cfg;
118
+ accountId;
119
+ token = "";
120
+ userId = "";
121
+ running = false;
122
+ nextBatch = null;
123
+ /** room ID → true if it is a DM room (populated from m.direct account data) */
124
+ directRooms = /* @__PURE__ */ new Set();
125
+ /** resolved room alias → room ID cache */
126
+ aliasCache = /* @__PURE__ */ new Map();
127
+ constructor(accountId, cfg) {
128
+ super();
129
+ this.accountId = accountId;
130
+ this.cfg = {
131
+ groupPolicy: "allowlist",
132
+ groupAllowFrom: [],
133
+ groups: {},
134
+ rooms: {},
135
+ threadReplies: "inbound",
136
+ replyToMode: "off",
137
+ textChunkLimit: DEFAULT_CHUNK,
138
+ chunkMode: "length",
139
+ mediaMaxMb: 10,
140
+ autoJoin: "always",
141
+ autoJoinAllowlist: [],
142
+ encryption: false,
143
+ ...cfg,
144
+ dm: {
145
+ policy: cfg.dm?.policy ?? "pairing",
146
+ allowFrom: cfg.dm?.allowFrom ?? []
147
+ }
148
+ };
149
+ }
150
+ async authenticate() {
151
+ const hs = this.cfg.homeserver;
152
+ const credsFile = path.default.join(CREDS_BASE, `${this.accountId}.json`);
153
+ if (this.cfg.accessToken) this.token = this.cfg.accessToken;
154
+ else if (this.cfg.password) {
155
+ let cached = false;
156
+ try {
157
+ const c = await fs_extra.default.readJson(credsFile);
158
+ if (c.homeserver === hs && c.userId === this.cfg.userId && c.accessToken) {
159
+ this.token = c.accessToken;
160
+ cached = true;
161
+ }
162
+ } catch {}
163
+ if (!cached) {
164
+ if (!this.cfg.userId) throw new Error(`Matrix [${this.accountId}]: userId required for password login`);
165
+ const res = await matrixLogin(hs, this.cfg.userId, this.cfg.password, this.cfg.deviceName);
166
+ if (!res.access_token) throw new Error(`Matrix [${this.accountId}]: login failed — ${JSON.stringify(res)}`);
167
+ this.token = res.access_token;
168
+ await fs_extra.default.ensureDir(path.default.dirname(credsFile));
169
+ await fs_extra.default.writeJson(credsFile, {
170
+ homeserver: hs,
171
+ userId: this.cfg.userId,
172
+ accessToken: this.token
173
+ }, { spaces: 2 });
174
+ }
175
+ } else throw new Error(`Matrix [${this.accountId}]: accessToken or (userId + password) required`);
176
+ const whoami = await matrixReq(hs, this.token, "GET", "/account/whoami");
177
+ this.userId = this.cfg.userId || whoami.user_id;
178
+ if (this.cfg.encryption) try {
179
+ const tokenHash = crypto.default.createHash("sha256").update(this.token).digest("hex").slice(0, 12);
180
+ const _cryptoDir = path.default.join(STATE_BASE, this.accountId, `${new URL(hs).hostname}__${this.userId.replace(/[^a-z0-9_.-]/gi, "_")}`, tokenHash, "crypto");
181
+ await import("@matrix-org/matrix-sdk-crypto-nodejs").catch(() => {
182
+ console.log(chalk.default.yellow(` ⚠ Matrix [${this.accountId}]: crypto module not available — E2EE disabled. Run: pnpm rebuild @matrix-org/matrix-sdk-crypto-nodejs`));
183
+ this.cfg.encryption = false;
184
+ });
185
+ } catch {
186
+ this.cfg.encryption = false;
187
+ }
188
+ }
189
+ stateFile() {
190
+ return path.default.join(STATE_BASE, this.accountId, "bot-storage.json");
191
+ }
192
+ async loadState() {
193
+ try {
194
+ const s = await fs_extra.default.readJson(this.stateFile());
195
+ this.nextBatch = s.nextBatch || null;
196
+ if (s.p) this.cfg.pendingPairings = s.p;
197
+ if (s.a) this.cfg.approvedPairings = s.a;
198
+ if (s.directRooms) this.directRooms = new Set(s.directRooms);
199
+ } catch {}
200
+ }
201
+ async saveState() {
202
+ await fs_extra.default.ensureDir(path.default.dirname(this.stateFile()));
203
+ await fs_extra.default.writeJson(this.stateFile(), {
204
+ nextBatch: this.nextBatch,
205
+ p: this.cfg.pendingPairings,
206
+ a: this.cfg.approvedPairings,
207
+ directRooms: [...this.directRooms]
208
+ }, { spaces: 2 });
209
+ }
210
+ async connect() {
211
+ await this.authenticate();
212
+ await this.loadState();
213
+ this.running = true;
214
+ console.log(chalk.default.green(` 🔷 Matrix [${this.accountId}]: ${this.userId} connected`));
215
+ this.emit("connected", {
216
+ userId: this.userId,
217
+ accountId: this.accountId
218
+ });
219
+ this.syncLoop();
220
+ }
221
+ disconnect() {
222
+ this.running = false;
223
+ }
224
+ async syncLoop() {
225
+ while (this.running) try {
226
+ const query = this.nextBatch ? {
227
+ since: this.nextBatch,
228
+ timeout: "30000"
229
+ } : { timeout: "0" };
230
+ const sync = await matrixReq(this.cfg.homeserver, this.token, "GET", "/sync", void 0, query);
231
+ this.nextBatch = sync.next_batch;
232
+ const directEvent = (sync.account_data?.events || []).find((e) => e.type === "m.direct");
233
+ if (directEvent?.content) for (const rooms of Object.values(directEvent.content)) for (const r of rooms) this.directRooms.add(r);
234
+ await this.saveState();
235
+ for (const [roomId] of Object.entries(sync.rooms?.invite || {})) await this.handleInvite(roomId);
236
+ const joinedRooms = sync.rooms?.join || {};
237
+ for (const [roomId, rd] of Object.entries(joinedRooms)) for (const event of rd.timeline?.events || []) {
238
+ if (event.sender === this.userId) continue;
239
+ await this.handleEvent(roomId, event, rd);
240
+ }
241
+ } catch (e) {
242
+ if (this.running) {
243
+ console.log(chalk.default.yellow(` ⚠ Matrix [${this.accountId}]: ${e.message}`));
244
+ await new Promise((r) => setTimeout(r, 5e3));
245
+ }
246
+ }
247
+ }
248
+ async handleInvite(roomId) {
249
+ const autoJoin = this.cfg.autoJoin ?? "always";
250
+ if (autoJoin === "off") return;
251
+ if (autoJoin === "allowlist") {
252
+ const resolved = await this.resolveRoom(roomId);
253
+ const list = this.cfg.autoJoinAllowlist ?? [];
254
+ if (!list.includes(roomId) && !list.includes(resolved)) return;
255
+ }
256
+ try {
257
+ await matrixReq(this.cfg.homeserver, this.token, "POST", `/rooms/${encodeURIComponent(roomId)}/join`, {});
258
+ } catch {}
259
+ }
260
+ async handleEvent(roomId, event, roomData) {
261
+ const isDM = this.directRooms.has(roomId);
262
+ const sender = event.sender || "";
263
+ if (!sender) return;
264
+ let text = "";
265
+ let eventThreadId;
266
+ switch (event.type) {
267
+ case "m.room.message": {
268
+ const msgtype = event.content?.msgtype || "";
269
+ const relatesTo = event.content?.["m.relates_to"];
270
+ eventThreadId = relatesTo?.rel_type === "m.thread" ? relatesTo.event_id : void 0;
271
+ switch (msgtype) {
272
+ case "m.text":
273
+ case "m.notice":
274
+ text = event.content?.body || "";
275
+ break;
276
+ case "m.image":
277
+ case "m.video":
278
+ case "m.audio":
279
+ case "m.file": {
280
+ const mxcUrl = event.content?.url || "";
281
+ const size = event.content?.info?.size || 0;
282
+ const maxBytes = (this.cfg.mediaMaxMb ?? 10) * 1024 * 1024;
283
+ if (size > maxBytes) return;
284
+ text = `[${msgtype.replace("m.", "")}:${mxcUrl}]`;
285
+ break;
286
+ }
287
+ case "m.location":
288
+ text = `[location:${event.content?.geo_uri || ""}]`;
289
+ break;
290
+ default: return;
291
+ }
292
+ break;
293
+ }
294
+ case "org.matrix.msc3381.poll.start":
295
+ case "m.poll.start": {
296
+ const q = event.content?.["org.matrix.msc3381.poll.start"]?.question?.body || event.content?.["m.poll"]?.question?.text || "";
297
+ if (!q) return;
298
+ text = `[poll] ${q}`;
299
+ break;
300
+ }
301
+ case "m.reaction": {
302
+ const key = event.content?.["m.relates_to"]?.key || "";
303
+ const reacted = event.content?.["m.relates_to"]?.event_id || "";
304
+ if (!key) return;
305
+ text = `[reaction:${key}:${reacted}]`;
306
+ break;
307
+ }
308
+ default: return;
309
+ }
310
+ if (!text) return;
311
+ if (isDM) {
312
+ const allowed = await this.checkDMPolicy(sender, text, roomId);
313
+ if (!allowed) return;
314
+ } else if (!this.checkGroupPolicy(roomId, sender, text, roomData)) return;
315
+ this.emit("message", {
316
+ channelId: "matrix",
317
+ accountId: this.accountId,
318
+ chatId: roomId,
319
+ from: sender,
320
+ text,
321
+ threadId: eventThreadId,
322
+ isDM,
323
+ timestamp: new Date(event.origin_server_ts || Date.now()).toISOString()
324
+ });
325
+ }
326
+ async checkDMPolicy(sender, text, roomId) {
327
+ const { policy, allowFrom } = this.cfg.dm;
328
+ switch (policy) {
329
+ case "disabled": return false;
330
+ case "open": return true;
331
+ case "allowlist":
332
+ if (allowFrom.includes(sender) || allowFrom.includes("*")) return true;
333
+ await this.sendMessage(roomId, "HyperClaw: Not on allowlist.");
334
+ return false;
335
+ case "pairing": {
336
+ if (this.cfg.approvedPairings.includes(sender)) return true;
337
+ const upper = text.trim().toUpperCase().match(/[A-Z0-9]{6}/)?.[0];
338
+ if (upper && this.cfg.pendingPairings[upper]) {
339
+ this.cfg.approvedPairings.push(sender);
340
+ delete this.cfg.pendingPairings[upper];
341
+ await this.saveState();
342
+ await this.sendMessage(roomId, "Paired!");
343
+ this.emit("pairing:approved", {
344
+ userId: sender,
345
+ channelId: "matrix",
346
+ accountId: this.accountId
347
+ });
348
+ return true;
349
+ }
350
+ const code = Array.from({ length: 6 }, () => "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"[Math.floor(Math.random() * 32)]).join("");
351
+ this.cfg.pendingPairings[code] = sender;
352
+ await this.saveState();
353
+ await this.sendMessage(roomId, `Pairing code: \`${code}\`\nApprove: hyperclaw pairing approve matrix ${code}`);
354
+ return false;
355
+ }
356
+ }
357
+ return false;
358
+ }
359
+ checkGroupPolicy(roomId, sender, text, roomData) {
360
+ const policy = this.cfg.groupPolicy ?? "allowlist";
361
+ if (policy === "disabled") return false;
362
+ const allGroups = {
363
+ ...this.cfg.rooms || {},
364
+ ...this.cfg.groups || {}
365
+ };
366
+ const roomCfg = allGroups[roomId] || allGroups["*"] || {};
367
+ if (policy === "open" || roomCfg.allow === true) {
368
+ if (roomCfg.allowFrom?.length && !roomCfg.allowFrom.includes(sender)) return false;
369
+ const globalAllow$1 = this.cfg.groupAllowFrom ?? [];
370
+ if (globalAllow$1.length && !globalAllow$1.includes(sender)) return false;
371
+ if (roomCfg.requireMention !== false) {
372
+ const botMention = `${this.userId}`;
373
+ if (!text.includes(botMention) && !text.startsWith("!")) return false;
374
+ }
375
+ return true;
376
+ }
377
+ if (!allGroups[roomId] && !allGroups["*"]) return false;
378
+ if (roomCfg.allow === false) return false;
379
+ const globalAllow = this.cfg.groupAllowFrom ?? [];
380
+ if (globalAllow.length && !globalAllow.includes(sender)) return false;
381
+ if (roomCfg.allowFrom?.length && !roomCfg.allowFrom.includes(sender)) return false;
382
+ if (roomCfg.requireMention !== false) {
383
+ const botMention = this.userId;
384
+ if (!text.includes(botMention) && !text.startsWith("!")) return false;
385
+ }
386
+ return true;
387
+ }
388
+ async sendMessage(roomId, text, threadId) {
389
+ const limit = this.cfg.textChunkLimit ?? DEFAULT_CHUNK;
390
+ const mode = this.cfg.chunkMode ?? "length";
391
+ const chunks = chunkText(text, limit, mode);
392
+ const threadReplies = this.cfg.threadReplies ?? "inbound";
393
+ const useThread = threadId && (threadReplies === "inbound" || threadReplies === "always");
394
+ for (const chunk of chunks) {
395
+ const content = {
396
+ msgtype: "m.text",
397
+ body: chunk,
398
+ format: "org.matrix.custom.html",
399
+ formatted_body: chunk.replace(/\n/g, "<br/>")
400
+ };
401
+ if (useThread) content["m.relates_to"] = {
402
+ rel_type: "m.thread",
403
+ event_id: threadId,
404
+ is_falling_back: true
405
+ };
406
+ const txnId = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
407
+ await matrixReq(this.cfg.homeserver, this.token, "PUT", `/rooms/${encodeURIComponent(roomId)}/send/m.room.message/${txnId}`, content);
408
+ }
409
+ }
410
+ async resolveRoom(idOrAlias) {
411
+ if (!idOrAlias.startsWith("#")) return idOrAlias;
412
+ if (this.aliasCache.has(idOrAlias)) return this.aliasCache.get(idOrAlias);
413
+ try {
414
+ const res = await matrixReq(this.cfg.homeserver, this.token, "GET", `/directory/room/${encodeURIComponent(idOrAlias)}`);
415
+ if (res.room_id) this.aliasCache.set(idOrAlias, res.room_id);
416
+ return res.room_id || idOrAlias;
417
+ } catch {
418
+ return idOrAlias;
419
+ }
420
+ }
421
+ approvePairing(code) {
422
+ const upper = code.toUpperCase();
423
+ if (!this.cfg.pendingPairings[upper]) return false;
424
+ this.cfg.approvedPairings.push(this.cfg.pendingPairings[upper]);
425
+ delete this.cfg.pendingPairings[upper];
426
+ this.saveState();
427
+ return true;
428
+ }
429
+ isRunning() {
430
+ return this.running;
431
+ }
432
+ };
433
+ var MatrixConnector = class extends events.EventEmitter {
434
+ config;
435
+ accounts = [];
436
+ constructor(config) {
437
+ super();
438
+ this.config = config;
439
+ }
440
+ async connect() {
441
+ const sharedState = {
442
+ approvedPairings: this.config.approvedPairings ?? [],
443
+ pendingPairings: this.config.pendingPairings ?? {}
444
+ };
445
+ const accountEntries = Object.entries(this.config.accounts || {});
446
+ if (accountEntries.length === 0) {
447
+ const acct = new MatrixAccount("default", {
448
+ ...this.config,
449
+ ...sharedState
450
+ });
451
+ this.wire(acct);
452
+ await acct.connect();
453
+ this.accounts.push(acct);
454
+ } else for (const [id, acctCfg] of accountEntries) {
455
+ const merged = {
456
+ ...this.config,
457
+ ...acctCfg,
458
+ homeserver: acctCfg.homeserver || this.config.homeserver,
459
+ ...sharedState
460
+ };
461
+ if (!merged.homeserver) {
462
+ console.error(`[matrix] Account "${id}" has no homeserver — skipping`);
463
+ continue;
464
+ }
465
+ const acct = new MatrixAccount(id, merged);
466
+ this.wire(acct);
467
+ try {
468
+ await acct.connect();
469
+ this.accounts.push(acct);
470
+ } catch (e) {
471
+ console.error(`[matrix] Account "${id}" failed: ${e.message}`);
472
+ }
473
+ }
474
+ }
475
+ wire(acct) {
476
+ acct.on("message", (msg) => this.emit("message", msg));
477
+ acct.on("connected", (info) => this.emit("connected", info));
478
+ acct.on("pairing:approved", (info) => this.emit("pairing:approved", info));
479
+ }
480
+ async sendMessage(roomId, text, threadId) {
481
+ const acct = this.accounts[0];
482
+ if (!acct) throw new Error("Matrix: no connected account");
483
+ await acct.sendMessage(roomId, text, threadId);
484
+ }
485
+ disconnect() {
486
+ for (const a of this.accounts) a.disconnect();
487
+ this.accounts = [];
488
+ }
489
+ approvePairing(code) {
490
+ return this.accounts.some((a) => a.approvePairing(code));
491
+ }
492
+ isRunning() {
493
+ return this.accounts.some((a) => a.isRunning());
494
+ }
495
+ };
496
+
497
+ //#endregion
498
+ exports.MatrixConnector = MatrixConnector;