hyperclaw 4.0.1 → 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 (277) hide show
  1. package/README.md +58 -4
  2. package/dist/a2ui-protocol-CT_jDEU9.js +75 -0
  3. package/dist/a2ui-protocol-CfBI44-Q.js +75 -0
  4. package/dist/agents-routing-683Q2JGp.js +129 -0
  5. package/dist/agents-routing-BpZBswBH.js +4 -0
  6. package/dist/agents-routing-ChHiZp36.js +327 -0
  7. package/dist/agents-routing-ChqZ6l2S.js +4 -0
  8. package/dist/api-keys-guide-BCcOl0Q7.js +149 -0
  9. package/dist/api-keys-guide-Dq5Obbp4.js +149 -0
  10. package/dist/audit-BYxPlnTQ.js +248 -0
  11. package/dist/audit-BaIiyWFu.js +441 -0
  12. package/dist/bounty-tools-C6LyzxM-.js +211 -0
  13. package/dist/bounty-tools-DWudyZie.js +211 -0
  14. package/dist/browser-tools-BsTeGMnX.js +5 -0
  15. package/dist/browser-tools-CQBSbIuO.js +5 -0
  16. package/dist/browser-tools-D8_rLe2p.js +179 -0
  17. package/dist/browser-tools-YQmwRLLM.js +179 -0
  18. package/dist/claw-tasks-BRLUvFRD.js +80 -0
  19. package/dist/claw-tasks-CgTsiNE8.js +80 -0
  20. package/dist/connector-3HnyH8fn.js +167 -0
  21. package/dist/connector-5N0-X_xs.js +194 -0
  22. package/dist/connector-6PMZo5Ky.js +189 -0
  23. package/dist/connector-B3v0qcXg.js +425 -0
  24. package/dist/connector-B6eoF3DD.js +181 -0
  25. package/dist/connector-B8R3iBY1.js +280 -0
  26. package/dist/connector-B9tLG8UZ.js +196 -0
  27. package/dist/connector-BAM-08NN.js +189 -0
  28. package/dist/connector-BC8FIVu4.js +181 -0
  29. package/dist/connector-BDmwwaVc.js +213 -0
  30. package/dist/connector-BGjbBy69.js +225 -0
  31. package/dist/connector-BO2SRzfG.js +218 -0
  32. package/dist/connector-BOlqjXWP.js +182 -0
  33. package/dist/connector-BP8zsbP8.js +189 -0
  34. package/dist/connector-BPoSevxp.js +286 -0
  35. package/dist/connector-BRHj773i.js +163 -0
  36. package/dist/connector-BToxU-jV.js +267 -0
  37. package/dist/connector-BfXky0L3.js +167 -0
  38. package/dist/connector-BiiSJpx3.js +192 -0
  39. package/dist/connector-BliDVsJQ.js +239 -0
  40. package/dist/connector-BnDmIhIu.js +85 -0
  41. package/dist/connector-Bv6s9oP7.js +88 -0
  42. package/dist/connector-By5wWGTR.js +343 -0
  43. package/dist/connector-C1BaFFgN.js +213 -0
  44. package/dist/connector-C1HSoUyk.js +189 -0
  45. package/dist/connector-CKQHZOXg.js +568 -0
  46. package/dist/connector-CRRWY5Wv.js +167 -0
  47. package/dist/connector-CRl-iidy.js +239 -0
  48. package/dist/connector-CXPQVGyI.js +85 -0
  49. package/dist/connector-Cdk1CXKi.js +194 -0
  50. package/dist/connector-Ci9glMD-.js +340 -0
  51. package/dist/connector-CjtZIEDj.js +181 -0
  52. package/dist/connector-Ck6JtOsX.js +531 -0
  53. package/dist/connector-CwlgFgjx.js +181 -0
  54. package/dist/connector-D8Kelee0.js +286 -0
  55. package/dist/connector-DAnRJ0oP.js +162 -0
  56. package/dist/connector-DFchk6l7.js +178 -0
  57. package/dist/connector-DKw7tRAy.js +192 -0
  58. package/dist/connector-DRv1ahC_.js +2 -2
  59. package/dist/connector-DU63KW94.js +165 -0
  60. package/dist/connector-DXTp5PE8.js +508 -0
  61. package/dist/connector-Dbvb1Cj9.js +280 -0
  62. package/dist/connector-DcZdQcgR.js +173 -0
  63. package/dist/connector-Dih6dUPP.js +173 -0
  64. package/dist/connector-DqTH_tPX.js +182 -0
  65. package/dist/connector-DrnEiiyP.js +419 -0
  66. package/dist/connector-DtR5GGTX.js +167 -0
  67. package/dist/connector-DxKL8VvZ.js +182 -0
  68. package/dist/connector-T_YdZtzv.js +162 -0
  69. package/dist/connector-Tky_qS_K.js +350 -0
  70. package/dist/connector-ZSc3oTTy.js +305 -0
  71. package/dist/connector-i4gOS9xL.js +154 -0
  72. package/dist/connector-rHXE1ZD2.js +167 -0
  73. package/dist/connector-sW5yhU1m.js +498 -0
  74. package/dist/connector-u3ICd3Ic.js +552 -0
  75. package/dist/connector-wdUXChwa.js +172 -0
  76. package/dist/cost-tracker-DD9wtWsr.js +103 -0
  77. package/dist/cost-tracker-pVE15Yq4.js +103 -0
  78. package/dist/credentials-store-BvnMPJwi.js +4 -0
  79. package/dist/credentials-store-C6ir0Dae.js +4 -0
  80. package/dist/credentials-store-H13LqOwJ.js +77 -0
  81. package/dist/credentials-store-sb-TRLwR.js +77 -0
  82. package/dist/cron-tasks-Bli7Kzd2.js +82 -0
  83. package/dist/cron-tasks-BvDFNyiE.js +82 -0
  84. package/dist/daemon-Bg4GtCmc.js +318 -0
  85. package/dist/daemon-DhmwY8k4.js +5 -0
  86. package/dist/delivery-BmIYy9VQ.js +4 -0
  87. package/dist/delivery-D5Z98EVq.js +95 -0
  88. package/dist/delivery-DCOXhXEO.js +5 -0
  89. package/dist/delivery-pWUPBp1F.js +95 -0
  90. package/dist/destructive-gate-D6vWOdEl.js +101 -0
  91. package/dist/destructive-gate-m-dWqUFg.js +101 -0
  92. package/dist/developer-keys-CPWT7Q6S.js +8 -0
  93. package/dist/developer-keys-DrrcUqFa.js +127 -0
  94. package/dist/developer-keys-JaJK3T27.js +127 -0
  95. package/dist/developer-keys-kyqmtWK3.js +8 -0
  96. package/dist/doctor-3oi89QIc.js +175 -0
  97. package/dist/doctor-BvCe8BBk.js +230 -0
  98. package/dist/doctor-Cf1XSfp9.js +4 -0
  99. package/dist/doctor-CxyPLYsJ.js +6 -0
  100. package/dist/engine-B4eMiTgl.js +7 -0
  101. package/dist/engine-B8M7dYul.js +7 -0
  102. package/dist/engine-BhT-1M9W.js +256 -0
  103. package/dist/engine-CEDSqXfw.js +256 -0
  104. package/dist/engine-D49jnSd_.js +256 -0
  105. package/dist/engine-Da4JMNpI.js +7 -0
  106. package/dist/env-resolve-CiXbWYwe.js +10 -0
  107. package/dist/env-resolve-CmGWhWXJ.js +115 -0
  108. package/dist/env-resolve-DWOQ45jG.js +9 -0
  109. package/dist/env-resolve-szSWl0UF.js +94 -0
  110. package/dist/extraction-tools-D3qDFBJ1.js +91 -0
  111. package/dist/extraction-tools-DLr_AEwq.js +5 -0
  112. package/dist/extraction-tools-HOZstZ0y.js +91 -0
  113. package/dist/extraction-tools-m4lmAv7l.js +5 -0
  114. package/dist/form_data-B_hIUrxU.js +8657 -0
  115. package/dist/form_data-Cz040rio.js +8657 -0
  116. package/dist/gmail-watch-setup-Czt8rXaX.js +40 -0
  117. package/dist/gmail-watch-setup-Du7DVV7S.js +40 -0
  118. package/dist/health-B-asI__D.js +6 -0
  119. package/dist/health-Ds2YlpTB.js +152 -0
  120. package/dist/heartbeat-engine-BYT5ayQH.js +83 -0
  121. package/dist/heartbeat-engine-CRqfPcFM.js +83 -0
  122. package/dist/hub-D0XwdjM-.js +515 -0
  123. package/dist/hub-DTsqe5Bt.js +6 -0
  124. package/dist/hub-FrPTA33j.js +515 -0
  125. package/dist/hub-LiD5Iztb.js +6 -0
  126. package/dist/hyperclawbot-D9KCtc4P.js +480 -0
  127. package/dist/hyperclawbot-Dw27pJo4.js +480 -0
  128. package/dist/hyperclawbot-zvczQgKx.js +505 -0
  129. package/dist/inference-BKVkBREb.js +6 -0
  130. package/dist/inference-CTWJeX9Q.js +922 -0
  131. package/dist/inference-DCXH4Q3x.js +922 -0
  132. package/dist/inference-ix607p7k.js +6 -0
  133. package/dist/knowledge-graph-DqA-Fztl.js +131 -0
  134. package/dist/knowledge-graph-iBG76fvm.js +131 -0
  135. package/dist/loader-CC45xGpC.js +4 -0
  136. package/dist/loader-CISCqBto.js +400 -0
  137. package/dist/loader-CYMQ8VOS.js +4 -0
  138. package/dist/loader-CnEdOyjT.js +400 -0
  139. package/dist/logger-8tEtAd3y.js +83 -0
  140. package/dist/logger-ybOp7VOC.js +83 -0
  141. package/dist/manager-03ipO9R0.js +105 -0
  142. package/dist/manager-BpDfbDjg.js +117 -0
  143. package/dist/manager-Bxl0sqlh.js +4 -0
  144. package/dist/manager-CPjeRe-6.js +4 -0
  145. package/dist/manager-CrVDn6eN.js +6 -0
  146. package/dist/manager-Cwzj7w5R.js +105 -0
  147. package/dist/manager-DLmZI-9R.js +6 -0
  148. package/dist/manager-DSGhn5i3.js +117 -0
  149. package/dist/manager-DgyF52mg.js +218 -0
  150. package/dist/manager-Dm8nrMFx.js +40 -0
  151. package/dist/manager-FCgF1plu.js +218 -0
  152. package/dist/manager-rgCsaWT1.js +40 -0
  153. package/dist/mcp-B_9Ber63.js +139 -0
  154. package/dist/mcp-CfoSU4Uz.js +139 -0
  155. package/dist/mcp-loader-DSM5UiFG.js +94 -0
  156. package/dist/mcp-loader-DkRBsLpk.js +94 -0
  157. package/dist/mcp-loader-j5ZLLw5O.js +94 -0
  158. package/dist/memory-BI1kPkAN.js +4 -0
  159. package/dist/memory-BVFGkxxK.js +270 -0
  160. package/dist/memory-BlHL7JCO.js +4 -0
  161. package/dist/memory-DsS_eFvJ.js +270 -0
  162. package/dist/memory-auto-Bc7euou4.js +306 -0
  163. package/dist/memory-auto-BkvtSFUw.js +5 -0
  164. package/dist/memory-auto-Bnz_-1wP.js +306 -0
  165. package/dist/memory-auto-DPfbkMVt.js +5 -0
  166. package/dist/memory-integration-DZExqWr4.js +91 -0
  167. package/dist/memory-integration-cSYkZyEo.js +91 -0
  168. package/dist/moltbook-B6ZeGN5_.js +81 -0
  169. package/dist/moltbook-BtLDZTfM.js +81 -0
  170. package/dist/node-Dw2Gi-cP.js +222 -0
  171. package/dist/node-pwL6O_KX.js +222 -0
  172. package/dist/nodes-registry-B8dmrlLv.js +52 -0
  173. package/dist/nodes-registry-CsPm_-CJ.js +52 -0
  174. package/dist/oauth-flow-CpWlgvNB.js +150 -0
  175. package/dist/oauth-flow-DQPvMHRH.js +150 -0
  176. package/dist/oauth-provider-BZb6qOw5.js +110 -0
  177. package/dist/oauth-provider-Uo4Nib_c.js +110 -0
  178. package/dist/observability-B43YvNQV.js +89 -0
  179. package/dist/observability-BV-Yx0V9.js +89 -0
  180. package/dist/onboard-0WoDxbv_.js +10 -0
  181. package/dist/onboard-BXNXCQp4.js +4070 -0
  182. package/dist/onboard-Bd_wsYdi.js +4086 -0
  183. package/dist/onboard-CAN7x3me.js +3026 -0
  184. package/dist/onboard-DnegOHMh.js +4 -4
  185. package/dist/onboard-RYtDlYBw.js +9 -0
  186. package/dist/onboard-aTwlQs-4.js +9 -0
  187. package/dist/orchestrator-BSp2M5EU.js +189 -0
  188. package/dist/orchestrator-C7ko5tWa.js +6 -0
  189. package/dist/orchestrator-DfPkIx2Z.js +6 -0
  190. package/dist/orchestrator-DmnEvMaL.js +189 -0
  191. package/dist/orchestrator-NJQsmiBE.js +189 -0
  192. package/dist/orchestrator-RI3bpqqc.js +6 -0
  193. package/dist/pairing-6iM27aD8.js +196 -0
  194. package/dist/pairing-DU0_J28n.js +87 -0
  195. package/dist/pairing-DWllbSbO.js +4 -0
  196. package/dist/pairing-dGoiGepK.js +4 -0
  197. package/dist/pc-access-CgCsYrpt.js +8 -0
  198. package/dist/pc-access-Ly-uA8mn.js +8 -0
  199. package/dist/pc-access-NxBvTrRj.js +819 -0
  200. package/dist/pc-access-_iH2aorG.js +819 -0
  201. package/dist/pending-approval-CUXjysAo.js +22 -0
  202. package/dist/pending-approval-DIHvwwWS.js +22 -0
  203. package/dist/puppeteer-2o3QOwAy.js +2 -2
  204. package/dist/puppeteer-BYTMp3BI.js +2 -2
  205. package/dist/puppeteer-DQ45qwWk.js +2 -2
  206. package/dist/reminders-store-D79qdfN0.js +58 -0
  207. package/dist/reminders-store-Drjed_-h.js +58 -0
  208. package/dist/renderer-BVQrd0_g.js +225 -0
  209. package/dist/renderer-pqlDRKbH.js +225 -0
  210. package/dist/rules-BE4GV6cV.js +103 -0
  211. package/dist/rules-BooT_qFP.js +103 -0
  212. package/dist/run-main.js +1649 -1227
  213. package/dist/runner-D1rjuMTJ.js +810 -0
  214. package/dist/runner-DatMMYYE.js +1271 -0
  215. package/dist/sdk/index.js +2 -2
  216. package/dist/sdk/index.mjs +2 -2
  217. package/dist/security-BqNyT4ID.js +4 -0
  218. package/dist/security-C-5URby1.js +73 -0
  219. package/dist/security-_xve79aq.js +4 -0
  220. package/dist/security-tpgqPWWH.js +73 -0
  221. package/dist/server-0kgyELx4.js +1047 -0
  222. package/dist/server-BIuTobTC.js +4 -0
  223. package/dist/server-BRlCEjyT.js +1047 -0
  224. package/dist/server-CCI1hv45.js +2 -2
  225. package/dist/server-D4wVHiX9.js +4 -0
  226. package/dist/server-DU9POoWc.js +4 -0
  227. package/dist/server-Dh3JlBFB.js +1255 -0
  228. package/dist/session-store-BUiPz0Vv.js +5 -0
  229. package/dist/session-store-CujxByI6.js +113 -0
  230. package/dist/session-store-is4B6qmD.js +113 -0
  231. package/dist/session-store-qpJUg2M1.js +5 -0
  232. package/dist/sessions-tools-CB2qbwIk.js +5 -0
  233. package/dist/sessions-tools-CbUTFe4i.js +5 -0
  234. package/dist/sessions-tools-CeqD7iil.js +95 -0
  235. package/dist/sessions-tools-DHMaTZIs.js +95 -0
  236. package/dist/skill-loader-BaNLVmJy.js +7 -0
  237. package/dist/skill-loader-BkceKkIg.js +7 -0
  238. package/dist/skill-loader-DhgIwK4J.js +159 -0
  239. package/dist/skill-loader-HgpF6Vqs.js +159 -0
  240. package/dist/skill-runtime--LqxWrp5.js +102 -0
  241. package/dist/skill-runtime-C5l0Tgt-.js +5 -0
  242. package/dist/skill-runtime-CJN24QPW.js +102 -0
  243. package/dist/skill-runtime-DsXK_HYG.js +102 -0
  244. package/dist/skill-runtime-IVTiqrMR.js +5 -0
  245. package/dist/skill-runtime-w1ig_lcw.js +5 -0
  246. package/dist/src-BEVLgaF1.js +63 -0
  247. package/dist/src-Bgu_OxTQ.js +458 -0
  248. package/dist/src-Bq-oKt7Z.js +458 -0
  249. package/dist/src-BxPHKO5x.js +63 -0
  250. package/dist/src-DIc-L2IG.js +20 -0
  251. package/dist/src-DWCUhnD4.js +20 -0
  252. package/dist/src-cfRTjFef.js +63 -0
  253. package/dist/src-g_rNx5rh.js +458 -0
  254. package/dist/sub-agent-tools-BD9DF8_g.js +39 -0
  255. package/dist/sub-agent-tools-CHQoHz9c.js +39 -0
  256. package/dist/sub-agent-tools-V7b3T9_s.js +39 -0
  257. package/dist/theme-DcxwcUgZ.js +180 -0
  258. package/dist/theme-cx0fkgWC.js +8 -0
  259. package/dist/tool-policy-CNT-mF2Z.js +189 -0
  260. package/dist/tool-policy-DNvNRnve.js +189 -0
  261. package/dist/tts-elevenlabs-BRosZv-f.js +61 -0
  262. package/dist/tts-elevenlabs-BUOGKL-k.js +61 -0
  263. package/dist/update-check-BD4qH7Am.js +81 -0
  264. package/dist/update-check-C2Dz85wJ.js +81 -0
  265. package/dist/vision-BMmiIKy7.js +121 -0
  266. package/dist/vision-DRq-f-Dj.js +121 -0
  267. package/dist/vision-tools-CFZEpQKm.js +5 -0
  268. package/dist/vision-tools-CQnBI9aa.js +51 -0
  269. package/dist/vision-tools-DVuYc17I.js +51 -0
  270. package/dist/vision-tools-U3YC4L-g.js +5 -0
  271. package/dist/voice-transcription-B555DbWR.js +138 -0
  272. package/dist/voice-transcription-CgWq54hn.js +138 -0
  273. package/dist/website-watch-tools-Bk_TnwuE.js +5 -0
  274. package/dist/website-watch-tools-DFMrJU-R.js +139 -0
  275. package/dist/website-watch-tools-DraMPxdl.js +139 -0
  276. package/dist/website-watch-tools-Du3W5sN7.js +5 -0
  277. package/package.json +1 -1
@@ -0,0 +1,1047 @@
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 crypto = require_chunk.__toESM(require("crypto"));
6
+ const child_process = require_chunk.__toESM(require("child_process"));
7
+ const http = require_chunk.__toESM(require("http"));
8
+ const ws = require_chunk.__toESM(require("ws"));
9
+
10
+ //#region packages/gateway/src/server.ts
11
+ let activeServer = null;
12
+ var GatewayServer = class {
13
+ wss = null;
14
+ httpServer = null;
15
+ sessions = /* @__PURE__ */ new Map();
16
+ transcripts = /* @__PURE__ */ new Map();
17
+ sessionStore = null;
18
+ config;
19
+ startedAt = "";
20
+ stopCron = null;
21
+ channelRunner = null;
22
+ constructor(config) {
23
+ this.config = config;
24
+ }
25
+ async start() {
26
+ this.httpServer = http.default.createServer((req, res) => {
27
+ this.handleHttp(req, res);
28
+ });
29
+ this.wss = new ws.WebSocketServer({ server: this.httpServer });
30
+ this.wss.on("connection", this.handleConnection.bind(this));
31
+ await new Promise((resolve, reject) => {
32
+ this.httpServer.listen(this.config.port, this.config.bind, () => resolve());
33
+ this.httpServer.on("error", reject);
34
+ });
35
+ this.startedAt = (/* @__PURE__ */ new Date()).toISOString();
36
+ activeServer = this;
37
+ try {
38
+ this.sessionStore = await this.config.deps.createSessionStore(this.config.deps.getHyperClawDir());
39
+ } catch (_) {
40
+ this.sessionStore = null;
41
+ }
42
+ const icon = this.config.daemonMode ? "🩸" : "🦅";
43
+ const color = this.config.daemonMode ? chalk.default.red.bind(chalk.default) : chalk.default.hex("#06b6d4");
44
+ console.log(color(`\n ${icon} Gateway started: ws://${this.config.bind}:${this.config.port}\n`));
45
+ this.channelRunner = await this.config.deps.startChannelRunners({
46
+ port: this.config.port,
47
+ bind: this.config.bind,
48
+ authToken: this.config.deps.resolveGatewayToken(this.config.authToken)
49
+ });
50
+ if (this.config.hooks && this.config.deps.createHookLoader) {
51
+ const loader = this.config.deps.createHookLoader();
52
+ loader.execute("gateway:start", {}).catch(() => {});
53
+ this.stopCron = loader.startCronScheduler();
54
+ }
55
+ }
56
+ async stop() {
57
+ if (this.channelRunner) {
58
+ await this.channelRunner.stop();
59
+ this.channelRunner = null;
60
+ }
61
+ if (this.stopCron) {
62
+ this.stopCron();
63
+ this.stopCron = null;
64
+ }
65
+ for (const s of this.sessions.values()) s.socket.close(1001, "Gateway shutting down");
66
+ this.sessions.clear();
67
+ this.wss?.close();
68
+ await new Promise((resolve) => this.httpServer?.close(() => resolve()));
69
+ activeServer = null;
70
+ }
71
+ /** Returns false and sends 401 if auth required but missing/invalid. */
72
+ async requireAuth(req, res) {
73
+ const token = this.config.deps.resolveGatewayToken(this.config.authToken);
74
+ const auth = req.headers.authorization;
75
+ if (!token && !auth) return true;
76
+ if (!auth || !auth.startsWith("Bearer ")) {
77
+ res.writeHead(401, { "Content-Type": "application/json" });
78
+ res.end(JSON.stringify({
79
+ error: "Unauthorized",
80
+ hint: "Authorization: Bearer <gateway_token_or_developer_key>"
81
+ }));
82
+ return false;
83
+ }
84
+ const bearer = auth.slice(7);
85
+ if (token && bearer === token) return true;
86
+ if (this.config.deps.validateApiAuth) {
87
+ const ok = await this.config.deps.validateApiAuth(bearer);
88
+ if (ok) return true;
89
+ }
90
+ res.writeHead(401, { "Content-Type": "application/json" });
91
+ res.end(JSON.stringify({
92
+ error: "Unauthorized",
93
+ hint: "Authorization: Bearer <gateway_token_or_developer_key>"
94
+ }));
95
+ return false;
96
+ }
97
+ async handleHttp(req, res) {
98
+ const url = (req.url || "/").split("?")[0];
99
+ res.setHeader("Access-Control-Allow-Origin", "*");
100
+ res.setHeader("Content-Type", "application/json");
101
+ if (req.method === "OPTIONS") {
102
+ res.writeHead(204);
103
+ res.end();
104
+ return;
105
+ }
106
+ if (url === "/api/v1/check") {
107
+ res.writeHead(200);
108
+ res.end(JSON.stringify({
109
+ ok: true,
110
+ service: "hyperclaw",
111
+ version: "4.0.2"
112
+ }));
113
+ return;
114
+ }
115
+ if (url === "/api/v1/pi" && req.method === "POST") {
116
+ if (!await this.requireAuth(req, res)) return;
117
+ let body = "";
118
+ req.on("data", (c) => body += c);
119
+ req.on("end", async () => {
120
+ try {
121
+ const handler = this.config.deps.createPiRPCHandler((msg, opts) => this.callAgent(msg, {
122
+ currentSessionId: opts?.currentSessionId,
123
+ source: opts?.source
124
+ }), () => this.getSessionsList());
125
+ const rpcReq = JSON.parse(body || "{}");
126
+ const rpcRes = await handler(rpcReq);
127
+ res.writeHead(200);
128
+ res.end(JSON.stringify(rpcRes));
129
+ } catch (e) {
130
+ res.writeHead(500);
131
+ res.end(JSON.stringify({
132
+ jsonrpc: "2.0",
133
+ error: {
134
+ code: -32700,
135
+ message: e.message || "Parse error"
136
+ }
137
+ }));
138
+ }
139
+ });
140
+ return;
141
+ }
142
+ if (url === "/api/status") {
143
+ const cfg = this.loadConfig();
144
+ res.writeHead(200);
145
+ res.end(JSON.stringify({
146
+ running: true,
147
+ port: this.config.port,
148
+ channels: this.config.enabledChannels,
149
+ model: cfg?.provider?.modelId || "unknown",
150
+ agentName: cfg?.identity?.agentName || "Hyper",
151
+ sessions: this.sessions.size,
152
+ uptime: this.startedAt ? `${Math.round((Date.now() - new Date(this.startedAt).getTime()) / 1e3)}s` : "0s"
153
+ }));
154
+ return;
155
+ }
156
+ if (url === "/api/traces" && req.method === "GET") {
157
+ if (!await this.requireAuth(req, res)) return;
158
+ (async () => {
159
+ const params = new URL(req.url || "", "http://localhost").searchParams;
160
+ const limit = Math.min(100, parseInt(params.get("limit") || "50", 10) || 50);
161
+ try {
162
+ const traces = this.config.deps.listTraces ? await this.config.deps.listTraces(this.config.deps.getHyperClawDir(), limit) : [];
163
+ res.writeHead(200);
164
+ res.end(JSON.stringify({ traces }));
165
+ } catch {
166
+ res.writeHead(500);
167
+ res.end(JSON.stringify({ error: "Failed to list traces" }));
168
+ }
169
+ })();
170
+ return;
171
+ }
172
+ if (url === "/api/costs" && req.method === "GET") {
173
+ if (!await this.requireAuth(req, res)) return;
174
+ (async () => {
175
+ const params = new URL(req.url || "", "http://localhost").searchParams;
176
+ const sessionId = params.get("sessionId");
177
+ const hcDir = this.config.deps.getHyperClawDir();
178
+ try {
179
+ if (sessionId && this.config.deps.getSessionSummary) {
180
+ const summary = await this.config.deps.getSessionSummary(hcDir, sessionId);
181
+ res.writeHead(200);
182
+ res.end(JSON.stringify({
183
+ sessionId,
184
+ summary
185
+ }));
186
+ } else if (this.config.deps.getGlobalSummary) {
187
+ const summary = await this.config.deps.getGlobalSummary(this.config.deps.getHyperClawDir());
188
+ res.writeHead(200);
189
+ res.end(JSON.stringify({ summary }));
190
+ }
191
+ } catch (e) {
192
+ res.writeHead(500);
193
+ res.end(JSON.stringify({ error: e.message }));
194
+ }
195
+ })();
196
+ return;
197
+ }
198
+ if (url === "/api/remote/restart" && req.method === "POST") {
199
+ const auth = req.headers.authorization;
200
+ const token = this.config.deps.resolveGatewayToken(this.config.authToken);
201
+ if (token && auth !== `Bearer ${token}`) {
202
+ res.writeHead(401);
203
+ res.end(JSON.stringify({ error: "Unauthorized" }));
204
+ return;
205
+ }
206
+ (async () => {
207
+ const hcDir = this.config.deps.getHyperClawDir();
208
+ const pidFile = path.default.join(hcDir, "gateway.pid");
209
+ let didSpawn = false;
210
+ try {
211
+ if (await fs_extra.default.pathExists(pidFile)) {
212
+ const storedPid = parseInt(await fs_extra.default.readFile(pidFile, "utf8"), 10);
213
+ if (storedPid === process.pid && this.config.daemonMode) {
214
+ const runMainPath = this.config.deps.getRunMainPath?.() || process.argv[1] || require.main?.filename || path.default.resolve(process.cwd(), "dist/run-main.js");
215
+ const child = (0, child_process.spawn)(process.execPath, [
216
+ runMainPath,
217
+ "daemon",
218
+ "restart"
219
+ ], {
220
+ detached: true,
221
+ stdio: "ignore",
222
+ env: process.env,
223
+ cwd: process.cwd()
224
+ });
225
+ child.unref();
226
+ didSpawn = true;
227
+ }
228
+ }
229
+ } catch {}
230
+ res.writeHead(200);
231
+ res.end(JSON.stringify({
232
+ accepted: true,
233
+ message: didSpawn ? "Restarting daemon..." : "Gateway does not run as daemon. Run: hyperclaw daemon start, or from remote: ssh user@host \"hyperclaw daemon restart\"",
234
+ restarted: didSpawn
235
+ }));
236
+ })();
237
+ return;
238
+ }
239
+ if (url === "/api/v1/tts" && req.method === "POST") {
240
+ if (!await this.requireAuth(req, res)) return;
241
+ let body = "";
242
+ req.on("data", (c) => body += c);
243
+ req.on("end", async () => {
244
+ try {
245
+ const { text } = JSON.parse(body || "{}");
246
+ const cfg = this.loadConfig();
247
+ const apiKey = cfg?.talkMode?.apiKey || process.env.ELEVENLABS_API_KEY;
248
+ if (!apiKey || !text) {
249
+ res.writeHead(400);
250
+ res.end(JSON.stringify({ error: "Missing text or ELEVENLABS_API_KEY" }));
251
+ return;
252
+ }
253
+ const audio = this.config.deps.textToSpeech ? await this.config.deps.textToSpeech(text.slice(0, 4e3), {
254
+ apiKey,
255
+ voiceId: cfg?.talkMode?.voiceId,
256
+ modelId: cfg?.talkMode?.modelId
257
+ }) : null;
258
+ if (!audio) {
259
+ res.writeHead(502);
260
+ res.end(JSON.stringify({ error: "TTS failed" }));
261
+ return;
262
+ }
263
+ res.writeHead(200, { "Content-Type": "application/json" });
264
+ res.end(JSON.stringify({
265
+ format: "mp3",
266
+ data: audio
267
+ }));
268
+ } catch (e) {
269
+ res.writeHead(500);
270
+ res.end(JSON.stringify({ error: e.message }));
271
+ }
272
+ });
273
+ return;
274
+ }
275
+ if (url === "/api/nodes" && req.method === "GET") {
276
+ if (!await this.requireAuth(req, res)) return;
277
+ try {
278
+ const NR = this.config.deps.NodeRegistry;
279
+ const nodes = NR ? NR.getNodes().map((n) => ({
280
+ nodeId: n.nodeId,
281
+ platform: n.platform,
282
+ capabilities: n.capabilities,
283
+ deviceName: n.deviceName,
284
+ connectedAt: n.connectedAt,
285
+ lastSeenAt: n.lastSeenAt
286
+ })) : [];
287
+ res.writeHead(200);
288
+ res.end(JSON.stringify({ nodes }));
289
+ } catch (e) {
290
+ res.writeHead(500);
291
+ res.end(JSON.stringify({ error: e.message }));
292
+ }
293
+ return;
294
+ }
295
+ if (url === "/api/chat" && req.method === "POST") {
296
+ if (!await this.requireAuth(req, res)) return;
297
+ let body = "";
298
+ req.on("data", (c) => body += c);
299
+ req.on("end", async () => {
300
+ try {
301
+ const { message } = JSON.parse(body);
302
+ const source = req.headers["x-hyperclaw-source"] || "unknown";
303
+ const response = await this.callAgent(message, { source });
304
+ res.writeHead(200);
305
+ res.end(JSON.stringify({ response }));
306
+ } catch (e) {
307
+ res.writeHead(500);
308
+ res.end(JSON.stringify({ error: e.message }));
309
+ }
310
+ });
311
+ return;
312
+ }
313
+ if (url === "/api/webhook/inbound" && req.method === "POST") {
314
+ if (!await this.requireAuth(req, res)) return;
315
+ let body = "";
316
+ req.on("data", (c) => body += c);
317
+ req.on("end", async () => {
318
+ try {
319
+ const parsed = typeof body === "string" ? JSON.parse(body || "{}") : {};
320
+ const message = parsed.message || parsed.text || parsed.prompt || String(parsed);
321
+ if (!message || typeof message !== "string") {
322
+ res.writeHead(400);
323
+ res.end(JSON.stringify({ error: "Body must include \"message\" or \"text\" or \"prompt\"" }));
324
+ return;
325
+ }
326
+ const response = await this.callAgent(message, { source: "webhook:inbound" });
327
+ res.writeHead(200);
328
+ res.end(JSON.stringify({
329
+ ok: true,
330
+ response
331
+ }));
332
+ } catch (e) {
333
+ res.writeHead(500);
334
+ res.end(JSON.stringify({ error: e.message }));
335
+ }
336
+ });
337
+ return;
338
+ }
339
+ if (url === "/api/canvas/state" && req.method === "GET") {
340
+ if (!await this.requireAuth(req, res)) return;
341
+ const getState = this.config.deps.getCanvasState;
342
+ if (getState) getState().then((canvas) => {
343
+ res.writeHead(200, { "Content-Type": "application/json" });
344
+ res.end(JSON.stringify(canvas));
345
+ }).catch((e) => {
346
+ res.writeHead(500);
347
+ res.end(JSON.stringify({ error: e.message }));
348
+ });
349
+ else Promise.resolve().then(() => require("./renderer-CN8ePGog.js")).then(({ CanvasRenderer }) => {
350
+ const renderer = new CanvasRenderer();
351
+ renderer.getOrCreate().then((canvas) => {
352
+ res.writeHead(200, { "Content-Type": "application/json" });
353
+ res.end(JSON.stringify(canvas));
354
+ }).catch((e) => {
355
+ res.writeHead(500);
356
+ res.end(JSON.stringify({ error: e.message }));
357
+ });
358
+ }).catch((e) => {
359
+ res.writeHead(500);
360
+ res.end(JSON.stringify({ error: e.message }));
361
+ });
362
+ return;
363
+ }
364
+ if (url === "/api/canvas/a2ui" && req.method === "GET") {
365
+ if (!await this.requireAuth(req, res)) return;
366
+ const getA2UI = this.config.deps.getCanvasA2UI;
367
+ if (getA2UI) getA2UI().then((jsonl) => {
368
+ res.setHeader("Content-Type", "application/x-ndjson");
369
+ res.setHeader("Cache-Control", "no-cache");
370
+ res.writeHead(200);
371
+ res.end(jsonl + "\n");
372
+ }).catch((e) => {
373
+ res.writeHead(500);
374
+ res.end(JSON.stringify({ error: e.message }));
375
+ });
376
+ else Promise.resolve().then(() => require("./renderer-CN8ePGog.js")).then(({ CanvasRenderer }) => {
377
+ Promise.resolve().then(() => require("./a2ui-protocol-Bw1wBBXC.js")).then(({ toBeginRendering, toJSONL }) => {
378
+ const renderer = new CanvasRenderer();
379
+ renderer.getOrCreate().then((canvas) => {
380
+ const msg = toBeginRendering(canvas);
381
+ res.setHeader("Content-Type", "application/x-ndjson");
382
+ res.setHeader("Cache-Control", "no-cache");
383
+ res.writeHead(200);
384
+ res.end(toJSONL([msg]) + "\n");
385
+ }).catch((e) => {
386
+ res.writeHead(500);
387
+ res.end(JSON.stringify({ error: e.message }));
388
+ });
389
+ });
390
+ }).catch((e) => {
391
+ res.writeHead(500);
392
+ res.end(JSON.stringify({ error: e.message }));
393
+ });
394
+ return;
395
+ }
396
+ if (url === "/chat" || url === "/chat/") {
397
+ res.setHeader("Content-Type", "text/html");
398
+ const fp = path.default.join(process.cwd(), "static", "chat.html");
399
+ if (fs_extra.default.pathExistsSync(fp)) res.end(fs_extra.default.readFileSync(fp, "utf8"));
400
+ else res.end("<!DOCTYPE html><html><body><p>Chat UI: <a href=\"/\">apps/web</a></p></body></html>");
401
+ return;
402
+ }
403
+ if (url === "/dashboard" || url === "/dashboard/") {
404
+ res.setHeader("Content-Type", "text/html");
405
+ const fp = path.default.join(process.cwd(), "static", "dashboard.html");
406
+ if (fs_extra.default.pathExistsSync(fp)) res.end(fs_extra.default.readFileSync(fp, "utf8"));
407
+ else res.end("<!DOCTYPE html><html><body><p>Dashboard: <a href=\"/api/status\">status</a></p></body></html>");
408
+ return;
409
+ }
410
+ if (url === "/" || url === "") {
411
+ res.writeHead(302, { Location: "/dashboard" });
412
+ res.end();
413
+ return;
414
+ }
415
+ if (url.startsWith("/webhook/")) {
416
+ const channelId = url.split("/")[2];
417
+ if (req.method === "GET") {
418
+ const params = new URL(url, "http://x").searchParams;
419
+ if (channelId === "twitter") {
420
+ const crcToken = params.get("crc_token");
421
+ if (crcToken) {
422
+ const verified$1 = this.channelRunner?.verifyWebhook?.(channelId, "crc", crcToken, "");
423
+ if (verified$1) {
424
+ res.writeHead(200, { "Content-Type": "application/json" });
425
+ res.end(verified$1);
426
+ return;
427
+ }
428
+ }
429
+ }
430
+ const mode = params.get("hub.mode") || "";
431
+ const token = params.get("hub.verify_token") || "";
432
+ const challenge = params.get("hub.challenge") || "";
433
+ const verified = this.channelRunner?.verifyWebhook?.(channelId, mode, token, challenge);
434
+ if (verified !== null && verified !== void 0) {
435
+ res.writeHead(200, { "Content-Type": "text/plain" });
436
+ res.end(verified);
437
+ } else {
438
+ res.writeHead(200);
439
+ res.end(JSON.stringify({ ok: true }));
440
+ }
441
+ return;
442
+ }
443
+ if (req.method === "POST") {
444
+ let body = "";
445
+ req.on("data", (c) => body += c);
446
+ req.on("end", async () => {
447
+ const host = req.headers["host"] || "localhost";
448
+ const baseUrl = `${req.headers["x-forwarded-proto"] === "https" ? "https" : "http"}://${host}`;
449
+ let opts;
450
+ if (channelId === "slack") opts = {
451
+ signature: req.headers["x-slack-signature"] || "",
452
+ timestamp: req.headers["x-slack-request-timestamp"] || ""
453
+ };
454
+ else if (channelId === "line") opts = { signature: req.headers["x-line-signature"] || "" };
455
+ else if (channelId === "sms") opts = {
456
+ twilioSignature: req.headers["x-twilio-signature"] || "",
457
+ webhookUrl: `${baseUrl}${req.url}`
458
+ };
459
+ else if (channelId === "instagram" || channelId === "messenger") opts = { signature: req.headers["x-hub-signature-256"] || "" };
460
+ else if (channelId === "viber") opts = { signature: req.headers["x-viber-signature"] || "" };
461
+ let challenge = void 0;
462
+ if (this.channelRunner?.handleWebhook) challenge = await this.channelRunner.handleWebhook(channelId, body, opts).catch(() => void 0);
463
+ this.broadcast({
464
+ type: "webhook:received",
465
+ channelId,
466
+ payload: body
467
+ });
468
+ if (typeof challenge === "string") {
469
+ const contentType = challenge.trim().startsWith("{") ? "application/json" : "text/plain";
470
+ res.writeHead(200, { "Content-Type": contentType });
471
+ res.end(challenge);
472
+ } else {
473
+ res.writeHead(200);
474
+ res.end(JSON.stringify({ ok: true }));
475
+ }
476
+ });
477
+ return;
478
+ }
479
+ }
480
+ res.writeHead(404);
481
+ res.end(JSON.stringify({ error: "Not found" }));
482
+ }
483
+ handleConnection(ws$1, req) {
484
+ const id = crypto.default.randomBytes(8).toString("hex");
485
+ const source = req.headers["x-hyperclaw-source"] || "unknown";
486
+ const authToken = this.config.deps.resolveGatewayToken(this.config.authToken);
487
+ const session = {
488
+ id,
489
+ socket: ws$1,
490
+ authenticated: !authToken,
491
+ source,
492
+ connectedAt: (/* @__PURE__ */ new Date()).toISOString(),
493
+ lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
494
+ };
495
+ this.sessions.set(id, session);
496
+ this.broadcast({
497
+ type: "presence:join",
498
+ sessionId: id,
499
+ source
500
+ }, id);
501
+ console.log(chalk.default.gray(` [gateway] +connect ${source} ${id}`));
502
+ if (authToken && !session.authenticated) this.send(session, {
503
+ type: "connect.challenge",
504
+ sessionId: id
505
+ });
506
+ else {
507
+ this.send(session, {
508
+ type: "connect.ok",
509
+ sessionId: id,
510
+ version: "4.0.2",
511
+ heartbeatInterval: 3e4
512
+ });
513
+ if (this.config.hooks && this.config.deps.createHookLoader) this.config.deps.createHookLoader().execute("session:start", { sessionId: id }).catch(() => {});
514
+ }
515
+ ws$1.on("message", (data) => {
516
+ session.lastActiveAt = (/* @__PURE__ */ new Date()).toISOString();
517
+ try {
518
+ this.handleMessage(session, JSON.parse(data.toString()));
519
+ } catch {
520
+ this.send(session, {
521
+ type: "error",
522
+ message: "Invalid JSON"
523
+ });
524
+ }
525
+ });
526
+ ws$1.on("close", () => {
527
+ const s = this.sessions.get(id);
528
+ if (s?.nodeId && this.config.deps.NodeRegistry) {
529
+ this.config.deps.NodeRegistry.unregister(s.nodeId);
530
+ console.log(chalk.default.gray(` [gateway] -node ${s.nodeId}`));
531
+ }
532
+ if (this.config.hooks && !s?.nodeId && this.config.deps.createHookLoader) {
533
+ const turnCount = this.transcripts.get(id)?.length ?? 0;
534
+ this.config.deps.createHookLoader().execute("session:end", {
535
+ sessionId: id,
536
+ turnCount
537
+ }).catch(() => {});
538
+ }
539
+ this.transcripts.delete(id);
540
+ this.sessions.delete(id);
541
+ this.broadcast({
542
+ type: "presence:leave",
543
+ sessionId: id
544
+ });
545
+ console.log(chalk.default.gray(` [gateway] -disconnect ${id}`));
546
+ });
547
+ ws$1.on("error", (e) => console.log(chalk.default.yellow(` [gateway] error ${id}: ${e.message}`)));
548
+ }
549
+ handleMessage(session, msg) {
550
+ if (msg.type === "node_register") {
551
+ const nodeId = msg.nodeId || `node-${session.id}`;
552
+ const platform = msg.platform === "ios" || msg.platform === "android" ? msg.platform : "ios";
553
+ const capabilities = msg.capabilities || {};
554
+ const authToken = this.config.deps.resolveGatewayToken(this.config.authToken);
555
+ if (authToken && msg.token !== authToken) {
556
+ this.send(session, {
557
+ type: "node:error",
558
+ message: "Invalid token"
559
+ });
560
+ session.socket.close(4001, "Unauthorized");
561
+ return;
562
+ }
563
+ const NR = this.config.deps.NodeRegistry;
564
+ if (!NR) {
565
+ this.send(session, {
566
+ type: "node:error",
567
+ message: "Node registry not available"
568
+ });
569
+ return;
570
+ }
571
+ const cmdIdToResolve = /* @__PURE__ */ new Map();
572
+ session._nodePending = cmdIdToResolve;
573
+ const node = {
574
+ nodeId,
575
+ platform,
576
+ capabilities,
577
+ deviceName: msg.deviceName,
578
+ connectedAt: (/* @__PURE__ */ new Date()).toISOString(),
579
+ lastSeenAt: (/* @__PURE__ */ new Date()).toISOString(),
580
+ send: async (cmd) => {
581
+ return new Promise((resolve) => {
582
+ const timeout = setTimeout(() => {
583
+ cmdIdToResolve.delete(cmd.id);
584
+ resolve({
585
+ ok: false,
586
+ error: "Timeout"
587
+ });
588
+ }, 3e4);
589
+ cmdIdToResolve.set(cmd.id, { resolve: (r) => {
590
+ clearTimeout(timeout);
591
+ resolve(r);
592
+ } });
593
+ this.send(session, {
594
+ type: "node:command",
595
+ id: cmd.id,
596
+ command: cmd.type,
597
+ params: cmd.params
598
+ });
599
+ });
600
+ }
601
+ };
602
+ const protocolVersion = msg.protocolVersion ?? 1;
603
+ NR.register(node);
604
+ session.nodeId = nodeId;
605
+ session.authenticated = true;
606
+ session.source = `node:${platform}`;
607
+ this.send(session, {
608
+ type: "node:registered",
609
+ nodeId,
610
+ sessionId: session.id,
611
+ protocolVersion: Math.min(protocolVersion, 2),
612
+ heartbeatInterval: 3e4,
613
+ capabilities: Object.keys(capabilities)
614
+ });
615
+ console.log(chalk.default.gray(` [gateway] +node ${nodeId} (${platform})`));
616
+ return;
617
+ }
618
+ if (msg.type === "node:unregister" && session.nodeId && this.config.deps.NodeRegistry) {
619
+ this.config.deps.NodeRegistry.unregister(session.nodeId);
620
+ session.nodeId = void 0;
621
+ this.send(session, { type: "node:unregistered" });
622
+ return;
623
+ }
624
+ if (msg.type === "node:command_response" && session._nodePending) {
625
+ const r = session._nodePending.get(msg.id);
626
+ if (r) {
627
+ session._nodePending.delete(msg.id);
628
+ r.resolve({
629
+ ok: msg.ok,
630
+ data: msg.data,
631
+ error: msg.error
632
+ });
633
+ }
634
+ return;
635
+ }
636
+ if (msg.type === "session:restore" && (msg.restoreKey ?? msg.previousSessionId)) {
637
+ const key = String(msg.restoreKey ?? msg.previousSessionId);
638
+ session.restoreKey = key;
639
+ if (this.sessionStore) this.sessionStore.get(key).then((state) => {
640
+ if (state?.transcript?.length) {
641
+ const arr = this.transcripts.get(session.id) || [];
642
+ for (const t of state.transcript) if (!arr.some((x) => x.role === t.role && x.content === t.content)) arr.push(t);
643
+ if (arr.length > 100) arr.splice(0, arr.length - 80);
644
+ this.transcripts.set(session.id, arr);
645
+ this.send(session, {
646
+ type: "session:restored",
647
+ transcript: state.transcript
648
+ });
649
+ }
650
+ }).catch(() => {});
651
+ return;
652
+ }
653
+ if (msg.type === "auth") {
654
+ const resolved = this.config.deps.resolveGatewayToken(this.config.authToken);
655
+ if (resolved && msg.token === resolved) {
656
+ session.authenticated = true;
657
+ this.send(session, {
658
+ type: "auth.ok",
659
+ sessionId: session.id
660
+ });
661
+ } else session.socket.close(4001, "Unauthorized");
662
+ return;
663
+ }
664
+ if (!session.authenticated) {
665
+ this.send(session, {
666
+ type: "error",
667
+ message: "Not authenticated"
668
+ });
669
+ return;
670
+ }
671
+ switch (msg.type) {
672
+ case "ping": {
673
+ if (session.nodeId && this.config.deps.NodeRegistry) this.config.deps.NodeRegistry.updateLastSeen?.(session.nodeId);
674
+ this.send(session, {
675
+ type: "pong",
676
+ ts: Date.now()
677
+ });
678
+ break;
679
+ }
680
+ case "talk:enable":
681
+ session.talkMode = true;
682
+ this.send(session, {
683
+ type: "talk:ok",
684
+ enabled: true
685
+ });
686
+ break;
687
+ case "talk:disable":
688
+ session.talkMode = false;
689
+ this.send(session, {
690
+ type: "talk:ok",
691
+ enabled: false
692
+ });
693
+ break;
694
+ case "elevated:enable": {
695
+ const cfg = this.loadConfig();
696
+ const allowFrom = (cfg?.tools?.elevated)?.allowFrom ?? [];
697
+ const enabled = (cfg?.tools?.elevated)?.enabled === true;
698
+ if (!enabled) {
699
+ this.send(session, {
700
+ type: "error",
701
+ message: "Elevated mode disabled in config"
702
+ });
703
+ break;
704
+ }
705
+ if (allowFrom.length && !allowFrom.includes(session.source) && !allowFrom.includes("*")) {
706
+ this.send(session, {
707
+ type: "error",
708
+ message: "Source not in elevated allowFrom"
709
+ });
710
+ break;
711
+ }
712
+ session.elevated = true;
713
+ this.send(session, {
714
+ type: "elevated:ok",
715
+ enabled: true
716
+ });
717
+ break;
718
+ }
719
+ case "elevated:disable":
720
+ session.elevated = false;
721
+ this.send(session, {
722
+ type: "elevated:ok",
723
+ enabled: false
724
+ });
725
+ break;
726
+ case "chat:message": {
727
+ const content = typeof msg.content === "string" ? msg.content : String(msg.content ?? "");
728
+ if (this.config.hooks && this.config.deps.createHookLoader) this.config.deps.createHookLoader().execute("message:received", { sessionId: session.id }).catch(() => {});
729
+ const onDone = (response) => {
730
+ this.send(session, {
731
+ type: "chat:response",
732
+ content: response
733
+ });
734
+ if (session.talkMode && response) this.synthesizeAndSendAudio(session, response).catch(() => {});
735
+ if (this.config.hooks && this.config.deps.createHookLoader) this.config.deps.createHookLoader().execute("message:sent", {
736
+ sessionId: session.id,
737
+ message: content,
738
+ response
739
+ }).catch(() => {});
740
+ };
741
+ this.callAgent(content, {
742
+ currentSessionId: session.id,
743
+ onToken: (token) => this.send(session, {
744
+ type: "chat:chunk",
745
+ content: token
746
+ }),
747
+ onDone
748
+ }).catch((e) => this.send(session, {
749
+ type: "chat:response",
750
+ content: `Error: ${e.message}`
751
+ }));
752
+ break;
753
+ }
754
+ case "gateway:status":
755
+ this.send(session, {
756
+ type: "gateway:status",
757
+ sessions: this.sessions.size,
758
+ uptime: this.startedAt
759
+ });
760
+ break;
761
+ case "presence:list":
762
+ this.send(session, {
763
+ type: "presence:list",
764
+ sessions: Array.from(this.sessions.entries()).map(([sid, s]) => ({
765
+ id: sid,
766
+ source: s.source
767
+ }))
768
+ });
769
+ break;
770
+ case "config:get":
771
+ this.send(session, {
772
+ type: "config:data",
773
+ config: this.scrubConfig(this.loadConfig())
774
+ });
775
+ break;
776
+ }
777
+ }
778
+ async callAgent(message, opts) {
779
+ const sid = opts?.currentSessionId;
780
+ const sess = sid ? this.sessions.get(sid) : void 0;
781
+ const confirmTriggers = [
782
+ "confirm",
783
+ "yes",
784
+ "ok",
785
+ "elevate"
786
+ ];
787
+ if (sid && confirmTriggers.includes(message.trim().toLowerCase())) {
788
+ const getPending = this.config.deps.getPending;
789
+ const clearPending = this.config.deps.clearPending;
790
+ if (getPending && clearPending) {
791
+ const pending = getPending(sid);
792
+ if (pending) {
793
+ clearPending(sid);
794
+ try {
795
+ const result$1 = await pending.execute();
796
+ opts?.onDone?.(result$1);
797
+ return result$1;
798
+ } catch (e) {
799
+ const err = `Error: ${e.message}`;
800
+ opts?.onDone?.(err);
801
+ return err;
802
+ }
803
+ }
804
+ }
805
+ }
806
+ const cfg = this.loadConfig();
807
+ const elevated = sess?.elevated && (cfg?.tools?.elevated)?.enabled === true;
808
+ const source = opts?.source || sess?.source;
809
+ const hcDir = this.config.deps.getHyperClawDir();
810
+ const runOpts = {
811
+ sessionId: sid,
812
+ source,
813
+ elevated,
814
+ onToken: opts?.onToken,
815
+ onDone: opts?.onDone,
816
+ daemonMode: this.config.daemonMode,
817
+ appendTranscript: (s, role, content) => this.appendTranscript(s, role, content),
818
+ activeServer: activeServer ?? this
819
+ };
820
+ if ((cfg?.observability)?.traces && this.config.deps.createRunTracer && this.config.deps.writeTraceToFile) {
821
+ const tracer = this.config.deps.createRunTracer(sid, source);
822
+ runOpts.onToolCall = tracer.onToolCall;
823
+ runOpts.onToolResult = tracer.onToolResult;
824
+ runOpts.onRunEnd = (usage, err) => {
825
+ tracer.onRunEnd(usage, err);
826
+ this.config.deps.writeTraceToFile(hcDir, tracer.trace).catch(() => {});
827
+ };
828
+ }
829
+ const baseOnRunEnd = runOpts.onRunEnd;
830
+ const recordUsage = this.config.deps.recordUsage;
831
+ runOpts.onRunEnd = (usage, err) => {
832
+ baseOnRunEnd?.(usage, err);
833
+ if (sid && usage && recordUsage) recordUsage(hcDir, sid, usage, {
834
+ source,
835
+ model: cfg?.provider?.modelId ?? void 0
836
+ }).catch(() => {});
837
+ };
838
+ const result = await this.config.deps.runAgentEngine(message, runOpts);
839
+ return result.text;
840
+ }
841
+ appendTranscript(sessionId, role, content) {
842
+ let arr = this.transcripts.get(sessionId);
843
+ if (!arr) {
844
+ arr = [];
845
+ this.transcripts.set(sessionId, arr);
846
+ }
847
+ arr.push({
848
+ role,
849
+ content
850
+ });
851
+ if (arr.length > 100) arr.splice(0, arr.length - 80);
852
+ const sess = this.sessions.get(sessionId);
853
+ const storeKey = sess?.restoreKey || sessionId;
854
+ if (this.sessionStore) this.sessionStore.append(storeKey, role, content, sess?.source).catch(() => {});
855
+ }
856
+ getSessionsList() {
857
+ return Array.from(this.sessions.entries()).map(([id, s]) => ({
858
+ id,
859
+ source: s.source,
860
+ connectedAt: s.connectedAt
861
+ }));
862
+ }
863
+ sendToSession(sessionId, msg) {
864
+ const s = this.sessions.get(sessionId);
865
+ if (!s || s.socket.readyState !== ws.WebSocket.OPEN) return false;
866
+ this.send(s, msg);
867
+ return true;
868
+ }
869
+ getSessionHistory(sessionId, limit = 20) {
870
+ const arr = this.transcripts.get(sessionId) ?? [];
871
+ return arr.slice(-limit);
872
+ }
873
+ send(session, msg) {
874
+ if (session.socket.readyState === ws.WebSocket.OPEN) session.socket.send(JSON.stringify(msg));
875
+ }
876
+ broadcast(msg, excludeId) {
877
+ for (const [id, s] of this.sessions) if (id !== excludeId && s.authenticated) this.send(s, msg);
878
+ }
879
+ async synthesizeAndSendAudio(session, text) {
880
+ const cfg = this.loadConfig();
881
+ const talk = cfg?.talkMode;
882
+ const apiKey = talk?.apiKey || process.env.ELEVENLABS_API_KEY;
883
+ if (!apiKey) return;
884
+ const textToSpeech = this.config.deps.textToSpeech;
885
+ if (!textToSpeech) return;
886
+ const audio = await textToSpeech(text.slice(0, 4e3), {
887
+ apiKey,
888
+ voiceId: talk?.voiceId,
889
+ modelId: talk?.modelId || "eleven_multilingual_v2"
890
+ });
891
+ if (audio) this.send(session, {
892
+ type: "chat:audio",
893
+ format: "mp3",
894
+ data: audio
895
+ });
896
+ }
897
+ loadConfig() {
898
+ if (this.config.deps.loadConfig) return this.config.deps.loadConfig();
899
+ try {
900
+ return fs_extra.default.readJsonSync(this.config.deps.getConfigPath());
901
+ } catch {
902
+ return null;
903
+ }
904
+ }
905
+ scrubConfig(cfg) {
906
+ if (!cfg) return null;
907
+ const s = JSON.parse(JSON.stringify(cfg));
908
+ if (s.provider?.apiKey) s.provider.apiKey = "***";
909
+ if (s.gateway?.authToken) s.gateway.authToken = "***";
910
+ return s;
911
+ }
912
+ getStatus() {
913
+ return {
914
+ running: true,
915
+ port: this.config.port,
916
+ sessions: this.sessions.size,
917
+ startedAt: this.startedAt
918
+ };
919
+ }
920
+ };
921
+ const DEFAULT_PORT = 18789;
922
+ async function startGateway(opts) {
923
+ const deps = opts.deps;
924
+ let base;
925
+ try {
926
+ base = fs_extra.default.readJsonSync(deps.getConfigPath()).gateway;
927
+ } catch {
928
+ base = {
929
+ port: DEFAULT_PORT,
930
+ bind: "127.0.0.1",
931
+ authToken: "",
932
+ runtime: "node",
933
+ enabledChannels: [],
934
+ hooks: true
935
+ };
936
+ }
937
+ const portEnv = process.env.PORT || process.env.HYPERCLAW_PORT;
938
+ const port = portEnv ? parseInt(portEnv, 10) || base.port : base.port;
939
+ const cfg = {
940
+ ...base,
941
+ port: port ?? DEFAULT_PORT,
942
+ bind: base.bind ?? "127.0.0.1",
943
+ authToken: deps.resolveGatewayToken(base.authToken ?? "") ?? base.authToken ?? "",
944
+ runtime: base.runtime ?? "node",
945
+ enabledChannels: base.enabledChannels ?? [],
946
+ hooks: base.hooks ?? true,
947
+ daemonMode: opts.daemonMode,
948
+ deps
949
+ };
950
+ const server = new GatewayServer(cfg);
951
+ await server.start();
952
+ return server;
953
+ }
954
+ function getActiveServer() {
955
+ return activeServer;
956
+ }
957
+
958
+ //#endregion
959
+ //#region src/gateway/deps-provider.ts
960
+ async function createDefaultGatewayDeps() {
961
+ const [paths, envResolve, sessionStore, channelRunner, hookLoader, core, devKeys, pendingApproval, observability, costTracker, tts, nodesRegistry, canvasRenderer, a2ui] = await Promise.all([
962
+ Promise.resolve().then(() => require("./paths-D-QecARF.js")),
963
+ Promise.resolve().then(() => require("./env-resolve-BazAsaKp.js")),
964
+ Promise.resolve().then(() => require("./session-store-v82VTWbD.js")),
965
+ Promise.resolve().then(() => require("./runner-Bu--_RXw.js")),
966
+ Promise.resolve().then(() => require("./loader-aSIGRXBq.js")),
967
+ Promise.resolve().then(() => require("./src-cfRTjFef.js")),
968
+ Promise.resolve().then(() => require("./developer-keys-DkZeQzV2.js")),
969
+ Promise.resolve().then(() => require("./pending-approval-Bdf11byB.js")),
970
+ Promise.resolve().then(() => require("./observability-CDaEJACJ.js")),
971
+ Promise.resolve().then(() => require("./cost-tracker-Bae6xRoO.js")),
972
+ Promise.resolve().then(() => require("./tts-elevenlabs-4stMe54k.js")),
973
+ Promise.resolve().then(() => require("./nodes-registry-Bkh_L-d2.js")),
974
+ Promise.resolve().then(() => require("./renderer-CN8ePGog.js")),
975
+ Promise.resolve().then(() => require("./a2ui-protocol-Bw1wBBXC.js"))
976
+ ]);
977
+ const createSessionStore = async (baseDir) => {
978
+ const store = await sessionStore.createFileSessionStore(baseDir);
979
+ return store;
980
+ };
981
+ const createHookLoader = () => new hookLoader.HookLoader();
982
+ const getCanvasState = async () => {
983
+ const renderer = new canvasRenderer.CanvasRenderer();
984
+ const canvas = await renderer.getOrCreate();
985
+ return canvas;
986
+ };
987
+ const getCanvasA2UI = async () => {
988
+ const renderer = new canvasRenderer.CanvasRenderer();
989
+ const canvas = await renderer.getOrCreate();
990
+ const msg = a2ui.toBeginRendering(canvas);
991
+ return a2ui.toJSONL([msg]);
992
+ };
993
+ return {
994
+ getHyperClawDir: paths.getHyperClawDir,
995
+ getConfigPath: paths.getConfigPath,
996
+ resolveGatewayToken: envResolve.resolveGatewayToken,
997
+ validateApiAuth: async (bearer) => (await devKeys.validateDeveloperKey(bearer)).valid,
998
+ createSessionStore,
999
+ startChannelRunners: channelRunner.startChannelRunners,
1000
+ createHookLoader,
1001
+ runAgentEngine: core.runAgentEngine,
1002
+ createPiRPCHandler: core.createPiRPCHandler,
1003
+ listTraces: observability.listTraces,
1004
+ getSessionSummary: costTracker.getSessionSummary,
1005
+ getGlobalSummary: costTracker.getGlobalSummary,
1006
+ recordUsage: costTracker.recordUsage,
1007
+ textToSpeech: tts.textToSpeech,
1008
+ getPending: pendingApproval.getPending,
1009
+ clearPending: pendingApproval.clearPending,
1010
+ createRunTracer: observability.createRunTracer,
1011
+ writeTraceToFile: observability.writeTraceToFile,
1012
+ NodeRegistry: nodesRegistry.NodeRegistry,
1013
+ getCanvasState,
1014
+ getCanvasA2UI
1015
+ };
1016
+ }
1017
+
1018
+ //#endregion
1019
+ //#region src/gateway/server.ts
1020
+ /** Start gateway with default deps (paths, channels, hooks, etc.). */
1021
+ async function startGateway$1(opts) {
1022
+ const deps = await createDefaultGatewayDeps();
1023
+ return startGateway({
1024
+ ...opts,
1025
+ deps
1026
+ });
1027
+ }
1028
+
1029
+ //#endregion
1030
+ Object.defineProperty(exports, 'GatewayServer', {
1031
+ enumerable: true,
1032
+ get: function () {
1033
+ return GatewayServer;
1034
+ }
1035
+ });
1036
+ Object.defineProperty(exports, 'getActiveServer', {
1037
+ enumerable: true,
1038
+ get: function () {
1039
+ return getActiveServer;
1040
+ }
1041
+ });
1042
+ Object.defineProperty(exports, 'startGateway', {
1043
+ enumerable: true,
1044
+ get: function () {
1045
+ return startGateway$1;
1046
+ }
1047
+ });