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,225 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ const fs_extra = require_chunk.__toESM(require("fs-extra"));
3
+ const path = require_chunk.__toESM(require("path"));
4
+ const os = require_chunk.__toESM(require("os"));
5
+ const child_process = require_chunk.__toESM(require("child_process"));
6
+ const events = require_chunk.__toESM(require("events"));
7
+
8
+ //#region extensions/imessage-native/src/connector.ts
9
+ const STATE_FILE = path.default.join(os.default.homedir(), ".hyperclaw", "imessage-native-state.json");
10
+ const PAIRING_TTL_MS = 60 * 60 * 1e3;
11
+ var IMessageNativeConnector = class extends events.EventEmitter {
12
+ config;
13
+ rpcProc = null;
14
+ running = false;
15
+ lastMessageTs = 0;
16
+ rpcSeq = 1;
17
+ pending = /* @__PURE__ */ new Map();
18
+ buf = "";
19
+ constructor(config = {}) {
20
+ super();
21
+ this.config = {
22
+ cliPath: config.cliPath || process.env.IMSG_PATH || "imsg",
23
+ dbPath: config.dbPath || path.default.join(os.default.homedir(), "Library", "Messages", "chat.db"),
24
+ dmPolicy: config.dmPolicy ?? "pairing",
25
+ allowFrom: config.allowFrom ?? [],
26
+ approvedPairings: config.approvedPairings ?? [],
27
+ pendingPairings: config.pendingPairings ?? {},
28
+ pendingPairingTs: config.pendingPairingTs ?? {}
29
+ };
30
+ }
31
+ async connect() {
32
+ if (process.platform !== "darwin") throw new Error("imessage-native is macOS only. For new deployments use BlueBubbles.");
33
+ await this.loadState();
34
+ this.running = true;
35
+ this.emit("connected", {});
36
+ this.startRpc();
37
+ }
38
+ startRpc() {
39
+ if (!this.running) return;
40
+ const bin = this.config.cliPath;
41
+ const args = ["rpc"];
42
+ if (this.config.dbPath) args.push("--db", this.config.dbPath);
43
+ this.rpcProc = (0, child_process.spawn)(bin, args, { stdio: [
44
+ "pipe",
45
+ "pipe",
46
+ "pipe"
47
+ ] });
48
+ this.rpcProc.stdout?.on("data", (chunk) => {
49
+ this.buf += chunk.toString();
50
+ const lines = this.buf.split("\n");
51
+ this.buf = lines.pop() || "";
52
+ for (const line of lines) {
53
+ if (!line.trim()) continue;
54
+ try {
55
+ this.handleRpcLine(JSON.parse(line));
56
+ } catch {}
57
+ }
58
+ });
59
+ this.rpcProc.stderr?.on("data", () => {});
60
+ this.rpcProc.on("error", () => {});
61
+ this.rpcProc.on("exit", (code) => {
62
+ this.rpcProc = null;
63
+ this.buf = "";
64
+ for (const [, cb] of this.pending) cb.reject(new Error("imsg rpc exited"));
65
+ this.pending.clear();
66
+ if (this.running && code !== 0) setTimeout(() => this.startRpc(), 5e3);
67
+ });
68
+ this.rpcSend("messages.watch", {}).catch(() => {});
69
+ }
70
+ handleRpcLine(msg) {
71
+ if (!msg.id && msg.method === "message" && msg.params) {
72
+ this.onIncomingMessage(msg.params);
73
+ return;
74
+ }
75
+ if (msg.id != null) {
76
+ const cb = this.pending.get(msg.id);
77
+ if (!cb) return;
78
+ this.pending.delete(msg.id);
79
+ if (msg.error) cb.reject(new Error(msg.error.message));
80
+ else cb.resolve(msg.result);
81
+ }
82
+ }
83
+ onIncomingMessage(params) {
84
+ if (params.isFromMe) return;
85
+ const handle = params.handle?.address || params.sender || params.chatId || params.from;
86
+ const text = params.text || params.body || params.message;
87
+ if (!handle || !text) return;
88
+ const ts = params.dateCreated || params.timestamp || Date.now();
89
+ if (ts <= this.lastMessageTs) return;
90
+ this.lastMessageTs = ts;
91
+ this.saveState();
92
+ this.checkDMPolicyAndEmit(handle, text);
93
+ }
94
+ pruneExpiredCodes() {
95
+ const now = Date.now();
96
+ const ts = this.config.pendingPairingTs;
97
+ for (const code of Object.keys(ts)) if (now - ts[code] > PAIRING_TTL_MS) {
98
+ delete this.config.pendingPairings[code];
99
+ delete ts[code];
100
+ }
101
+ }
102
+ async checkDMPolicyAndEmit(from, text) {
103
+ if (this.config.dmPolicy === "disabled") return;
104
+ if (this.config.dmPolicy === "open") {
105
+ this.emit("message", {
106
+ chatId: from,
107
+ text
108
+ });
109
+ return;
110
+ }
111
+ if (this.config.dmPolicy === "allowlist") {
112
+ if (this.config.allowFrom.includes(from)) this.emit("message", {
113
+ chatId: from,
114
+ text
115
+ });
116
+ else await this.sendMessage(from, "HyperClaw: Not on allowlist.");
117
+ return;
118
+ }
119
+ this.pruneExpiredCodes();
120
+ if (this.config.approvedPairings.includes(from)) {
121
+ this.emit("message", {
122
+ chatId: from,
123
+ text
124
+ });
125
+ return;
126
+ }
127
+ const code = (text.trim().toUpperCase().match(/[A-Z0-9]{6}/) || [])[0];
128
+ if (code && this.config.pendingPairings[code]) {
129
+ this.config.approvedPairings.push(from);
130
+ delete this.config.pendingPairings[code];
131
+ delete this.config.pendingPairingTs[code];
132
+ await this.saveState();
133
+ await this.sendMessage(from, "Paired!");
134
+ this.emit("pairing:approved", {
135
+ userId: from,
136
+ channelId: "imessage-native"
137
+ });
138
+ this.emit("message", {
139
+ chatId: from,
140
+ text
141
+ });
142
+ return;
143
+ }
144
+ const newCode = Array.from({ length: 6 }, () => "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"[Math.floor(Math.random() * 32)]).join("");
145
+ this.config.pendingPairings[newCode] = from;
146
+ this.config.pendingPairingTs[newCode] = Date.now();
147
+ await this.saveState();
148
+ await this.sendMessage(from, `Pairing code: ${newCode}\nApprove: hyperclaw pairing approve imessage-native ${newCode}\n(expires in 1 hour)`);
149
+ }
150
+ async sendMessage(chatId, text) {
151
+ const to = String(chatId).trim();
152
+ if (!to) return;
153
+ if (!this.rpcProc) throw new Error("imsg rpc not running");
154
+ await this.rpcSend("messages.send", {
155
+ to,
156
+ text
157
+ });
158
+ }
159
+ rpcSend(method, params) {
160
+ return new Promise((resolve, reject) => {
161
+ if (!this.rpcProc?.stdin) {
162
+ reject(new Error("imsg rpc stdin unavailable"));
163
+ return;
164
+ }
165
+ const id = this.rpcSeq++;
166
+ const req = {
167
+ jsonrpc: "2.0",
168
+ id,
169
+ method,
170
+ params
171
+ };
172
+ this.pending.set(id, {
173
+ resolve,
174
+ reject
175
+ });
176
+ this.rpcProc.stdin.write(JSON.stringify(req) + "\n");
177
+ const timer = setTimeout(() => {
178
+ if (this.pending.has(id)) {
179
+ this.pending.delete(id);
180
+ reject(new Error(`imsg rpc timeout for method ${method}`));
181
+ }
182
+ }, 15e3);
183
+ const orig = this.pending.get(id);
184
+ this.pending.set(id, {
185
+ resolve: (v) => {
186
+ clearTimeout(timer);
187
+ orig.resolve(v);
188
+ },
189
+ reject: (e) => {
190
+ clearTimeout(timer);
191
+ orig.reject(e);
192
+ }
193
+ });
194
+ });
195
+ }
196
+ disconnect() {
197
+ this.running = false;
198
+ this.rpcProc?.kill();
199
+ this.rpcProc = null;
200
+ this.buf = "";
201
+ for (const [, cb] of this.pending) cb.reject(new Error("disconnected"));
202
+ this.pending.clear();
203
+ }
204
+ async loadState() {
205
+ try {
206
+ const s = await fs_extra.default.readJson(STATE_FILE);
207
+ this.lastMessageTs = s.lastTs || 0;
208
+ if (s.p) this.config.pendingPairings = s.p;
209
+ if (s.a) this.config.approvedPairings = s.a;
210
+ if (s.pts) this.config.pendingPairingTs = s.pts;
211
+ } catch {}
212
+ }
213
+ async saveState() {
214
+ await fs_extra.default.ensureDir(path.default.dirname(STATE_FILE));
215
+ await fs_extra.default.writeJson(STATE_FILE, {
216
+ lastTs: this.lastMessageTs,
217
+ p: this.config.pendingPairings,
218
+ a: this.config.approvedPairings,
219
+ pts: this.config.pendingPairingTs
220
+ }, { spaces: 2 });
221
+ }
222
+ };
223
+
224
+ //#endregion
225
+ exports.IMessageNativeConnector = IMessageNativeConnector;
@@ -0,0 +1,218 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ const chalk = require_chunk.__toESM(require("chalk"));
3
+ const events = require_chunk.__toESM(require("events"));
4
+ const irc = require_chunk.__toESM(require("irc"));
5
+
6
+ //#region extensions/irc/src/connector.ts
7
+ function resolveEnvConfig(cfg) {
8
+ return {
9
+ server: cfg.server || process.env["IRC_HOST"] || "",
10
+ port: cfg.port ?? (process.env["IRC_PORT"] ? parseInt(process.env["IRC_PORT"], 10) : void 0),
11
+ tls: cfg.tls ?? (process.env["IRC_TLS"] === "true" || process.env["IRC_TLS"] === "1"),
12
+ nick: cfg.nick || process.env["IRC_NICK"] || "hyperclaw-bot",
13
+ username: cfg.username || process.env["IRC_USERNAME"],
14
+ realname: cfg.realname || process.env["IRC_REALNAME"],
15
+ password: cfg.password || process.env["IRC_PASSWORD"],
16
+ channels: cfg.channels?.length ? cfg.channels : process.env["IRC_CHANNELS"]?.split(",").map((c) => c.trim()).filter(Boolean) ?? [],
17
+ nickserv: cfg.nickserv ?? (process.env["IRC_NICKSERV_PASSWORD"] ? {
18
+ enabled: true,
19
+ service: "NickServ",
20
+ password: process.env["IRC_NICKSERV_PASSWORD"],
21
+ registerEmail: process.env["IRC_NICKSERV_REGISTER_EMAIL"]
22
+ } : void 0),
23
+ dmPolicy: cfg.dmPolicy ?? "pairing",
24
+ allowFrom: cfg.allowFrom ?? [],
25
+ groupPolicy: cfg.groupPolicy ?? "allowlist",
26
+ groupAllowFrom: cfg.groupAllowFrom ?? [],
27
+ groups: cfg.groups ?? {},
28
+ dangerouslyAllowNameMatching: cfg.dangerouslyAllowNameMatching ?? false
29
+ };
30
+ }
31
+ /** Match a sender (nick!user@host or bare nick) against an allowFrom entry. */
32
+ function matchSender(sender, pattern, allowBareNick) {
33
+ if (pattern === "*") return true;
34
+ if (pattern.startsWith("id:")) {
35
+ const id = pattern.slice(3);
36
+ return sender === id || sender.startsWith(id + "!");
37
+ }
38
+ if (pattern === sender) return true;
39
+ if (allowBareNick) {
40
+ const nick = sender.split("!")[0];
41
+ return nick === pattern;
42
+ }
43
+ return false;
44
+ }
45
+ function senderAllowed(sender, allowList, allowBareNick) {
46
+ if (!allowList.length) return false;
47
+ return allowList.some((p) => matchSender(sender, p, allowBareNick));
48
+ }
49
+ /** Return the first matching ToolsBySender policy for a sender. */
50
+ function resolveToolsBySender(sender, toolsBySender, allowBareNick) {
51
+ for (const [pattern, policy] of Object.entries(toolsBySender)) {
52
+ const pat = pattern.startsWith("id:") ? pattern : `id:${pattern}`;
53
+ if (matchSender(sender, pat === "id:*" ? "*" : pat, allowBareNick)) return policy;
54
+ }
55
+ return void 0;
56
+ }
57
+ /** Resolve effective tool policy for a sender in a channel. */
58
+ function resolveToolPolicy(sender, channelCfg, allowBareNick) {
59
+ if (!channelCfg) return void 0;
60
+ if (channelCfg.toolsBySender) {
61
+ const byS = resolveToolsBySender(sender, channelCfg.toolsBySender, allowBareNick);
62
+ if (byS) return byS;
63
+ }
64
+ return channelCfg.tools;
65
+ }
66
+ /** Find the best group config for a channel name. */
67
+ function getGroupConfig(channel, groups) {
68
+ return groups[channel] ?? groups["*"];
69
+ }
70
+ var IrcConnector = class extends events.EventEmitter {
71
+ client = null;
72
+ config;
73
+ constructor(rawConfig) {
74
+ super();
75
+ this.config = resolveEnvConfig(rawConfig);
76
+ }
77
+ async connect() {
78
+ return new Promise((resolve, reject) => {
79
+ const cfg = this.config;
80
+ const useTls = cfg.tls ?? false;
81
+ const port = cfg.port ?? (useTls ? 6697 : 6667);
82
+ const channels = (cfg.channels ?? []).map((c) => c.startsWith("#") ? c : `#${c}`);
83
+ this.client = new irc.default.Client(cfg.server, cfg.nick, {
84
+ port,
85
+ secure: useTls,
86
+ channels,
87
+ userName: cfg.username ?? cfg.nick,
88
+ realName: cfg.realname ?? "HyperClaw IRC Bot",
89
+ password: cfg.password,
90
+ autoConnect: true,
91
+ debug: false,
92
+ showErrors: true,
93
+ stripColors: true
94
+ });
95
+ this.client.on("registered", () => {
96
+ console.log(chalk.default.green(` 🦅 IRC: ${cfg.nick} on ${cfg.server}:${port}${useTls ? " (TLS)" : ""} connected`));
97
+ this._handleNickServ();
98
+ this.emit("connected", {
99
+ server: cfg.server,
100
+ nick: cfg.nick,
101
+ port,
102
+ tls: useTls
103
+ });
104
+ resolve();
105
+ });
106
+ this.client.on("error", (err) => {
107
+ console.log(chalk.default.yellow(` ⚠ IRC error: ${err.message}`));
108
+ reject(err);
109
+ });
110
+ this.client.on("message", (from, to, message) => {
111
+ const isChannel = to.startsWith("#");
112
+ if (isChannel) this._handleChannelMessage(from, to, message);
113
+ else this._handleDm(from, message);
114
+ });
115
+ this.client.on("pm", (from, message) => {
116
+ this._handleDm(from, message);
117
+ });
118
+ });
119
+ }
120
+ _handleNickServ() {
121
+ const ns = this.config.nickserv;
122
+ if (!ns?.enabled) return;
123
+ const service = ns.service ?? "NickServ";
124
+ const nsPassword = ns.password ?? process.env["IRC_NICKSERV_PASSWORD"];
125
+ if (ns.register && ns.registerEmail) {
126
+ console.log(chalk.default.gray(` IRC NickServ: attempting REGISTER`));
127
+ this.client.say(service, `REGISTER ${nsPassword} ${ns.registerEmail}`);
128
+ } else if (nsPassword) {
129
+ console.log(chalk.default.gray(` IRC NickServ: identifying`));
130
+ this.client.say(service, `IDENTIFY ${nsPassword}`);
131
+ }
132
+ }
133
+ _handleChannelMessage(from, channel, message) {
134
+ const cfg = this.config;
135
+ const text = message.trim();
136
+ if (!text) return;
137
+ const groupCfg = getGroupConfig(channel, cfg.groups ?? {});
138
+ if (cfg.groupPolicy === "allowlist") {
139
+ const defined = cfg.groups && (cfg.groups[channel] !== void 0 || cfg.groups["*"] !== void 0);
140
+ if (!defined) {
141
+ console.log(chalk.default.gray(` irc: drop channel ${channel} (groupPolicy=allowlist, not in groups)`));
142
+ return;
143
+ }
144
+ }
145
+ const allowBareNick = cfg.dangerouslyAllowNameMatching ?? false;
146
+ const perChannelAllow = groupCfg?.allowFrom ?? [];
147
+ const globalGroupAllow = cfg.groupAllowFrom ?? [];
148
+ const effectiveAllow = perChannelAllow.length ? perChannelAllow : globalGroupAllow;
149
+ if (effectiveAllow.length && !senderAllowed(from, effectiveAllow, allowBareNick)) {
150
+ console.log(chalk.default.gray(` irc: drop group sender ${from} (policy=allowlist)`));
151
+ return;
152
+ }
153
+ const requireMention = groupCfg?.requireMention ?? true;
154
+ if (requireMention) {
155
+ const mentionPatterns = [
156
+ cfg.nick,
157
+ `${cfg.nick}:`,
158
+ `@${cfg.nick}`,
159
+ `${cfg.nick},`
160
+ ];
161
+ const mentioned = mentionPatterns.some((p) => text.toLowerCase().startsWith(p.toLowerCase()));
162
+ if (!mentioned) {
163
+ console.log(chalk.default.gray(` irc: drop channel ${channel} (missing-mention)`));
164
+ return;
165
+ }
166
+ }
167
+ const toolPolicy = resolveToolPolicy(from, groupCfg, allowBareNick);
168
+ const payload = {
169
+ chatId: channel,
170
+ text,
171
+ from,
172
+ to: channel,
173
+ isChannel: true,
174
+ ...toolPolicy ? { toolPolicy } : {}
175
+ };
176
+ this.emit("message", payload);
177
+ }
178
+ _handleDm(from, message) {
179
+ const cfg = this.config;
180
+ const text = message.trim();
181
+ if (!text) return;
182
+ if (cfg.dmPolicy === "none") return;
183
+ if (cfg.dmPolicy === "allowlist") {
184
+ const allowBareNick = cfg.dangerouslyAllowNameMatching ?? false;
185
+ const allowList = cfg.allowFrom ?? [];
186
+ if (!senderAllowed(from, allowList, allowBareNick)) {
187
+ console.log(chalk.default.gray(` irc: drop DM from ${from} (dmPolicy=allowlist)`));
188
+ return;
189
+ }
190
+ }
191
+ const payload = {
192
+ chatId: from,
193
+ text,
194
+ from,
195
+ to: from,
196
+ isChannel: false
197
+ };
198
+ this.emit("message", payload);
199
+ }
200
+ async sendMessage(chatId, text) {
201
+ if (!this.client) throw new Error("IRC not connected");
202
+ const lines = text.split("\n").filter(Boolean);
203
+ for (const line of lines) this.client.say(chatId, line);
204
+ }
205
+ async disconnect() {
206
+ if (this.client) {
207
+ this.client.disconnect();
208
+ this.client = null;
209
+ }
210
+ }
211
+ getToolPolicy(sender, channel) {
212
+ const groupCfg = getGroupConfig(channel, this.config.groups ?? {});
213
+ return resolveToolPolicy(sender, groupCfg, this.config.dangerouslyAllowNameMatching ?? false);
214
+ }
215
+ };
216
+
217
+ //#endregion
218
+ exports.IrcConnector = IrcConnector;
@@ -0,0 +1,167 @@
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 https = require_chunk.__toESM(require("https"));
7
+ const events = require_chunk.__toESM(require("events"));
8
+
9
+ //#region extensions/zalo-personal/src/connector.ts
10
+ const STATE_FILE = path.default.join(os.default.homedir(), ".hyperclaw", "zalo-personal-state.json");
11
+ function zaloWebReq(cookie, method, endpoint, body) {
12
+ return new Promise((resolve, reject) => {
13
+ const payload = body ? JSON.stringify(body) : null;
14
+ const req = https.default.request({
15
+ hostname: "chat.zalo.me",
16
+ port: 443,
17
+ path: `/api${endpoint}`,
18
+ method,
19
+ headers: {
20
+ "Cookie": cookie,
21
+ "Referer": "https://chat.zalo.me/",
22
+ "User-Agent": "Mozilla/5.0 (compatible; HyperClaw/4.0)",
23
+ ...payload ? {
24
+ "Content-Type": "application/json",
25
+ "Content-Length": Buffer.byteLength(payload)
26
+ } : {}
27
+ }
28
+ }, (res) => {
29
+ let data = "";
30
+ res.on("data", (c) => data += c);
31
+ res.on("end", () => {
32
+ try {
33
+ resolve(JSON.parse(data));
34
+ } catch {
35
+ resolve({ raw: data });
36
+ }
37
+ });
38
+ });
39
+ req.on("error", reject);
40
+ if (payload) req.write(payload);
41
+ req.end();
42
+ });
43
+ }
44
+ var ZaloPersonalConnector = class extends events.EventEmitter {
45
+ config;
46
+ running = false;
47
+ ws = null;
48
+ userId = "";
49
+ constructor(config) {
50
+ super();
51
+ this.config = {
52
+ imei: require("crypto").randomUUID(),
53
+ dmPolicy: "allowlist",
54
+ allowFrom: [],
55
+ approvedPairings: [],
56
+ pendingPairings: {},
57
+ ...config
58
+ };
59
+ }
60
+ async connect() {
61
+ const profile = await zaloWebReq(this.config.cookie, "GET", "/profile");
62
+ this.userId = profile?.data?.userId || profile?.userId || "";
63
+ await this.loadState();
64
+ this.running = true;
65
+ console.log(chalk.default.green(` 🦅 Zalo Personal: ${profile?.data?.displayName || this.userId} connected`));
66
+ this.emit("connected", { userId: this.userId });
67
+ this.startPolling();
68
+ }
69
+ async startPolling() {
70
+ while (this.running) try {
71
+ const msgs = await zaloWebReq(this.config.cookie, "GET", `/message/fetchlatestmsg?last_msg_id=0&limit=20`);
72
+ for (const msg of msgs?.data?.msgs || []) {
73
+ if (msg.fromUid === this.userId) continue;
74
+ if (!msg.msgId || !msg.content) continue;
75
+ const from = msg.fromUid;
76
+ const text = msg.content;
77
+ const allowed = await this.checkDMPolicy(from, text);
78
+ if (!allowed) continue;
79
+ this.emit("message", {
80
+ id: msg.msgId,
81
+ channelId: "zalo-personal",
82
+ from,
83
+ chatId: msg.toUid || from,
84
+ text,
85
+ timestamp: new Date(parseInt(msg.ts || "0")).toISOString(),
86
+ isDM: true
87
+ });
88
+ }
89
+ await new Promise((r) => setTimeout(r, 3e3));
90
+ } catch (e) {
91
+ if (this.running) {
92
+ console.log(chalk.default.yellow(` ⚠ Zalo Personal: ${e.message}`));
93
+ await new Promise((r) => setTimeout(r, 5e3));
94
+ }
95
+ }
96
+ }
97
+ async checkDMPolicy(from, text) {
98
+ if (this.config.dmPolicy === "none") return false;
99
+ if (this.config.dmPolicy === "open") return true;
100
+ if (this.config.dmPolicy === "allowlist") {
101
+ if (this.config.allowFrom.includes(from)) return true;
102
+ await this.sendMessage(from, "🦅 HyperClaw: Not on allowlist.");
103
+ return false;
104
+ }
105
+ if (this.config.dmPolicy === "pairing") {
106
+ if (this.config.approvedPairings.includes(from)) return true;
107
+ const upper = text.trim().toUpperCase();
108
+ if (this.config.pendingPairings[upper]) {
109
+ this.config.approvedPairings.push(from);
110
+ delete this.config.pendingPairings[upper];
111
+ await this.saveState();
112
+ await this.sendMessage(from, "🦅 Paired!");
113
+ this.emit("pairing:approved", {
114
+ userId: from,
115
+ channelId: "zalo-personal"
116
+ });
117
+ return true;
118
+ }
119
+ const code = Array.from({ length: 6 }, () => "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"[Math.floor(Math.random() * 32)]).join("");
120
+ this.config.pendingPairings[code] = from;
121
+ await this.saveState();
122
+ await this.sendMessage(from, `🦅 Mã ghép đôi: ${code}\nXác nhận: hyperclaw pairing approve zalo-personal ${code}`);
123
+ return false;
124
+ }
125
+ return false;
126
+ }
127
+ async sendMessage(toUid, text) {
128
+ await zaloWebReq(this.config.cookie, "POST", "/message/sendmsg", {
129
+ toid: toUid,
130
+ msg: text.slice(0, 2e3),
131
+ imei: this.config.imei,
132
+ type: 1
133
+ });
134
+ }
135
+ disconnect() {
136
+ this.running = false;
137
+ this.ws?.close();
138
+ }
139
+ approvePairing(code) {
140
+ const upper = code.toUpperCase();
141
+ if (!this.config.pendingPairings[upper]) return false;
142
+ this.config.approvedPairings.push(this.config.pendingPairings[upper]);
143
+ delete this.config.pendingPairings[upper];
144
+ this.saveState();
145
+ return true;
146
+ }
147
+ async loadState() {
148
+ try {
149
+ const s = await fs_extra.default.readJson(STATE_FILE);
150
+ if (s.p) this.config.pendingPairings = s.p;
151
+ if (s.a) this.config.approvedPairings = s.a;
152
+ } catch {}
153
+ }
154
+ async saveState() {
155
+ await fs_extra.default.ensureDir(path.default.dirname(STATE_FILE));
156
+ await fs_extra.default.writeJson(STATE_FILE, {
157
+ p: this.config.pendingPairings,
158
+ a: this.config.approvedPairings
159
+ }, { spaces: 2 });
160
+ }
161
+ isRunning() {
162
+ return this.running;
163
+ }
164
+ };
165
+
166
+ //#endregion
167
+ exports.ZaloPersonalConnector = ZaloPersonalConnector;