hyperclaw 5.4.1 → 5.4.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 (135) hide show
  1. package/dist/a2ui-protocol-CUqdJGh7.js +75 -0
  2. package/dist/agents-routing-B0D0vcp5.js +424 -0
  3. package/dist/agents-routing-BC6GndVe.js +7 -0
  4. package/dist/agents-routing-CyFBHvyk.js +424 -0
  5. package/dist/agents-routing-DdpszaMx.js +7 -0
  6. package/dist/api-key-validation-DrMrLEa0.js +66 -0
  7. package/dist/api-keys-guide-DmKF7tB-.js +149 -0
  8. package/dist/audit-Q-Uy5nem.js +445 -0
  9. package/dist/backup-CtHJEqGr.js +86 -0
  10. package/dist/banner-DYzQ8cCb.js +143 -0
  11. package/dist/banner-jW84OrYg.js +7 -0
  12. package/dist/bounty-tools-CCwY61YO.js +211 -0
  13. package/dist/chat-CJa0ph8c.js +528 -0
  14. package/dist/chat-CKnfxa1-.js +528 -0
  15. package/dist/chat-CQKCIrIY.js +528 -0
  16. package/dist/chat-npW_ZOmo.js +528 -0
  17. package/dist/claw-tasks-Dq38PrL5.js +80 -0
  18. package/dist/config-BzK_Xl4Y.js +261 -0
  19. package/dist/config-ClsdlpXc.js +261 -0
  20. package/dist/config-Dm394B6X.js +7 -0
  21. package/dist/config-SiLqEezw.js +7 -0
  22. package/dist/connector-BYPxgmsD.js +312 -0
  23. package/dist/cost-tracker-x9E8VKtk.js +103 -0
  24. package/dist/credentials-store-Ddhgmbpz.js +7 -0
  25. package/dist/credentials-store-onL1tYct.js +89 -0
  26. package/dist/cron-tasks-CF4MJoIU.js +89 -0
  27. package/dist/daemon-ApB1nMs2.js +421 -0
  28. package/dist/daemon-B2ghXB-I.js +7 -0
  29. package/dist/daemon-BldYSrDj.js +421 -0
  30. package/dist/daemon-BqTcxMZe.js +7 -0
  31. package/dist/daemon-CivMFYkD.js +7 -0
  32. package/dist/daemon-DBXFUMue.js +421 -0
  33. package/dist/delivery-BURWi8wu.js +4 -0
  34. package/dist/delivery-kZ2mVkU5.js +95 -0
  35. package/dist/destructive-gate-C1ny9ek2.js +116 -0
  36. package/dist/engine-B-JvIt_Y.js +7 -0
  37. package/dist/engine-BGZnBZ4m.js +7 -0
  38. package/dist/engine-BTSXJNba.js +346 -0
  39. package/dist/engine-C7LyH310.js +353 -0
  40. package/dist/engine-C_nC_Ioe.js +351 -0
  41. package/dist/engine-DCtJSbKU.js +7 -0
  42. package/dist/env-resolve-C0R8R7pb.js +167 -0
  43. package/dist/env-resolve-Dr-KfTtw.js +11 -0
  44. package/dist/gmail-watch-setup-BzbG0ICM.js +42 -0
  45. package/dist/heartbeat-engine-B9bhAHNi.js +89 -0
  46. package/dist/hyperclawbot-BEm8_87h.js +516 -0
  47. package/dist/hyperclawbot-DR6BgI_d.js +516 -0
  48. package/dist/hyperclawbot-hZv4pde0.js +516 -0
  49. package/dist/inference-C874-2MI.js +8 -0
  50. package/dist/inference-DCSz6Sb1.js +2880 -0
  51. package/dist/knowledge-graph-BiIvoxPt.js +134 -0
  52. package/dist/loader-DMMb9emn.js +410 -0
  53. package/dist/loader-JktrmJOG.js +6 -0
  54. package/dist/logger-Oty9sC13.js +86 -0
  55. package/dist/manager-BIc6zzZV.js +250 -0
  56. package/dist/manager-BwobWy0l.js +120 -0
  57. package/dist/mcp-CI2F3m8G.js +142 -0
  58. package/dist/mcp-loader-C-21ynRH.js +93 -0
  59. package/dist/mcp-loader-Di7n__ta.js +93 -0
  60. package/dist/memory-auto-BVCJeTwd.js +306 -0
  61. package/dist/memory-auto-DXKe2ayf.js +5 -0
  62. package/dist/memory-integration-D2RvZ-MB.js +91 -0
  63. package/dist/moltbook-DvV6GFFL.js +81 -0
  64. package/dist/node-DFKhz7Zn.js +251 -0
  65. package/dist/node-pending-queue-CIMXPU6K.js +32 -0
  66. package/dist/nodes-registry-BeiEjd9U.js +52 -0
  67. package/dist/oauth-flow-CZOsvU1v.js +148 -0
  68. package/dist/oauth-provider-Dk-6BmGL.js +111 -0
  69. package/dist/observability-B3dDQSdI.js +89 -0
  70. package/dist/onboard-BnyHie0K.js +14 -0
  71. package/dist/onboard-D-5gWzH0.js +3854 -0
  72. package/dist/onboard-D9pjgaVR.js +3854 -0
  73. package/dist/onboard-UhWVcTap.js +14 -0
  74. package/dist/onboard-W5DsxVf2.js +3854 -0
  75. package/dist/onboard-YszvVNgS.js +14 -0
  76. package/dist/onboard-pLDBUBpO.js +14 -0
  77. package/dist/onboard-zISipu-l.js +3854 -0
  78. package/dist/orchestrator-C0t11xj7.js +189 -0
  79. package/dist/orchestrator-CA4eKeGn.js +189 -0
  80. package/dist/orchestrator-CNxTIlOK.js +189 -0
  81. package/dist/orchestrator-Cg1vgEHb.js +6 -0
  82. package/dist/orchestrator-DV5t6wQ0.js +6 -0
  83. package/dist/orchestrator-eT0ZL4yl.js +6 -0
  84. package/dist/osint-47yIek6w.js +283 -0
  85. package/dist/osint-c-xDjLb-.js +283 -0
  86. package/dist/osint-chat-BJgnkFDm.js +789 -0
  87. package/dist/osint-chat-C09BvbGy.js +789 -0
  88. package/dist/osint-chat-zdeaaw7a.js +789 -0
  89. package/dist/osint-e6oBrtlj.js +283 -0
  90. package/dist/pending-approval-CEu_-DGQ.js +22 -0
  91. package/dist/providers-BfW-fgpw.js +5 -0
  92. package/dist/providers-Cs1h_TJA.js +1137 -0
  93. package/dist/renderer-B_ew6jRs.js +228 -0
  94. package/dist/rules-BAYXiKiJ.js +106 -0
  95. package/dist/run-main.js +112 -77
  96. package/dist/runner-B5uo6C5q.js +1310 -0
  97. package/dist/search-tools-DXVuVXW_.js +107 -0
  98. package/dist/server-BJkDIs8Z.js +1467 -0
  99. package/dist/server-CtFoXM88.js +4 -0
  100. package/dist/server-DVxVLu_G.js +1467 -0
  101. package/dist/server-DZj6Nobr.js +1467 -0
  102. package/dist/server-Diu80smx.js +4 -0
  103. package/dist/server-DszV63tu.js +4 -0
  104. package/dist/skill-runtime-BLkXA1mO.js +104 -0
  105. package/dist/skill-runtime-BMk-h6Dl.js +5 -0
  106. package/dist/skill-runtime-BaTX-RGy.js +5 -0
  107. package/dist/skill-runtime-CB9tnc-P.js +104 -0
  108. package/dist/skill-runtime-D6-rGzX1.js +104 -0
  109. package/dist/skill-runtime-Dej1Yr5V.js +5 -0
  110. package/dist/src-6dmkVQGq.js +63 -0
  111. package/dist/src-7yBXPAs6.js +315 -0
  112. package/dist/src-BOnuFlI4.js +23 -0
  113. package/dist/src-BkEtHLLy.js +462 -0
  114. package/dist/src-CDeWGebw.js +315 -0
  115. package/dist/src-CNAVUFC6.js +462 -0
  116. package/dist/src-DB6dPsbY.js +63 -0
  117. package/dist/src-DE4mH0BB.js +63 -0
  118. package/dist/src-krHV0uVj.js +315 -0
  119. package/dist/src-tF0sBtr3.js +462 -0
  120. package/dist/sub-agent-tools-BwOxHu6f.js +39 -0
  121. package/dist/sub-agent-tools-CJVEIF1F.js +39 -0
  122. package/dist/sub-agent-tools-f4X1M-li.js +39 -0
  123. package/dist/tool-policy-CfWEnRxy.js +190 -0
  124. package/dist/tts-elevenlabs-CCeOqqrh.js +64 -0
  125. package/dist/vision-BMRKyu3c.js +167 -0
  126. package/dist/vision-tools-DVYx9-Jw.js +5 -0
  127. package/dist/vision-tools-kYb3effk.js +51 -0
  128. package/dist/voice-transcription-B1D1rpca.js +170 -0
  129. package/package.json +1 -1
  130. package/static/chat.html +18 -4
  131. package/static/web/assets/index-D2ekZ-uM.js +75 -0
  132. package/static/web/assets/index-D_9lvvup.css +1 -0
  133. package/static/web/index.html +2 -2
  134. package/static/web/assets/index-8bDizzaq.js +0 -75
  135. package/static/web/assets/index-B5N1LHGR.css +0 -1
@@ -0,0 +1,312 @@
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/telegram/src/connector.ts
10
+ function tgDownloadFile(token, filePath) {
11
+ return new Promise((resolve, reject) => {
12
+ const req = https.default.request({
13
+ hostname: "api.telegram.org",
14
+ port: 443,
15
+ path: `/file/bot${token}/${filePath}`,
16
+ method: "GET"
17
+ }, (res) => {
18
+ const chunks = [];
19
+ res.on("data", (c) => chunks.push(c));
20
+ res.on("end", () => resolve(Buffer.concat(chunks)));
21
+ });
22
+ req.on("error", reject);
23
+ req.setTimeout(3e4, () => {
24
+ req.destroy();
25
+ reject(new Error("Download timeout"));
26
+ });
27
+ req.end();
28
+ });
29
+ }
30
+ function tgRequest(token, method, body) {
31
+ return new Promise((resolve, reject) => {
32
+ const payload = body ? JSON.stringify(body) : null;
33
+ const req = https.default.request({
34
+ hostname: "api.telegram.org",
35
+ port: 443,
36
+ path: `/bot${token}/${method}`,
37
+ method: payload ? "POST" : "GET",
38
+ headers: payload ? {
39
+ "Content-Type": "application/json",
40
+ "Content-Length": Buffer.byteLength(payload)
41
+ } : {}
42
+ }, (res) => {
43
+ let data = "";
44
+ res.on("data", (c) => data += c);
45
+ res.on("end", () => {
46
+ try {
47
+ const r = JSON.parse(data);
48
+ if (r.ok) resolve(r.result);
49
+ else reject(new Error(r.description || "Telegram API error"));
50
+ } catch {
51
+ reject(new Error("Invalid JSON"));
52
+ }
53
+ });
54
+ });
55
+ req.on("error", reject);
56
+ req.setTimeout(35e3, () => {
57
+ req.destroy();
58
+ reject(new Error("Timeout"));
59
+ });
60
+ if (payload) req.write(payload);
61
+ req.end();
62
+ });
63
+ }
64
+ const STATE_FILE = path.default.join(os.default.homedir(), ".hyperclaw", "telegram-state.json");
65
+ function sleep(ms) {
66
+ return new Promise((r) => setTimeout(r, ms));
67
+ }
68
+ function generateCode() {
69
+ const chars = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
70
+ return Array.from({ length: 6 }, () => chars[Math.floor(Math.random() * chars.length)]).join("");
71
+ }
72
+ function chunkText(text, max) {
73
+ if (text.length <= max) return [text];
74
+ const chunks = [];
75
+ let i = 0;
76
+ while (i < text.length) {
77
+ let end = Math.min(i + max, text.length);
78
+ if (end < text.length) {
79
+ const nl = text.lastIndexOf("\n", end);
80
+ if (nl > i) end = nl + 1;
81
+ }
82
+ chunks.push(text.slice(i, end));
83
+ i = end;
84
+ }
85
+ return chunks;
86
+ }
87
+ var TelegramConnector = class extends events.EventEmitter {
88
+ token;
89
+ config;
90
+ offset = 0;
91
+ running = false;
92
+ botInfo = null;
93
+ constructor(token, config) {
94
+ super();
95
+ this.token = token;
96
+ this.config = {
97
+ token,
98
+ dmPolicy: "allowlist",
99
+ allowFrom: [],
100
+ pendingPairings: {},
101
+ approvedPairings: [],
102
+ ...config
103
+ };
104
+ }
105
+ async connect() {
106
+ this.botInfo = await tgRequest(this.token, "getMe");
107
+ console.log(chalk.default.green(` 🦅 Telegram: @${this.botInfo?.username} connected`));
108
+ await this.loadState();
109
+ this.running = true;
110
+ this.pollLoop();
111
+ this.emit("connected", this.botInfo);
112
+ }
113
+ async disconnect() {
114
+ this.running = false;
115
+ await this.saveState();
116
+ }
117
+ async pollLoop() {
118
+ while (this.running) try {
119
+ const allowed = this.config.inlineMode ? ["message", "inline_query"] : ["message"];
120
+ const updates = await tgRequest(this.token, "getUpdates", {
121
+ offset: this.offset,
122
+ timeout: 30,
123
+ allowed_updates: allowed
124
+ });
125
+ for (const u of updates) {
126
+ this.offset = u.update_id + 1;
127
+ await this.handleUpdate(u).catch((e) => console.log(chalk.default.yellow(` ⚠ ${e.message}`)));
128
+ }
129
+ } catch (e) {
130
+ if (this.running) {
131
+ console.log(chalk.default.yellow(` ⚠ Telegram poll: ${e.message}`));
132
+ await sleep(5e3);
133
+ }
134
+ }
135
+ }
136
+ async handleUpdate(u) {
137
+ if (u.inline_query) {
138
+ this.emit("inline_query", {
139
+ id: u.inline_query.id,
140
+ from: String(u.inline_query.from?.id),
141
+ query: u.inline_query.query,
142
+ username: u.inline_query.from?.username
143
+ });
144
+ return;
145
+ }
146
+ const msg = u.message || u.edited_message;
147
+ if (!msg) return;
148
+ const text = msg.text?.trim() || "";
149
+ if (!text && !msg.voice) return;
150
+ const userId = String(msg.from?.id || "");
151
+ const isDM = msg.chat.type === "private";
152
+ const isGroup = msg.chat.type === "group" || msg.chat.type === "supergroup";
153
+ if (isDM && !await this.checkDMPolicy(userId, msg.chat.id, text || "[voice note]")) return;
154
+ let finalText = text || "[voice note]";
155
+ if (isGroup) {
156
+ const groupAllowFrom = this.config.groupAllowFrom ?? [];
157
+ if (groupAllowFrom.length > 0 && !groupAllowFrom.includes(String(msg.chat.id))) return;
158
+ const activation = this.config.groupActivation ?? "mention";
159
+ if (activation === "mention") {
160
+ const botUsername = this.botInfo?.username ? `@${this.botInfo.username}`.toLowerCase() : "";
161
+ const mentioned = botUsername && text.toLowerCase().includes(botUsername);
162
+ const isReplyToBot = msg.reply_to_message?.from?.is_bot && msg.reply_to_message.from.id === this.botInfo?.id;
163
+ if (!mentioned && !isReplyToBot) return;
164
+ if (mentioned && botUsername) finalText = text.replace(new RegExp(botUsername, "gi"), "").trim() || finalText;
165
+ }
166
+ }
167
+ let audioBuffer;
168
+ if (msg?.voice?.file_id) try {
169
+ const file = await tgRequest(this.token, "getFile", { file_id: msg.voice.file_id });
170
+ audioBuffer = await tgDownloadFile(this.token, file.file_path);
171
+ } catch (e) {
172
+ console.log(chalk.default.yellow(` ⚠ Telegram voice download failed: ${e.message}`));
173
+ }
174
+ this.emit("message", {
175
+ id: String(msg.message_id),
176
+ channelId: "telegram",
177
+ from: userId,
178
+ fromUsername: msg.from?.username,
179
+ chatId: msg.chat.id,
180
+ text: finalText,
181
+ audioBuffer,
182
+ timestamp: new Date(msg.date * 1e3).toISOString(),
183
+ isDM,
184
+ isGroup,
185
+ threadId: msg.message_thread_id != null ? String(msg.message_thread_id) : void 0
186
+ });
187
+ }
188
+ async checkDMPolicy(userId, chatId, text) {
189
+ if (this.config.dmPolicy === "none") return false;
190
+ if (this.config.dmPolicy === "open") return true;
191
+ if (this.config.dmPolicy === "allowlist") {
192
+ if (this.config.allowFrom.includes(userId)) return true;
193
+ await this.sendMessage(chatId, `🦅 *HyperClaw*\n\nYou are not on the allowlist.`);
194
+ return false;
195
+ }
196
+ if (this.config.dmPolicy === "pairing") {
197
+ if (this.config.approvedPairings.includes(userId)) return true;
198
+ const upper = text.trim().toUpperCase();
199
+ if (this.config.pendingPairings[upper]) {
200
+ this.config.approvedPairings.push(userId);
201
+ delete this.config.pendingPairings[upper];
202
+ await this.saveState();
203
+ await this.sendMessage(chatId, `🦅 *Paired!* You can now send messages.`);
204
+ this.emit("pairing:approved", {
205
+ userId,
206
+ channelId: "telegram"
207
+ });
208
+ return true;
209
+ }
210
+ const code = generateCode();
211
+ this.config.pendingPairings[code] = userId;
212
+ await this.saveState();
213
+ await this.sendMessage(chatId, `🦅 *HyperClaw Pairing*\n\nSend the owner this code:\n\`${code}\`\n\nApprove with:\n\`hyperclaw pairing approve telegram ${code}\``);
214
+ console.log(chalk.default.cyan(` 🦅 Telegram pairing from ${userId} — code: ${code}`));
215
+ return false;
216
+ }
217
+ return false;
218
+ }
219
+ async sendMessage(chatId, text, opts = {}) {
220
+ const chunks = chunkText(text, 4096);
221
+ let last = null;
222
+ for (const chunk of chunks) last = await tgRequest(this.token, "sendMessage", {
223
+ chat_id: chatId,
224
+ text: chunk,
225
+ parse_mode: opts.parse_mode || "Markdown",
226
+ disable_web_page_preview: opts.disable_web_page_preview ?? true,
227
+ ...opts.reply_to_message_id ? { reply_to_message_id: opts.reply_to_message_id } : {},
228
+ ...opts.message_thread_id != null ? { message_thread_id: opts.message_thread_id } : {}
229
+ });
230
+ return last;
231
+ }
232
+ async sendTyping(chatId) {
233
+ await tgRequest(this.token, "sendChatAction", {
234
+ chat_id: chatId,
235
+ action: "typing"
236
+ }).catch(() => {});
237
+ }
238
+ /** Answer inline query (Telegram inline mode). Results shown when user types @botname &lt;query&gt; in any chat. */
239
+ async answerInlineQuery(queryId, results, opts) {
240
+ try {
241
+ const articles = results.map((r) => ({
242
+ type: "article",
243
+ id: r.id,
244
+ title: r.title,
245
+ description: r.description,
246
+ input_message_content: {
247
+ message_text: r.message_text,
248
+ parse_mode: r.parse_mode || "Markdown"
249
+ }
250
+ }));
251
+ await tgRequest(this.token, "answerInlineQuery", {
252
+ inline_query_id: queryId,
253
+ results: articles,
254
+ cache_time: opts?.cache_time ?? 60
255
+ });
256
+ return true;
257
+ } catch {
258
+ return false;
259
+ }
260
+ }
261
+ approvePairing(code) {
262
+ const upper = code.toUpperCase();
263
+ if (!this.config.pendingPairings[upper]) return false;
264
+ const userId = this.config.pendingPairings[upper];
265
+ this.config.approvedPairings.push(userId);
266
+ delete this.config.pendingPairings[upper];
267
+ this.saveState();
268
+ return true;
269
+ }
270
+ addToAllowlist(userId) {
271
+ if (!this.config.allowFrom.includes(userId)) {
272
+ this.config.allowFrom.push(userId);
273
+ this.saveState();
274
+ }
275
+ }
276
+ listPendingPairings() {
277
+ return Object.entries(this.config.pendingPairings).map(([code, userId]) => ({
278
+ code,
279
+ userId
280
+ }));
281
+ }
282
+ handleWebhookPayload(body) {
283
+ try {
284
+ this.handleUpdate(JSON.parse(body));
285
+ } catch {}
286
+ }
287
+ async loadState() {
288
+ try {
289
+ const s = await fs_extra.default.readJson(STATE_FILE);
290
+ this.offset = s.offset || 0;
291
+ if (s.pendingPairings) this.config.pendingPairings = s.pendingPairings;
292
+ if (s.approvedPairings) this.config.approvedPairings = s.approvedPairings;
293
+ } catch {}
294
+ }
295
+ async saveState() {
296
+ await fs_extra.default.ensureDir(path.default.dirname(STATE_FILE));
297
+ await fs_extra.default.writeJson(STATE_FILE, {
298
+ offset: this.offset,
299
+ pendingPairings: this.config.pendingPairings,
300
+ approvedPairings: this.config.approvedPairings
301
+ }, { spaces: 2 });
302
+ }
303
+ isRunning() {
304
+ return this.running;
305
+ }
306
+ getBotInfo() {
307
+ return this.botInfo;
308
+ }
309
+ };
310
+
311
+ //#endregion
312
+ exports.TelegramConnector = TelegramConnector;
@@ -0,0 +1,103 @@
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
+
5
+ //#region src/infra/cost-tracker.ts
6
+ /** Rough cost per 1M tokens by provider/model (Claude Sonnet ballpark). */
7
+ const DEFAULT_COST_PER_1M_INPUT = 3;
8
+ const DEFAULT_COST_PER_1M_OUTPUT = 15;
9
+ function estimateCost(usage, model) {
10
+ if (!usage) return 0;
11
+ const inp = (usage.input || 0) + (usage.cacheRead || 0);
12
+ const inputCost = inp / 1e6 * DEFAULT_COST_PER_1M_INPUT;
13
+ const outputCost = (usage.output || 0) / 1e6 * DEFAULT_COST_PER_1M_OUTPUT;
14
+ return inputCost + outputCost;
15
+ }
16
+ /** Path to cost log file for a session. */
17
+ function getCostLogPath(baseDir, sessionId) {
18
+ return path.default.join(baseDir, "costs", `session-${sessionId}.jsonl`);
19
+ }
20
+ /** Append a cost entry for a session. */
21
+ async function recordUsage(baseDir, sessionId, usage, opts) {
22
+ const costUsd = estimateCost(usage, opts?.model);
23
+ const entry = {
24
+ sessionId,
25
+ source: opts?.source,
26
+ tenantId: opts?.tenantId,
27
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
28
+ usage,
29
+ costUsd,
30
+ model: opts?.model
31
+ };
32
+ const dir = path.default.join(baseDir, "costs");
33
+ await fs_extra.default.ensureDir(dir);
34
+ const fp = getCostLogPath(baseDir, sessionId);
35
+ await fs_extra.default.appendFile(fp, JSON.stringify(entry) + "\n");
36
+ }
37
+ /** Read and aggregate all entries for a session. */
38
+ async function getSessionSummary(baseDir, sessionId) {
39
+ const fp = getCostLogPath(baseDir, sessionId);
40
+ if (!await fs_extra.default.pathExists(fp)) return {
41
+ input: 0,
42
+ output: 0,
43
+ cacheRead: 0,
44
+ costUsd: 0,
45
+ runs: 0
46
+ };
47
+ const lines = (await fs_extra.default.readFile(fp, "utf8")).trim().split("\n").filter(Boolean);
48
+ let input = 0, output = 0, cacheRead = 0, costUsd = 0;
49
+ for (const line of lines) try {
50
+ const e = JSON.parse(line);
51
+ input += e.usage.input || 0;
52
+ output += e.usage.output || 0;
53
+ cacheRead += e.usage.cacheRead || 0;
54
+ costUsd += e.costUsd || 0;
55
+ } catch {}
56
+ return {
57
+ input,
58
+ output,
59
+ cacheRead,
60
+ costUsd,
61
+ runs: lines.length
62
+ };
63
+ }
64
+ /** Get global summary across all sessions. */
65
+ async function getGlobalSummary(baseDir) {
66
+ const dir = path.default.join(baseDir, "costs");
67
+ if (!await fs_extra.default.pathExists(dir)) return {
68
+ sessions: 0,
69
+ totalInput: 0,
70
+ totalOutput: 0,
71
+ totalCacheRead: 0,
72
+ totalCostUsd: 0,
73
+ totalRuns: 0
74
+ };
75
+ const files = (await fs_extra.default.readdir(dir)).filter((f) => f.startsWith("session-") && f.endsWith(".jsonl"));
76
+ let totalInput = 0, totalOutput = 0, totalCacheRead = 0, totalCostUsd = 0, totalRuns = 0;
77
+ for (const f of files) {
78
+ const fp = path.default.join(dir, f);
79
+ const content = await fs_extra.default.readFile(fp, "utf8").catch(() => "");
80
+ for (const line of content.trim().split("\n").filter(Boolean)) try {
81
+ const e = JSON.parse(line);
82
+ totalInput += e.usage.input || 0;
83
+ totalOutput += e.usage.output || 0;
84
+ totalCacheRead += e.usage.cacheRead || 0;
85
+ totalCostUsd += e.costUsd || 0;
86
+ totalRuns++;
87
+ } catch {}
88
+ }
89
+ return {
90
+ sessions: files.length,
91
+ totalInput,
92
+ totalOutput,
93
+ totalCacheRead,
94
+ totalCostUsd,
95
+ totalRuns
96
+ };
97
+ }
98
+
99
+ //#endregion
100
+ exports.estimateCost = estimateCost;
101
+ exports.getGlobalSummary = getGlobalSummary;
102
+ exports.getSessionSummary = getSessionSummary;
103
+ exports.recordUsage = recordUsage;
@@ -0,0 +1,7 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ require('./paths-AIyBxIzm.js');
3
+ require('./paths-DPovhojT.js');
4
+ const require_credentials_store = require('./credentials-store-onL1tYct.js');
5
+
6
+ require_credentials_store.init_credentials_store();
7
+ exports.CredentialsStore = require_credentials_store.CredentialsStore;
@@ -0,0 +1,89 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ const require_paths = require('./paths-AIyBxIzm.js');
3
+ const require_paths$1 = require('./paths-DPovhojT.js');
4
+ const chalk = require_chunk.__toESM(require("chalk"));
5
+ const fs_extra = require_chunk.__toESM(require("fs-extra"));
6
+ const path = require_chunk.__toESM(require("path"));
7
+
8
+ //#region src/secrets/credentials-store.ts
9
+ var CredentialsStore;
10
+ var init_credentials_store = require_chunk.__esm({ "src/secrets/credentials-store.ts"() {
11
+ require_paths$1.init_paths();
12
+ CredentialsStore = class {
13
+ credsDir;
14
+ constructor(baseDir) {
15
+ const base = baseDir ?? require_paths.getHyperClawDir();
16
+ this.credsDir = path.default.join(base, "credentials");
17
+ }
18
+ filePath(providerId) {
19
+ const safe = providerId.replace(/[^a-zA-Z0-9_-]/g, "_");
20
+ return path.default.join(this.credsDir, `${safe}.json`);
21
+ }
22
+ async set(providerId, creds) {
23
+ await fs_extra.default.ensureDir(this.credsDir);
24
+ await fs_extra.default.chmod(this.credsDir, 448);
25
+ const record = {
26
+ ...creds,
27
+ providerId,
28
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
29
+ };
30
+ const fpath = this.filePath(providerId);
31
+ await fs_extra.default.writeJson(fpath, record, { spaces: 2 });
32
+ await fs_extra.default.chmod(fpath, 384);
33
+ }
34
+ async get(providerId) {
35
+ const fpath = this.filePath(providerId);
36
+ if (!await fs_extra.default.pathExists(fpath)) return null;
37
+ const stat = await fs_extra.default.stat(fpath);
38
+ if (process.platform !== "win32" && (stat.mode & 63) !== 0) {
39
+ console.log(chalk.default.yellow(` ⚠ Unsafe permissions on credentials/${providerId}.json — fixing...`));
40
+ await fs_extra.default.chmod(fpath, 384);
41
+ }
42
+ return fs_extra.default.readJson(fpath);
43
+ }
44
+ async remove(providerId) {
45
+ const fpath = this.filePath(providerId);
46
+ await fs_extra.default.remove(fpath);
47
+ console.log(chalk.default.green(` ✔ Credentials removed: ${providerId}`));
48
+ }
49
+ async list() {
50
+ if (!await fs_extra.default.pathExists(this.credsDir)) return [];
51
+ const files = await fs_extra.default.readdir(this.credsDir);
52
+ return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
53
+ }
54
+ async showList() {
55
+ const providers = await this.list();
56
+ console.log(chalk.default.bold.cyan("\n 🔐 CREDENTIALS\n"));
57
+ if (providers.length === 0) {
58
+ console.log(chalk.default.gray(" No credentials stored.\n"));
59
+ console.log(chalk.default.gray(" Add with: hyperclaw auth add <service_id> (for any API key)\n"));
60
+ console.log(chalk.default.gray(" Or: hyperclaw secrets set KEY=value (for .env vars)\n"));
61
+ return;
62
+ }
63
+ for (const p of providers) {
64
+ const cred = await this.get(p);
65
+ const hasKey = !!cred?.apiKey;
66
+ const hasRefresh = !!cred?.refreshToken;
67
+ const expiry = cred?.expiresAt ? new Date(cred.expiresAt) > /* @__PURE__ */ new Date() ? chalk.default.green("valid") : chalk.default.red("expired") : chalk.default.gray("no expiry");
68
+ console.log(` ${chalk.default.green("●")} ${chalk.default.white(p.padEnd(20))} ${hasKey ? chalk.default.cyan("api_key") : ""}${hasRefresh ? chalk.default.yellow(" refresh_token") : ""} ${expiry}`);
69
+ console.log(` ${chalk.default.gray(`Updated: ${cred?.updatedAt ? new Date(cred.updatedAt).toLocaleString() : "unknown"}`)}`);
70
+ console.log();
71
+ }
72
+ console.log(chalk.default.gray(" credentials/ — stored at ~/.hyperclaw/credentials/*.json (mode 0600)\n"));
73
+ }
74
+ };
75
+ } });
76
+
77
+ //#endregion
78
+ Object.defineProperty(exports, 'CredentialsStore', {
79
+ enumerable: true,
80
+ get: function () {
81
+ return CredentialsStore;
82
+ }
83
+ });
84
+ Object.defineProperty(exports, 'init_credentials_store', {
85
+ enumerable: true,
86
+ get: function () {
87
+ return init_credentials_store;
88
+ }
89
+ });
@@ -0,0 +1,89 @@
1
+ const require_chunk = require('./chunk-jS-bbMI5.js');
2
+ const require_paths = require('./paths-AIyBxIzm.js');
3
+ const require_paths$1 = require('./paths-DPovhojT.js');
4
+ const fs_extra = require_chunk.__toESM(require("fs-extra"));
5
+ const path = require_chunk.__toESM(require("path"));
6
+
7
+ //#region src/services/cron-tasks.ts
8
+ require_paths$1.init_paths();
9
+ const getCronTasksFile = () => path.default.join(require_paths.getHyperClawDir(), "cron-tasks.json");
10
+ let tasks = [];
11
+ async function loadCronTasks() {
12
+ try {
13
+ tasks = await fs_extra.default.readJson(getCronTasksFile());
14
+ } catch {
15
+ tasks = [];
16
+ }
17
+ return tasks;
18
+ }
19
+ async function saveCronTasks() {
20
+ const f = getCronTasksFile();
21
+ await fs_extra.default.ensureDir(path.default.dirname(f));
22
+ await fs_extra.default.writeJson(f, tasks, { spaces: 2 });
23
+ }
24
+ function addCronTask(schedule, prompt, name, skillId) {
25
+ const id = `task-${Date.now().toString(36)}`;
26
+ const task = {
27
+ id,
28
+ schedule,
29
+ prompt,
30
+ name,
31
+ skillId,
32
+ enabled: true,
33
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
34
+ };
35
+ tasks.push(task);
36
+ return task;
37
+ }
38
+ function removeCronTask(id) {
39
+ const i = tasks.findIndex((t) => t.id === id);
40
+ if (i >= 0) {
41
+ tasks.splice(i, 1);
42
+ return true;
43
+ }
44
+ return false;
45
+ }
46
+ async function runCronTask(task, port = 18789) {
47
+ const http = await import("http");
48
+ return new Promise((resolve, reject) => {
49
+ const payload = JSON.stringify({
50
+ message: task.prompt,
51
+ ...task.skillId ? { skillId: task.skillId } : {}
52
+ });
53
+ const req = http.request({
54
+ hostname: "127.0.0.1",
55
+ port,
56
+ path: "/api/webhook/inbound",
57
+ method: "POST",
58
+ headers: {
59
+ "Content-Type": "application/json",
60
+ "Content-Length": Buffer.byteLength(payload)
61
+ }
62
+ }, (res) => {
63
+ let data = "";
64
+ res.on("data", (c) => data += c);
65
+ res.on("end", async () => {
66
+ task.lastRunAt = (/* @__PURE__ */ new Date()).toISOString();
67
+ await saveCronTasks().catch(() => {});
68
+ resolve();
69
+ });
70
+ });
71
+ req.on("error", (e) => {
72
+ console.error(`[cron] task ${task.id} failed:`, e.message);
73
+ resolve();
74
+ });
75
+ req.setTimeout(6e4, () => {
76
+ req.destroy();
77
+ resolve();
78
+ });
79
+ req.write(payload);
80
+ req.end();
81
+ });
82
+ }
83
+
84
+ //#endregion
85
+ exports.addCronTask = addCronTask;
86
+ exports.loadCronTasks = loadCronTasks;
87
+ exports.removeCronTask = removeCronTask;
88
+ exports.runCronTask = runCronTask;
89
+ exports.saveCronTasks = saveCronTasks;