hyperclaw 5.2.8 → 5.2.9
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.
- package/dist/a2ui-protocol-DEsfqO7h.js +75 -0
- package/dist/agents-routing-ChorJKFL.js +6 -0
- package/dist/agents-routing-Cpg20-1e.js +398 -0
- package/dist/api-key-validation-DgOBmp8Y.js +64 -0
- package/dist/api-keys-guide--73Bq0Ey.js +149 -0
- package/dist/audit-Dntx9fG9.js +445 -0
- package/dist/banner-B_rR7FPO.js +7 -0
- package/dist/banner-Bb7CderS.js +143 -0
- package/dist/bounty-tools-Dn9Yq7V1.js +211 -0
- package/dist/browser-tools-CJ9M9o22.js +179 -0
- package/dist/browser-tools-CXxWxA1c.js +5 -0
- package/dist/chat-D1Zc73I5.js +513 -0
- package/dist/claw-tasks-ChqkHdFs.js +80 -0
- package/dist/config-Bzues-G2.js +7 -0
- package/dist/config-DGAAJ49A.js +261 -0
- package/dist/connector-1efnZgQN.js +566 -0
- package/dist/connector-B5q1_srT.js +286 -0
- package/dist/connector-BMFLJ4fr.js +508 -0
- package/dist/connector-BZYv9siY.js +189 -0
- package/dist/connector-B_XkXm-j.js +218 -0
- package/dist/connector-BkY1I6gf.js +189 -0
- package/dist/connector-C2Z3RN1z.js +350 -0
- package/dist/connector-C7aYvVzU.js +225 -0
- package/dist/connector-CXXYOyHw.js +164 -0
- package/dist/connector-Ca1J23HX.js +167 -0
- package/dist/connector-Cjqc656I.js +181 -0
- package/dist/connector-CluRienN.js +425 -0
- package/dist/connector-CuNz2eP-.js +305 -0
- package/dist/connector-DHL_oeHy.js +552 -0
- package/dist/connector-DJ79rd1L.js +173 -0
- package/dist/connector-DcLE6xCZ.js +239 -0
- package/dist/connector-DcyQTJnJ.js +162 -0
- package/dist/connector-DgyX9qSc.js +192 -0
- package/dist/connector-DnDXXZ7L.js +182 -0
- package/dist/connector-DqUslg-X.js +213 -0
- package/dist/connector-Duc-HmRZ.js +85 -0
- package/dist/connector-IV0QFer8.js +498 -0
- package/dist/connector-OnsLxE8G.js +194 -0
- package/dist/connector-UYu_TS0X.js +204 -0
- package/dist/connector-cCA5ffmp.js +340 -0
- package/dist/connector-fbNfx4_L.js +568 -0
- package/dist/connector-fi2vlwbO.js +276 -0
- package/dist/connector-l3LD8IDN.js +419 -0
- package/dist/cost-tracker-DCXDUzBI.js +103 -0
- package/dist/credentials-store-Bmm9e1SS.js +7 -0
- package/dist/credentials-store-D8ERbGR2.js +89 -0
- package/dist/cron-tasks-OQbgmenS.js +85 -0
- package/dist/daemon-aVX-WGz1.js +421 -0
- package/dist/daemon-iFmVBPXN.js +7 -0
- package/dist/delivery-Pko6sSkt.js +4 -0
- package/dist/delivery-hMHFRZwy.js +95 -0
- package/dist/destructive-gate-C2TrWsp2.js +101 -0
- package/dist/developer-keys-BWXHaWxY.js +127 -0
- package/dist/developer-keys-CzDxVczE.js +8 -0
- package/dist/device-auth-store-C1bCwXO2.js +7 -0
- package/dist/device-auth-store-DIZTOz4V.js +88 -0
- package/dist/doctor-C6nAGdH8.js +233 -0
- package/dist/doctor-mgWumA25.js +6 -0
- package/dist/engine-BGRTi0fo.js +327 -0
- package/dist/engine-BvCEhaUn.js +7 -0
- package/dist/env-resolve-CHxjGo8u.js +151 -0
- package/dist/env-resolve-pIETNTpQ.js +10 -0
- package/dist/extraction-tools-BE6z_Yw5.js +91 -0
- package/dist/extraction-tools-CJsdyBST.js +5 -0
- package/dist/form_data-B2_0EoWj.js +8657 -0
- package/dist/gmail-watch-setup-1RGIHNdu.js +42 -0
- package/dist/health-BMUmUNoe.js +152 -0
- package/dist/health-C8n9RH5O.js +6 -0
- package/dist/heartbeat-engine-aRbab8a5.js +89 -0
- package/dist/hub-BJM2KXLO.js +6 -0
- package/dist/hub-Bb_dYECE.js +512 -0
- package/dist/hyperclawbot-CgrV46DA.js +516 -0
- package/dist/inference-CFBkvLpE.js +2854 -0
- package/dist/inference-G4MbdErG.js +8 -0
- package/dist/knowledge-graph-9UNrsiIY.js +134 -0
- package/dist/loader-DIPs649t.js +410 -0
- package/dist/loader-Dq_cDlOW.js +6 -0
- package/dist/logger-CG38Idq4.js +86 -0
- package/dist/manager--wG9JdFW.js +120 -0
- package/dist/manager-BNc21xgG.js +6 -0
- package/dist/manager-DWJ7WZcY.js +250 -0
- package/dist/manager-DYfzqckn.js +35 -0
- package/dist/mcp-SsMEvl28.js +142 -0
- package/dist/mcp-loader-DLrp_oZJ.js +93 -0
- package/dist/memory-BCYvdqwo.js +273 -0
- package/dist/memory-BGgCBSx1.js +6 -0
- package/dist/memory-auto-Bh52cQJP.js +5 -0
- package/dist/memory-auto-BupvVwNd.js +306 -0
- package/dist/memory-integration-4oGqX6rr.js +91 -0
- package/dist/moltbook-B3DNdh40.js +81 -0
- package/dist/node-C4esBfbX.js +226 -0
- package/dist/nodes-registry-DLUZhEMS.js +52 -0
- package/dist/oauth-flow-BbLQTzZk.js +148 -0
- package/dist/oauth-provider-UZyG84s7.js +111 -0
- package/dist/observability-BtLyuxcz.js +89 -0
- package/dist/onboard-B3drurt-.js +3812 -0
- package/dist/onboard-DEwuHrMj.js +14 -0
- package/dist/orchestrator-BXyIgAeH.js +189 -0
- package/dist/orchestrator-MLTc4NYu.js +6 -0
- package/dist/osint-Bsf6RGPv.js +283 -0
- package/dist/osint-chat-Ark94iFc.js +789 -0
- package/dist/pairing-2vAiDBjN.js +6 -0
- package/dist/pairing-B4NoBvyE.js +207 -0
- package/dist/pc-access-BLnc-DYp.js +858 -0
- package/dist/pc-access-CTNtG2LD.js +8 -0
- package/dist/pending-approval-C4ZaHHWl.js +22 -0
- package/dist/reminders-store-BixTWL1h.js +58 -0
- package/dist/renderer-B1ToXngl.js +228 -0
- package/dist/rules-Cqen1Mpt.js +106 -0
- package/dist/run-main.js +94 -93
- package/dist/runner-Cr1_mwnU.js +1274 -0
- package/dist/security-B4vH02lO.js +4 -0
- package/dist/security-HOOGCw5z.js +90 -0
- package/dist/server-CRhXiGI9.js +4 -0
- package/dist/server-De4H45Ju.js +1365 -0
- package/dist/session-store-7sEPyV16.js +5 -0
- package/dist/session-store-Ce2QMSL_.js +141 -0
- package/dist/sessions-tools-CWr_pDtp.js +5 -0
- package/dist/sessions-tools-DKVu9aIN.js +95 -0
- package/dist/skill-loader-DK19Jm4e.js +7 -0
- package/dist/skill-loader-Dfs9VNM-.js +160 -0
- package/dist/skill-runtime-BeKh2rD_.js +5 -0
- package/dist/skill-runtime-CcpC2Zfc.js +104 -0
- package/dist/src-BxmkZ9RH.js +63 -0
- package/dist/src-DjTtmSRg.js +20 -0
- package/dist/src-n_46LPDi.js +458 -0
- package/dist/sub-agent-tools-q5JqEze_.js +39 -0
- package/dist/tool-policy-QXF3MMxu.js +189 -0
- package/dist/tts-elevenlabs-y6HGWWDS.js +64 -0
- package/dist/update-check-C4te7JmY.js +6 -0
- package/dist/update-check-GDue_it1.js +98 -0
- package/dist/vision-tools-CbVfyTZT.js +5 -0
- package/dist/vision-tools-DieVQp6s.js +51 -0
- package/dist/vision-u4kMThdo.js +167 -0
- package/dist/voice-transcription-DgON5qaF.js +170 -0
- package/dist/website-watch-tools-B8L_NgwT.js +5 -0
- package/dist/website-watch-tools-Drm5HjIX.js +176 -0
- package/package.json +1 -1
|
@@ -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,189 @@
|
|
|
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/msteams/src/connector.ts
|
|
10
|
+
const STATE_FILE = path.default.join(os.default.homedir(), ".hyperclaw", "msteams-state.json");
|
|
11
|
+
let cachedToken = null;
|
|
12
|
+
async function getBotToken(appId, appPassword) {
|
|
13
|
+
if (cachedToken && cachedToken.expiresAt > Date.now() + 6e4) return cachedToken.token;
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
const body = `grant_type=client_credentials&client_id=${encodeURIComponent(appId)}&client_secret=${encodeURIComponent(appPassword)}&scope=https%3A%2F%2Fapi.botframework.com%2F.default`;
|
|
16
|
+
const req = https.default.request({
|
|
17
|
+
hostname: "login.microsoftonline.com",
|
|
18
|
+
port: 443,
|
|
19
|
+
path: "/botframework.com/oauth2/v2.0/token",
|
|
20
|
+
method: "POST",
|
|
21
|
+
headers: {
|
|
22
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
23
|
+
"Content-Length": Buffer.byteLength(body)
|
|
24
|
+
}
|
|
25
|
+
}, (res) => {
|
|
26
|
+
let data = "";
|
|
27
|
+
res.on("data", (c) => data += c);
|
|
28
|
+
res.on("end", () => {
|
|
29
|
+
try {
|
|
30
|
+
const r = JSON.parse(data);
|
|
31
|
+
cachedToken = {
|
|
32
|
+
token: r.access_token,
|
|
33
|
+
expiresAt: Date.now() + r.expires_in * 1e3
|
|
34
|
+
};
|
|
35
|
+
resolve(r.access_token);
|
|
36
|
+
} catch {
|
|
37
|
+
reject(new Error("Token parse error"));
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
req.on("error", reject);
|
|
42
|
+
req.write(body);
|
|
43
|
+
req.end();
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async function sendActivity(token, serviceUrl, conversationId, activity) {
|
|
47
|
+
const url = new URL(`${serviceUrl}v3/conversations/${conversationId}/activities`);
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
const payload = JSON.stringify(activity);
|
|
50
|
+
const req = https.default.request({
|
|
51
|
+
hostname: url.hostname,
|
|
52
|
+
port: 443,
|
|
53
|
+
path: url.pathname,
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: {
|
|
56
|
+
"Authorization": `Bearer ${token}`,
|
|
57
|
+
"Content-Type": "application/json",
|
|
58
|
+
"Content-Length": Buffer.byteLength(payload)
|
|
59
|
+
}
|
|
60
|
+
}, (res) => {
|
|
61
|
+
res.on("data", () => {});
|
|
62
|
+
res.on("end", resolve);
|
|
63
|
+
});
|
|
64
|
+
req.on("error", reject);
|
|
65
|
+
req.write(payload);
|
|
66
|
+
req.end();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
var MSTeamsConnector = class extends events.EventEmitter {
|
|
70
|
+
config;
|
|
71
|
+
running = false;
|
|
72
|
+
constructor(config) {
|
|
73
|
+
super();
|
|
74
|
+
this.config = {
|
|
75
|
+
dmPolicy: "allowlist",
|
|
76
|
+
allowFrom: [],
|
|
77
|
+
approvedPairings: [],
|
|
78
|
+
pendingPairings: {},
|
|
79
|
+
...config
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async connect() {
|
|
83
|
+
await getBotToken(this.config.appId, this.config.appPassword);
|
|
84
|
+
await this.loadState();
|
|
85
|
+
this.running = true;
|
|
86
|
+
console.log(chalk.default.green(` 🦅 MS Teams: Bot ${this.config.appId} connected`));
|
|
87
|
+
this.emit("connected", { appId: this.config.appId });
|
|
88
|
+
}
|
|
89
|
+
disconnect() {
|
|
90
|
+
this.running = false;
|
|
91
|
+
}
|
|
92
|
+
async handleWebhook(body) {
|
|
93
|
+
let activity;
|
|
94
|
+
try {
|
|
95
|
+
activity = JSON.parse(body);
|
|
96
|
+
} catch {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (activity.type !== "message") return;
|
|
100
|
+
const from = activity.from?.aadObjectId || activity.from?.id;
|
|
101
|
+
const text = activity.text?.replace(/<at>[^<]+<\/at>/g, "").trim();
|
|
102
|
+
const serviceUrl = activity.serviceUrl;
|
|
103
|
+
const conversationId = activity.conversation?.id;
|
|
104
|
+
if (!from || !text || !serviceUrl || !conversationId) return;
|
|
105
|
+
const allowed = await this.checkDMPolicy(from, text, serviceUrl, conversationId, activity);
|
|
106
|
+
if (!allowed) return;
|
|
107
|
+
this.emit("message", {
|
|
108
|
+
id: activity.id,
|
|
109
|
+
channelId: "msteams",
|
|
110
|
+
from,
|
|
111
|
+
chatId: conversationId,
|
|
112
|
+
fromName: activity.from?.name,
|
|
113
|
+
text,
|
|
114
|
+
timestamp: activity.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
115
|
+
isDM: activity.conversation?.conversationType === "personal",
|
|
116
|
+
serviceUrl,
|
|
117
|
+
activity
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
async checkDMPolicy(from, text, serviceUrl, convId, activity) {
|
|
121
|
+
if (this.config.dmPolicy === "none") return false;
|
|
122
|
+
if (this.config.dmPolicy === "open") return true;
|
|
123
|
+
if (this.config.dmPolicy === "allowlist") {
|
|
124
|
+
if (this.config.allowFrom.includes(from)) return true;
|
|
125
|
+
await this.reply(serviceUrl, convId, activity, "🦅 HyperClaw: Not on allowlist.");
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
if (this.config.dmPolicy === "pairing") {
|
|
129
|
+
if (this.config.approvedPairings.includes(from)) return true;
|
|
130
|
+
const upper = text.trim().toUpperCase();
|
|
131
|
+
if (this.config.pendingPairings[upper]) {
|
|
132
|
+
this.config.approvedPairings.push(from);
|
|
133
|
+
delete this.config.pendingPairings[upper];
|
|
134
|
+
await this.saveState();
|
|
135
|
+
await this.reply(serviceUrl, convId, activity, "🦅 Paired!");
|
|
136
|
+
this.emit("pairing:approved", {
|
|
137
|
+
userId: from,
|
|
138
|
+
channelId: "msteams"
|
|
139
|
+
});
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
const code = Array.from({ length: 6 }, () => "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"[Math.floor(Math.random() * 32)]).join("");
|
|
143
|
+
this.config.pendingPairings[code] = from;
|
|
144
|
+
await this.saveState();
|
|
145
|
+
await this.reply(serviceUrl, convId, activity, `🦅 Pairing code: ${code}\nApprove: hyperclaw pairing approve msteams ${code}`);
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
async reply(serviceUrl, conversationId, originalActivity, text) {
|
|
151
|
+
const token = await getBotToken(this.config.appId, this.config.appPassword);
|
|
152
|
+
await sendActivity(token, serviceUrl, conversationId, {
|
|
153
|
+
type: "message",
|
|
154
|
+
text: text.slice(0, 4e3),
|
|
155
|
+
replyToId: originalActivity.id,
|
|
156
|
+
from: { id: this.config.appId },
|
|
157
|
+
conversation: originalActivity.conversation,
|
|
158
|
+
recipient: originalActivity.from
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
approvePairing(code) {
|
|
162
|
+
const upper = code.toUpperCase();
|
|
163
|
+
if (!this.config.pendingPairings[upper]) return false;
|
|
164
|
+
this.config.approvedPairings.push(this.config.pendingPairings[upper]);
|
|
165
|
+
delete this.config.pendingPairings[upper];
|
|
166
|
+
this.saveState();
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
async loadState() {
|
|
170
|
+
try {
|
|
171
|
+
const s = await fs_extra.default.readJson(STATE_FILE);
|
|
172
|
+
if (s.p) this.config.pendingPairings = s.p;
|
|
173
|
+
if (s.a) this.config.approvedPairings = s.a;
|
|
174
|
+
} catch {}
|
|
175
|
+
}
|
|
176
|
+
async saveState() {
|
|
177
|
+
await fs_extra.default.ensureDir(path.default.dirname(STATE_FILE));
|
|
178
|
+
await fs_extra.default.writeJson(STATE_FILE, {
|
|
179
|
+
p: this.config.pendingPairings,
|
|
180
|
+
a: this.config.approvedPairings
|
|
181
|
+
}, { spaces: 2 });
|
|
182
|
+
}
|
|
183
|
+
isRunning() {
|
|
184
|
+
return this.running;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
//#endregion
|
|
189
|
+
exports.MSTeamsConnector = MSTeamsConnector;
|