visionclaw 0.1.206-beta.21 → 0.1.206-beta.22

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 (309) hide show
  1. package/dist/agent/applied-credential-signature.d.ts +53 -0
  2. package/dist/agent/applied-credential-signature.d.ts.map +1 -0
  3. package/dist/agent/applied-credential-signature.js +137 -0
  4. package/dist/agent/applied-credential-signature.js.map +1 -0
  5. package/dist/agent/engines/client-factory.d.ts +63 -0
  6. package/dist/agent/engines/client-factory.d.ts.map +1 -0
  7. package/dist/agent/engines/client-factory.js +382 -0
  8. package/dist/agent/engines/client-factory.js.map +1 -0
  9. package/dist/agent/engines/engine.d.ts +8 -0
  10. package/dist/agent/engines/engine.d.ts.map +1 -0
  11. package/dist/agent/engines/engine.js +15 -0
  12. package/dist/agent/engines/engine.js.map +1 -0
  13. package/dist/agent/engines/openai/file-session.d.ts +19 -0
  14. package/dist/agent/engines/openai/file-session.d.ts.map +1 -0
  15. package/dist/agent/engines/openai/file-session.js +78 -0
  16. package/dist/agent/engines/openai/file-session.js.map +1 -0
  17. package/dist/agent/engines/openai/file-tools.d.ts +35 -0
  18. package/dist/agent/engines/openai/file-tools.d.ts.map +1 -0
  19. package/dist/agent/engines/openai/file-tools.js +194 -0
  20. package/dist/agent/engines/openai/file-tools.js.map +1 -0
  21. package/dist/agent/engines/openai/session.d.ts +55 -0
  22. package/dist/agent/engines/openai/session.d.ts.map +1 -0
  23. package/dist/agent/engines/openai/session.js +447 -0
  24. package/dist/agent/engines/openai/session.js.map +1 -0
  25. package/dist/agent/engines/openai/tools.d.ts +15 -0
  26. package/dist/agent/engines/openai/tools.d.ts.map +1 -0
  27. package/dist/agent/engines/openai/tools.js +221 -0
  28. package/dist/agent/engines/openai/tools.js.map +1 -0
  29. package/dist/agent/engines/pi/session.d.ts +49 -0
  30. package/dist/agent/engines/pi/session.d.ts.map +1 -0
  31. package/dist/agent/engines/pi/session.js +309 -0
  32. package/dist/agent/engines/pi/session.js.map +1 -0
  33. package/dist/agent/memory-preload.d.ts +55 -0
  34. package/dist/agent/memory-preload.d.ts.map +1 -0
  35. package/dist/agent/memory-preload.js +166 -0
  36. package/dist/agent/memory-preload.js.map +1 -0
  37. package/dist/agent/providers/claude/cli-resolver.d.ts +16 -0
  38. package/dist/agent/providers/claude/cli-resolver.d.ts.map +1 -0
  39. package/dist/agent/providers/claude/cli-resolver.js +83 -0
  40. package/dist/agent/providers/claude/cli-resolver.js.map +1 -0
  41. package/dist/agent/providers/claude/session-browser-policy.d.ts +9 -0
  42. package/dist/agent/providers/claude/session-browser-policy.d.ts.map +1 -0
  43. package/dist/agent/providers/claude/session-browser-policy.js +49 -0
  44. package/dist/agent/providers/claude/session-browser-policy.js.map +1 -0
  45. package/dist/agent/providers/claude/session.d.ts +304 -0
  46. package/dist/agent/providers/claude/session.d.ts.map +1 -0
  47. package/dist/agent/providers/claude/session.js +1236 -0
  48. package/dist/agent/providers/claude/session.js.map +1 -0
  49. package/dist/agent/providers/client-factory.d.ts +60 -0
  50. package/dist/agent/providers/client-factory.d.ts.map +1 -0
  51. package/dist/agent/providers/client-factory.js +400 -0
  52. package/dist/agent/providers/client-factory.js.map +1 -0
  53. package/dist/agent/providers/openai/file-session.d.ts +19 -0
  54. package/dist/agent/providers/openai/file-session.d.ts.map +1 -0
  55. package/dist/agent/providers/openai/file-session.js +78 -0
  56. package/dist/agent/providers/openai/file-session.js.map +1 -0
  57. package/dist/agent/providers/openai/session.d.ts +55 -0
  58. package/dist/agent/providers/openai/session.d.ts.map +1 -0
  59. package/dist/agent/providers/openai/session.js +447 -0
  60. package/dist/agent/providers/openai/session.js.map +1 -0
  61. package/dist/agent/providers/openai/tools.d.ts +15 -0
  62. package/dist/agent/providers/openai/tools.d.ts.map +1 -0
  63. package/dist/agent/providers/openai/tools.js +229 -0
  64. package/dist/agent/providers/openai/tools.js.map +1 -0
  65. package/dist/agent/providers/session-types.d.ts +153 -0
  66. package/dist/agent/providers/session-types.d.ts.map +1 -0
  67. package/dist/agent/providers/session-types.js +2 -0
  68. package/dist/agent/providers/session-types.js.map +1 -0
  69. package/dist/agent/providers/system-prompt-log.d.ts +9 -0
  70. package/dist/agent/providers/system-prompt-log.d.ts.map +1 -0
  71. package/dist/agent/providers/system-prompt-log.js +46 -0
  72. package/dist/agent/providers/system-prompt-log.js.map +1 -0
  73. package/dist/agent/runtime-surface.d.ts.map +1 -1
  74. package/dist/agent/runtime-surface.js +10 -1
  75. package/dist/agent/runtime-surface.js.map +1 -1
  76. package/dist/agent/transcript-backfill.d.ts +54 -0
  77. package/dist/agent/transcript-backfill.d.ts.map +1 -0
  78. package/dist/agent/transcript-backfill.js +604 -0
  79. package/dist/agent/transcript-backfill.js.map +1 -0
  80. package/dist/agent/transcript-indexer.d.ts +200 -0
  81. package/dist/agent/transcript-indexer.d.ts.map +1 -0
  82. package/dist/agent/transcript-indexer.js +775 -0
  83. package/dist/agent/transcript-indexer.js.map +1 -0
  84. package/dist/agent/transcript-memory-migrations.d.ts +25 -0
  85. package/dist/agent/transcript-memory-migrations.d.ts.map +1 -0
  86. package/dist/agent/transcript-memory-migrations.js +87 -0
  87. package/dist/agent/transcript-memory-migrations.js.map +1 -0
  88. package/dist/agent/tunnel-credential-handler.d.ts +90 -0
  89. package/dist/agent/tunnel-credential-handler.d.ts.map +1 -0
  90. package/dist/agent/tunnel-credential-handler.js +162 -0
  91. package/dist/agent/tunnel-credential-handler.js.map +1 -0
  92. package/dist/agent/usage-backfill-handler.d.ts +18 -0
  93. package/dist/agent/usage-backfill-handler.d.ts.map +1 -0
  94. package/dist/agent/usage-backfill-handler.js +69 -0
  95. package/dist/agent/usage-backfill-handler.js.map +1 -0
  96. package/dist/agent/usage-gate.d.ts +25 -0
  97. package/dist/agent/usage-gate.d.ts.map +1 -0
  98. package/dist/agent/usage-gate.js +83 -0
  99. package/dist/agent/usage-gate.js.map +1 -0
  100. package/dist/agent/usage-handler.d.ts +7 -0
  101. package/dist/agent/usage-handler.d.ts.map +1 -0
  102. package/dist/agent/usage-handler.js +28 -0
  103. package/dist/agent/usage-handler.js.map +1 -0
  104. package/dist/agent/usage-report-builder.d.ts +26 -0
  105. package/dist/agent/usage-report-builder.d.ts.map +1 -0
  106. package/dist/agent/usage-report-builder.js +80 -0
  107. package/dist/agent/usage-report-builder.js.map +1 -0
  108. package/dist/agent/usage-report-queue.d.ts +26 -0
  109. package/dist/agent/usage-report-queue.d.ts.map +1 -0
  110. package/dist/agent/usage-report-queue.js +199 -0
  111. package/dist/agent/usage-report-queue.js.map +1 -0
  112. package/dist/agent/usage-report-types.d.ts +41 -0
  113. package/dist/agent/usage-report-types.d.ts.map +1 -0
  114. package/dist/agent/usage-report-types.js +2 -0
  115. package/dist/agent/usage-report-types.js.map +1 -0
  116. package/dist/agent/usage-reporter.d.ts +31 -0
  117. package/dist/agent/usage-reporter.d.ts.map +1 -0
  118. package/dist/agent/usage-reporter.js +102 -0
  119. package/dist/agent/usage-reporter.js.map +1 -0
  120. package/dist/agent/wake-cycle-tool-tracker.d.ts +39 -0
  121. package/dist/agent/wake-cycle-tool-tracker.d.ts.map +1 -0
  122. package/dist/agent/wake-cycle-tool-tracker.js +72 -0
  123. package/dist/agent/wake-cycle-tool-tracker.js.map +1 -0
  124. package/dist/billing/payg-handler.d.ts +29 -0
  125. package/dist/billing/payg-handler.d.ts.map +1 -0
  126. package/dist/billing/payg-handler.js +92 -0
  127. package/dist/billing/payg-handler.js.map +1 -0
  128. package/dist/billing/payment-handler.d.ts +24 -0
  129. package/dist/billing/payment-handler.d.ts.map +1 -0
  130. package/dist/billing/payment-handler.js +101 -0
  131. package/dist/billing/payment-handler.js.map +1 -0
  132. package/dist/builtin-skills/catalog/phone-adb-automation/SKILL.md +412 -0
  133. package/dist/builtin-skills/catalog/phone-adb-automation/phone_input.sh +132 -0
  134. package/dist/builtin-skills/catalog/phone-adb-automation/phone_launch.sh +166 -0
  135. package/dist/builtin-skills/catalog/phone-adb-automation/phone_screenshot.sh +87 -0
  136. package/dist/builtin-skills/catalog/phone-adb-automation/phone_security_kbd.py +174 -0
  137. package/dist/builtin-skills/catalog/phone-adb-automation/phone_setup.sh +274 -0
  138. package/dist/builtin-skills/catalog/phone-adb-automation/phone_swipe.sh +111 -0
  139. package/dist/builtin-skills/catalog/phone-adb-automation/phone_tap.sh +87 -0
  140. package/dist/builtin-skills/catalog/phone-adb-automation/phone_ui_parse.py +176 -0
  141. package/dist/builtin-skills/catalog/phone-adb-automation/phone_wake_unlock.sh +67 -0
  142. package/dist/builtin-skills/transcribe-audio/SKILL.md +122 -0
  143. package/dist/channels/web.d.ts +40 -0
  144. package/dist/channels/web.d.ts.map +1 -0
  145. package/dist/channels/web.js +137 -0
  146. package/dist/channels/web.js.map +1 -0
  147. package/dist/data-processing/convert-demo-cli.d.ts +7 -0
  148. package/dist/data-processing/convert-demo-cli.d.ts.map +1 -0
  149. package/dist/data-processing/convert-demo-cli.js +30 -0
  150. package/dist/data-processing/convert-demo-cli.js.map +1 -0
  151. package/dist/data-processing/convert-demo.d.ts +26 -0
  152. package/dist/data-processing/convert-demo.d.ts.map +1 -0
  153. package/dist/data-processing/convert-demo.js +233 -0
  154. package/dist/data-processing/convert-demo.js.map +1 -0
  155. package/dist/obs/auth.d.ts +45 -0
  156. package/dist/obs/auth.d.ts.map +1 -0
  157. package/dist/obs/auth.js +181 -0
  158. package/dist/obs/auth.js.map +1 -0
  159. package/dist/obs/mini-app/tasks.d.ts +2 -0
  160. package/dist/obs/mini-app/tasks.d.ts.map +1 -0
  161. package/dist/obs/mini-app/tasks.js +506 -0
  162. package/dist/obs/mini-app/tasks.js.map +1 -0
  163. package/dist/obs/rdp/icons/icons/app_windows.svg +4 -0
  164. package/dist/obs/rdp/icons/icons/clip_get.svg +4 -0
  165. package/dist/obs/rdp/icons/icons/clip_send.svg +4 -0
  166. package/dist/obs/rdp/icons/icons/clip_shared.svg +4 -0
  167. package/dist/obs/rdp/icons/icons/clipboard.svg +4 -0
  168. package/dist/obs/rdp/icons/icons/clipboard_shared.svg +4 -0
  169. package/dist/obs/rdp/icons/icons/control.svg +4 -0
  170. package/dist/obs/rdp/icons/icons/desktop.svg +4 -0
  171. package/dist/obs/rdp/icons/icons/display.svg +4 -0
  172. package/dist/obs/rdp/icons/icons/launchpad.svg +4 -0
  173. package/dist/obs/rdp/icons/icons/mission_control.svg +4 -0
  174. package/dist/obs/rdp/icons/icons/screenshot.svg +4 -0
  175. package/dist/obs/rdp/icons/icons/zoom_actual.svg +4 -0
  176. package/dist/obs/rdp/icons/icons/zoom_fit.svg +4 -0
  177. package/dist/obs/rdp/icons/icons/zoom_in.svg +4 -0
  178. package/dist/obs/rdp/icons/icons/zoom_out.svg +4 -0
  179. package/dist/obs/tunnel-telemetry.d.ts +46 -0
  180. package/dist/obs/tunnel-telemetry.d.ts.map +1 -0
  181. package/dist/obs/tunnel-telemetry.js +70 -0
  182. package/dist/obs/tunnel-telemetry.js.map +1 -0
  183. package/dist/onboarding/cloudflared-cert.d.ts +15 -0
  184. package/dist/onboarding/cloudflared-cert.d.ts.map +1 -0
  185. package/dist/onboarding/cloudflared-cert.js +57 -0
  186. package/dist/onboarding/cloudflared-cert.js.map +1 -0
  187. package/dist/phonecall-credentials.d.ts +21 -0
  188. package/dist/phonecall-credentials.d.ts.map +1 -0
  189. package/dist/phonecall-credentials.js +34 -0
  190. package/dist/phonecall-credentials.js.map +1 -0
  191. package/dist/realtime/agent-bridge.d.ts +7 -0
  192. package/dist/realtime/agent-bridge.d.ts.map +1 -0
  193. package/dist/realtime/agent-bridge.js +31 -0
  194. package/dist/realtime/agent-bridge.js.map +1 -0
  195. package/dist/realtime/assets/index.html +1058 -0
  196. package/dist/realtime/assets/samples/alloy.mp3 +0 -0
  197. package/dist/realtime/assets/samples/ash.mp3 +0 -0
  198. package/dist/realtime/assets/samples/ballad.mp3 +0 -0
  199. package/dist/realtime/assets/samples/cedar.mp3 +0 -0
  200. package/dist/realtime/assets/samples/coral.mp3 +0 -0
  201. package/dist/realtime/assets/samples/echo.mp3 +0 -0
  202. package/dist/realtime/assets/samples/marin.mp3 +0 -0
  203. package/dist/realtime/assets/samples/sage.mp3 +0 -0
  204. package/dist/realtime/assets/samples/shimmer.mp3 +0 -0
  205. package/dist/realtime/assets/samples/verse.mp3 +0 -0
  206. package/dist/realtime/context.d.ts +14 -0
  207. package/dist/realtime/context.d.ts.map +1 -0
  208. package/dist/realtime/context.js +153 -0
  209. package/dist/realtime/context.js.map +1 -0
  210. package/dist/realtime/http-helpers.d.ts +5 -0
  211. package/dist/realtime/http-helpers.d.ts.map +1 -0
  212. package/dist/realtime/http-helpers.js +29 -0
  213. package/dist/realtime/http-helpers.js.map +1 -0
  214. package/dist/realtime/index.d.ts +62 -0
  215. package/dist/realtime/index.d.ts.map +1 -0
  216. package/dist/realtime/index.js +94 -0
  217. package/dist/realtime/index.js.map +1 -0
  218. package/dist/realtime/server.d.ts +6 -0
  219. package/dist/realtime/server.d.ts.map +1 -0
  220. package/dist/realtime/server.js +479 -0
  221. package/dist/realtime/server.js.map +1 -0
  222. package/dist/realtime/telegram-auth.d.ts +2 -0
  223. package/dist/realtime/telegram-auth.d.ts.map +1 -0
  224. package/dist/realtime/telegram-auth.js +24 -0
  225. package/dist/realtime/telegram-auth.js.map +1 -0
  226. package/dist/realtime/tools.d.ts +829 -0
  227. package/dist/realtime/tools.d.ts.map +1 -0
  228. package/dist/realtime/tools.js +611 -0
  229. package/dist/realtime/tools.js.map +1 -0
  230. package/dist/realtime/types.d.ts +62 -0
  231. package/dist/realtime/types.d.ts.map +1 -0
  232. package/dist/realtime/types.js +3 -0
  233. package/dist/realtime/types.js.map +1 -0
  234. package/dist/realtime/voice-summarizer.d.ts +4 -0
  235. package/dist/realtime/voice-summarizer.d.ts.map +1 -0
  236. package/dist/realtime/voice-summarizer.js +123 -0
  237. package/dist/realtime/voice-summarizer.js.map +1 -0
  238. package/dist/realtime/websocket.d.ts +7 -0
  239. package/dist/realtime/websocket.d.ts.map +1 -0
  240. package/dist/realtime/websocket.js +65 -0
  241. package/dist/realtime/websocket.js.map +1 -0
  242. package/dist/service/gbox-tun.d.ts +14 -0
  243. package/dist/service/gbox-tun.d.ts.map +1 -0
  244. package/dist/service/gbox-tun.js +315 -0
  245. package/dist/service/gbox-tun.js.map +1 -0
  246. package/dist/skills/installed.d.ts +11 -0
  247. package/dist/skills/installed.d.ts.map +1 -0
  248. package/dist/skills/installed.js +35 -0
  249. package/dist/skills/installed.js.map +1 -0
  250. package/dist/tools/card.d.ts +11 -0
  251. package/dist/tools/card.d.ts.map +1 -0
  252. package/dist/tools/card.js +87 -0
  253. package/dist/tools/card.js.map +1 -0
  254. package/dist/tools/coordinate-resolver.d.ts +30 -0
  255. package/dist/tools/coordinate-resolver.d.ts.map +1 -0
  256. package/dist/tools/coordinate-resolver.js +104 -0
  257. package/dist/tools/coordinate-resolver.js.map +1 -0
  258. package/dist/tools/stock-data.d.ts +70 -0
  259. package/dist/tools/stock-data.d.ts.map +1 -0
  260. package/dist/tools/stock-data.js +596 -0
  261. package/dist/tools/stock-data.js.map +1 -0
  262. package/dist/tools/webapp.d.ts +30 -0
  263. package/dist/tools/webapp.d.ts.map +1 -0
  264. package/dist/tools/webapp.js +114 -0
  265. package/dist/tools/webapp.js.map +1 -0
  266. package/dist/utils/wechat-monitor.d.ts +21 -0
  267. package/dist/utils/wechat-monitor.d.ts.map +1 -0
  268. package/dist/utils/wechat-monitor.js +88 -0
  269. package/dist/utils/wechat-monitor.js.map +1 -0
  270. package/dist/webapp/index.d.ts +28 -0
  271. package/dist/webapp/index.d.ts.map +1 -0
  272. package/dist/webapp/index.js +75 -0
  273. package/dist/webapp/index.js.map +1 -0
  274. package/dist/webapp/server.d.ts +32 -0
  275. package/dist/webapp/server.d.ts.map +1 -0
  276. package/dist/webapp/server.js +375 -0
  277. package/dist/webapp/server.js.map +1 -0
  278. package/dist/webapp/storage.d.ts +64 -0
  279. package/dist/webapp/storage.d.ts.map +1 -0
  280. package/dist/webapp/storage.js +103 -0
  281. package/dist/webapp/storage.js.map +1 -0
  282. package/dist/webapp/ui.d.ts +2 -0
  283. package/dist/webapp/ui.d.ts.map +1 -0
  284. package/dist/webapp/ui.js +319 -0
  285. package/dist/webapp/ui.js.map +1 -0
  286. package/dist-agent/assets/index.html +1058 -0
  287. package/dist-agent/assets/samples/alloy.mp3 +0 -0
  288. package/dist-agent/assets/samples/ash.mp3 +0 -0
  289. package/dist-agent/assets/samples/ballad.mp3 +0 -0
  290. package/dist-agent/assets/samples/cedar.mp3 +0 -0
  291. package/dist-agent/assets/samples/coral.mp3 +0 -0
  292. package/dist-agent/assets/samples/echo.mp3 +0 -0
  293. package/dist-agent/assets/samples/marin.mp3 +0 -0
  294. package/dist-agent/assets/samples/sage.mp3 +0 -0
  295. package/dist-agent/assets/samples/shimmer.mp3 +0 -0
  296. package/dist-agent/assets/samples/verse.mp3 +0 -0
  297. package/dist-agent/bundle.cjs +13651 -17320
  298. package/dist-agent/realtime/assets/index.html +1058 -0
  299. package/dist-agent/realtime/assets/samples/alloy.mp3 +0 -0
  300. package/dist-agent/realtime/assets/samples/ash.mp3 +0 -0
  301. package/dist-agent/realtime/assets/samples/ballad.mp3 +0 -0
  302. package/dist-agent/realtime/assets/samples/cedar.mp3 +0 -0
  303. package/dist-agent/realtime/assets/samples/coral.mp3 +0 -0
  304. package/dist-agent/realtime/assets/samples/echo.mp3 +0 -0
  305. package/dist-agent/realtime/assets/samples/marin.mp3 +0 -0
  306. package/dist-agent/realtime/assets/samples/sage.mp3 +0 -0
  307. package/dist-agent/realtime/assets/samples/shimmer.mp3 +0 -0
  308. package/dist-agent/realtime/assets/samples/verse.mp3 +0 -0
  309. package/package.json +1 -1
@@ -0,0 +1,375 @@
1
+ import fs from "node:fs";
2
+ import http from "node:http";
3
+ import { URL } from "node:url";
4
+ import { logger } from "../logger.js";
5
+ import { getAgentState } from "../agent/state.js";
6
+ import { probeLocalTunnelCredential } from "../agent/runtime-credentials.js";
7
+ import { ensureIngressRule, resolveTunnelId } from "../obs/cloudflared-config.js";
8
+ import { OBS_AUTH_COOKIE, resolveOwnerAuth, renderOwnerLoginHtml, readOwnerEmailFromForm, } from "../obs/auth.js";
9
+ import { resolveFinancialToolApiKey, resolveFinancialToolBaseUrl } from "../financial-tool-credentials.js";
10
+ import { loadWorkspace, getDashboardHtmlPath, } from "./storage.js";
11
+ import { renderWorkspaceHtml } from "./ui.js";
12
+ function json(res, status, data) {
13
+ res.statusCode = status;
14
+ res.setHeader("content-type", "application/json; charset=utf-8");
15
+ res.setHeader("cache-control", "no-store");
16
+ res.end(JSON.stringify(data));
17
+ }
18
+ function readJsonBody(req) {
19
+ return new Promise((resolve, reject) => {
20
+ let body = "";
21
+ let size = 0;
22
+ req.on("data", (chunk) => {
23
+ size += chunk.length;
24
+ if (size > 65536) {
25
+ reject(new Error("Body too large"));
26
+ req.destroy();
27
+ return;
28
+ }
29
+ body += chunk.toString();
30
+ });
31
+ req.on("end", () => {
32
+ try {
33
+ resolve(body ? JSON.parse(body) : {});
34
+ }
35
+ catch (err) {
36
+ reject(err instanceof Error ? err : new Error(String(err)));
37
+ }
38
+ });
39
+ req.on("error", reject);
40
+ });
41
+ }
42
+ function getWebAdapter() {
43
+ try {
44
+ return getAgentState().channelManager.getAdapter("web");
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ }
50
+ /**
51
+ * Register an ingress rule so the existing cloudflared connector routes
52
+ * `tunnelHostname` (e.g. ws.agent.visionclawobs.com) to this local port.
53
+ *
54
+ * Mirrors the obs server's `resolveTunnelOpts` logic: prefer the
55
+ * runtime-credential config.yml when present, otherwise fall back to the
56
+ * cert.pem-resolved tunnel UUID. The `ws.` hostname is covered by the agent's
57
+ * existing `*.<agentname>` wildcard DNS, so no DNS mutation is needed here —
58
+ * only the ingress rule. Best-effort: failures are logged, not fatal.
59
+ */
60
+ export function registerWorkspaceIngress(opts, port) {
61
+ const hostname = opts.tunnelHostname?.trim();
62
+ if (!hostname)
63
+ return;
64
+ const service = `http://localhost:${port}`;
65
+ try {
66
+ const runtime = probeLocalTunnelCredential();
67
+ if (runtime) {
68
+ ensureIngressRule(runtime.tunnelId, hostname, service, { configPath: runtime.configFile });
69
+ logger.system(`[webapp] Ingress registered (runtime): ${hostname} -> ${service}`);
70
+ return;
71
+ }
72
+ const isoOpts = opts.tunnelOriginCert
73
+ ? { originCert: opts.tunnelOriginCert, configPath: opts.tunnelConfigPath }
74
+ : undefined;
75
+ const tunnelId = opts.tunnelName ? resolveTunnelId(opts.tunnelName, isoOpts) : undefined;
76
+ if (tunnelId) {
77
+ ensureIngressRule(tunnelId, hostname, service, isoOpts);
78
+ logger.system(`[webapp] Ingress registered (legacy): ${hostname} -> ${service}`);
79
+ }
80
+ else {
81
+ logger.warn(`[webapp] Could not resolve tunnel UUID; ${hostname} ingress not registered.`);
82
+ }
83
+ }
84
+ catch (err) {
85
+ logger.warn(`[webapp] Failed to register ingress for ${hostname}: ${err instanceof Error ? err.message : String(err)}`);
86
+ }
87
+ }
88
+ /**
89
+ * Forward dashboard quote requests to the financial-tool REST endpoint so
90
+ * dashboard HTML can fetch live data same-origin without seeing the service
91
+ * API key.
92
+ *
93
+ * Query params:
94
+ * - `symbols` (comma-separated) or `symbol` (single symbol) is required.
95
+ * - optional `market` is forwarded to the financial-tool service.
96
+ */
97
+ async function handleDashboardDataProxy(config, url, res) {
98
+ const apiKey = resolveFinancialToolApiKey(config);
99
+ if (!apiKey) {
100
+ json(res, 503, { error: "Financial tool is not configured for this agent." });
101
+ return;
102
+ }
103
+ const rawSymbols = url.searchParams.get("symbols") ?? url.searchParams.get("symbol") ?? "";
104
+ const symbols = rawSymbols
105
+ .split(",")
106
+ .map((symbol) => symbol.trim())
107
+ .filter((symbol) => symbol.length > 0)
108
+ .slice(0, 100);
109
+ if (symbols.length === 0) {
110
+ json(res, 400, { error: "symbols or symbol query parameter is required" });
111
+ return;
112
+ }
113
+ const upstreamUrl = new URL(`/internal/quotes/${encodeURIComponent(apiKey)}`, resolveFinancialToolBaseUrl(config));
114
+ upstreamUrl.searchParams.set("symbols", symbols.join(","));
115
+ const market = url.searchParams.get("market")?.trim();
116
+ if (market)
117
+ upstreamUrl.searchParams.set("market", market);
118
+ const ac = new AbortController();
119
+ const timer = setTimeout(() => { ac.abort(); }, 15_000);
120
+ try {
121
+ const upstream = await fetch(upstreamUrl, {
122
+ method: "GET",
123
+ headers: { accept: "application/json" },
124
+ signal: ac.signal,
125
+ });
126
+ const text = await upstream.text();
127
+ res.statusCode = upstream.ok ? 200 : 502;
128
+ res.setHeader("content-type", "application/json; charset=utf-8");
129
+ res.setHeader("cache-control", "no-store");
130
+ res.end(text || JSON.stringify({ error: "Empty response from financial tool" }));
131
+ }
132
+ catch (err) {
133
+ json(res, 502, { error: `Financial tool request failed: ${err instanceof Error ? err.message : String(err)}` });
134
+ }
135
+ finally {
136
+ clearTimeout(timer);
137
+ }
138
+ }
139
+ export function startWebappServer(options) {
140
+ const host = options.host ?? "0.0.0.0";
141
+ const requestedPort = options.port ?? 3102;
142
+ const agentName = options.config.agentName;
143
+ const server = http.createServer((req, res) => {
144
+ try {
145
+ handleRequest(req, res);
146
+ }
147
+ catch (err) {
148
+ logger.warn(`[webapp] Unhandled request error: ${err instanceof Error ? err.message : String(err)}`);
149
+ if (!res.headersSent) {
150
+ res.statusCode = 500;
151
+ res.end("Internal Server Error");
152
+ }
153
+ }
154
+ });
155
+ function handleRequest(req, res) {
156
+ const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
157
+ const pathname = url.pathname;
158
+ if (pathname === "/healthz") {
159
+ json(res, 200, { ok: true });
160
+ return;
161
+ }
162
+ const auth = resolveOwnerAuth(req);
163
+ // ── Login (owner-email cookie gate, scoped to the whole workspace) ──
164
+ if (pathname === "/login" && req.method === "GET") {
165
+ if (auth.hasSession) {
166
+ res.statusCode = 302;
167
+ res.setHeader("location", "/");
168
+ res.end();
169
+ return;
170
+ }
171
+ res.statusCode = 200;
172
+ res.setHeader("content-type", "text/html; charset=utf-8");
173
+ res.setHeader("cache-control", "no-store");
174
+ res.end(renderOwnerLoginHtml("/login"));
175
+ return;
176
+ }
177
+ if (pathname === "/login" && req.method === "POST") {
178
+ void readOwnerEmailFromForm(req, res).then((submitted) => {
179
+ if (submitted === null)
180
+ return; // response already sent (oversize)
181
+ if (auth.ownerEmail && auth.expectedHash && submitted === auth.ownerEmail) {
182
+ res.statusCode = 302;
183
+ res.setHeader("location", "/");
184
+ res.setHeader("set-cookie", `${OBS_AUTH_COOKIE}=${auth.expectedHash}; Path=/; HttpOnly; SameSite=Strict`);
185
+ res.end();
186
+ return;
187
+ }
188
+ res.statusCode = 401;
189
+ res.setHeader("content-type", "text/html; charset=utf-8");
190
+ res.setHeader("cache-control", "no-store");
191
+ res.end(renderOwnerLoginHtml("/login", "That email does not match the configured owner."));
192
+ });
193
+ return;
194
+ }
195
+ if (pathname === "/logout" && req.method === "POST") {
196
+ res.statusCode = 302;
197
+ res.setHeader("location", "/login");
198
+ res.setHeader("set-cookie", `${OBS_AUTH_COOKIE}=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0`);
199
+ res.end();
200
+ return;
201
+ }
202
+ // Everything below requires an authenticated owner session.
203
+ const requireAuth = () => {
204
+ if (auth.hasSession)
205
+ return true;
206
+ // For HTML navigations show the login page; for API calls return 401 JSON.
207
+ if (pathname.startsWith("/api/")) {
208
+ json(res, 401, { error: "Unauthorized" });
209
+ }
210
+ else {
211
+ res.statusCode = 401;
212
+ res.setHeader("content-type", "text/html; charset=utf-8");
213
+ res.setHeader("cache-control", "no-store");
214
+ res.end(renderOwnerLoginHtml("/login"));
215
+ }
216
+ return false;
217
+ };
218
+ // ── IDE shell ──────────────────────────────────────────────────────
219
+ if (pathname === "/" || pathname === "/index.html") {
220
+ if (!requireAuth())
221
+ return;
222
+ res.statusCode = 200;
223
+ res.setHeader("content-type", "text/html; charset=utf-8");
224
+ res.setHeader("cache-control", "no-store");
225
+ res.end(renderWorkspaceHtml(agentName));
226
+ return;
227
+ }
228
+ // ── Workspace layout ───────────────────────────────────────────────
229
+ if (pathname === "/api/workspace") {
230
+ if (!requireAuth())
231
+ return;
232
+ json(res, 200, loadWorkspace());
233
+ return;
234
+ }
235
+ // ── Dashboard HTML files ───────────────────────────────────────────
236
+ const dashMatch = /^\/dashboards\/([a-z0-9-]+)\.html$/.exec(pathname);
237
+ if (dashMatch) {
238
+ if (!requireAuth())
239
+ return;
240
+ let filePath;
241
+ try {
242
+ filePath = getDashboardHtmlPath(dashMatch[1]);
243
+ }
244
+ catch {
245
+ res.statusCode = 404;
246
+ res.end("Not found");
247
+ return;
248
+ }
249
+ if (!fs.existsSync(filePath)) {
250
+ res.statusCode = 404;
251
+ res.setHeader("content-type", "text/plain; charset=utf-8");
252
+ res.end("Dashboard not found");
253
+ return;
254
+ }
255
+ res.statusCode = 200;
256
+ res.setHeader("content-type", "text/html; charset=utf-8");
257
+ res.setHeader("cache-control", "no-store");
258
+ fs.createReadStream(filePath).pipe(res);
259
+ return;
260
+ }
261
+ // ── Chat: SSE stream of agent replies ──────────────────────────────
262
+ if (pathname === "/api/events") {
263
+ if (!requireAuth())
264
+ return;
265
+ const senderId = url.searchParams.get("sender") ?? `web-anon-${Date.now()}`;
266
+ const web = getWebAdapter();
267
+ if (!web) {
268
+ json(res, 503, { error: "Web channel not available" });
269
+ return;
270
+ }
271
+ web.addSseClient(res, senderId);
272
+ return;
273
+ }
274
+ // ── Chat: inject a user message into the shared agent session ──────
275
+ if (pathname === "/api/chat" && req.method === "POST") {
276
+ if (!requireAuth())
277
+ return;
278
+ void (async () => {
279
+ try {
280
+ const body = (await readJsonBody(req));
281
+ const text = typeof body.text === "string" ? body.text.trim() : "";
282
+ if (!text) {
283
+ json(res, 400, { error: "Missing 'text' field" });
284
+ return;
285
+ }
286
+ const sender = typeof body.sender === "string" && body.sender ? body.sender : `web-${process.pid}`;
287
+ const state = getAgentState();
288
+ const msg = {
289
+ id: `web-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
290
+ channel: "web",
291
+ sender,
292
+ text,
293
+ attachments: [],
294
+ timestamp: new Date().toISOString(),
295
+ meta: { source: "web" },
296
+ };
297
+ state.replyMap.set(`web::${sender}`, {
298
+ sender,
299
+ channel: "web",
300
+ replyContext: { messageId: msg.id },
301
+ });
302
+ const web = getWebAdapter();
303
+ if (web) {
304
+ web.injectMessage(msg);
305
+ web.pushEvent({ type: "ack", timestamp: new Date().toISOString(), commandId: msg.id, commandState: "queued" }, sender);
306
+ }
307
+ else {
308
+ state.messageQueue.enqueue(msg);
309
+ state.channelManager.emit("message", msg);
310
+ }
311
+ json(res, 200, { ok: true, messageId: msg.id });
312
+ }
313
+ catch (err) {
314
+ json(res, 500, { error: err instanceof Error ? err.message : String(err) });
315
+ }
316
+ })();
317
+ return;
318
+ }
319
+ // ── Optional: live financial data proxy for dashboards ─────────────
320
+ if (pathname === "/api/dashboard-data") {
321
+ if (!requireAuth())
322
+ return;
323
+ void handleDashboardDataProxy(options.config, url, res);
324
+ return;
325
+ }
326
+ res.statusCode = 404;
327
+ res.setHeader("content-type", "text/plain; charset=utf-8");
328
+ res.end("Not found");
329
+ }
330
+ server.on("error", (err) => {
331
+ logger.warn(`[webapp] Server failed to start: ${err instanceof Error ? err.message : String(err)}`);
332
+ });
333
+ let boundPort = 0;
334
+ let publicUrl = null;
335
+ server.listen(requestedPort, host, () => {
336
+ const address = server.address();
337
+ boundPort = typeof address === "object" && address ? address.port : requestedPort;
338
+ logger.system(`Web workspace: http://${host}:${boundPort}/`);
339
+ registerWorkspaceIngress(options, boundPort);
340
+ if (options.tunnelHostname) {
341
+ publicUrl = `https://${options.tunnelHostname}`;
342
+ logger.system(`[webapp] Public URL: ${publicUrl} (via Cloudflare tunnel)`);
343
+ // Best-effort: surface the URL in /status once agent state exists.
344
+ // The agent loop initializes state after this server binds, so retry
345
+ // briefly until the singleton is available.
346
+ const setUrl = () => {
347
+ try {
348
+ getAgentState().workspaceUrl = publicUrl ?? undefined;
349
+ return true;
350
+ }
351
+ catch {
352
+ return false;
353
+ }
354
+ };
355
+ if (!setUrl()) {
356
+ let attempts = 0;
357
+ const t = setInterval(() => {
358
+ if (setUrl() || ++attempts > 60)
359
+ clearInterval(t);
360
+ }, 1000);
361
+ t.unref();
362
+ }
363
+ }
364
+ });
365
+ return {
366
+ get port() { return boundPort; },
367
+ get publicUrl() { return publicUrl; },
368
+ close: async () => {
369
+ await new Promise((resolve) => {
370
+ server.close(() => { resolve(); });
371
+ });
372
+ },
373
+ };
374
+ }
375
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/webapp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Shared storage model for the web workspace.
3
+ *
4
+ * Dashboards are agent-authored self-contained HTML files stored under the
5
+ * active profile's `dashboards/` directory. The IDE-style layout (sidebar
6
+ * groups, open tabs, temp views) is described by `workspace.json` in the same
7
+ * profile directory. Both the workspace HTTP server (reads) and the `webapp`
8
+ * MCP tool (writes) go through these helpers so the on-disk shape stays
9
+ * consistent.
10
+ */
11
+ /** A dashboard tab shown in the main area. */
12
+ export interface DashboardTab {
13
+ /** Slug (also the HTML filename without extension). */
14
+ name: string;
15
+ /** Human-friendly tab label. */
16
+ title: string;
17
+ /** Optional sidebar group this dashboard belongs to. */
18
+ group?: string;
19
+ /** Marks a transient/scratch view (rendered under "Temp Views"). */
20
+ temp?: boolean;
21
+ /** ISO timestamp of the last write. */
22
+ updatedAt: string;
23
+ }
24
+ /** A free-form sidebar group with a label and ordered dashboard slugs. */
25
+ export interface SidebarGroup {
26
+ label: string;
27
+ items: string[];
28
+ }
29
+ export interface Workspace {
30
+ /** Ordered list of dashboards/tabs. */
31
+ tabs: DashboardTab[];
32
+ /** Sidebar grouping (purely presentational). */
33
+ sidebar: SidebarGroup[];
34
+ /** Free-text focus notes shown at the bottom of the sidebar. */
35
+ focus: string[];
36
+ /** ISO timestamp of the last workspace mutation. */
37
+ updatedAt: string;
38
+ }
39
+ export declare function getDashboardsDir(): string;
40
+ export declare function getWorkspaceFile(): string;
41
+ /**
42
+ * Validate + normalize a dashboard slug. Allows lowercase letters, digits,
43
+ * and hyphens only (DNS-label-ish) so it is safe to use as a filename and in
44
+ * URLs. Throws on invalid input.
45
+ */
46
+ export declare function normalizeDashboardName(raw: string): string;
47
+ export declare function loadWorkspace(): Workspace;
48
+ export declare function saveWorkspace(ws: Workspace): void;
49
+ /** Resolve a dashboard HTML path, guarding against path traversal. */
50
+ export declare function getDashboardHtmlPath(name: string): string;
51
+ /**
52
+ * Write a dashboard's HTML file and upsert its tab entry in workspace.json.
53
+ * Returns the normalized slug.
54
+ */
55
+ export declare function writeDashboard(opts: {
56
+ name: string;
57
+ html: string;
58
+ title?: string;
59
+ group?: string;
60
+ temp?: boolean;
61
+ }): string;
62
+ /** Delete a dashboard HTML file and remove it from workspace.json. */
63
+ export declare function deleteDashboard(rawName: string): void;
64
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/webapp/storage.ts"],"names":[],"mappings":"AAKA;;;;;;;;;GASG;AAEH,8CAA8C;AAC9C,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0EAA0E;AAC1E,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,uCAAuC;IACvC,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,gDAAgD;IAChD,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,gEAAgE;IAChE,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK1D;AAMD,wBAAgB,aAAa,IAAI,SAAS,CAezC;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAKjD;AAED,sEAAsE;AACtE,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,GAAG,MAAM,CAyBT;AAED,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAWrD"}
@@ -0,0 +1,103 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { getConfigDir } from "../config/index.js";
4
+ import { logger } from "../logger.js";
5
+ const DASHBOARDS_DIRNAME = "dashboards";
6
+ const WORKSPACE_FILENAME = "workspace.json";
7
+ export function getDashboardsDir() {
8
+ return path.join(getConfigDir(), DASHBOARDS_DIRNAME);
9
+ }
10
+ export function getWorkspaceFile() {
11
+ return path.join(getConfigDir(), WORKSPACE_FILENAME);
12
+ }
13
+ /**
14
+ * Validate + normalize a dashboard slug. Allows lowercase letters, digits,
15
+ * and hyphens only (DNS-label-ish) so it is safe to use as a filename and in
16
+ * URLs. Throws on invalid input.
17
+ */
18
+ export function normalizeDashboardName(raw) {
19
+ const name = raw.trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
20
+ if (!name)
21
+ throw new Error(`Invalid dashboard name: "${raw}"`);
22
+ if (name.length > 64)
23
+ throw new Error(`Dashboard name too long (max 64 chars): "${raw}"`);
24
+ return name;
25
+ }
26
+ function emptyWorkspace() {
27
+ return { tabs: [], sidebar: [], focus: [], updatedAt: new Date().toISOString() };
28
+ }
29
+ export function loadWorkspace() {
30
+ const file = getWorkspaceFile();
31
+ if (!fs.existsSync(file))
32
+ return emptyWorkspace();
33
+ try {
34
+ const parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
35
+ return {
36
+ tabs: Array.isArray(parsed.tabs) ? parsed.tabs : [],
37
+ sidebar: Array.isArray(parsed.sidebar) ? parsed.sidebar : [],
38
+ focus: Array.isArray(parsed.focus) ? parsed.focus : [],
39
+ updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : new Date().toISOString(),
40
+ };
41
+ }
42
+ catch (err) {
43
+ logger.warn(`[webapp] Failed to parse workspace.json: ${err instanceof Error ? err.message : String(err)}`);
44
+ return emptyWorkspace();
45
+ }
46
+ }
47
+ export function saveWorkspace(ws) {
48
+ ws.updatedAt = new Date().toISOString();
49
+ const file = getWorkspaceFile();
50
+ fs.mkdirSync(path.dirname(file), { recursive: true });
51
+ fs.writeFileSync(file, JSON.stringify(ws, null, 2), "utf-8");
52
+ }
53
+ /** Resolve a dashboard HTML path, guarding against path traversal. */
54
+ export function getDashboardHtmlPath(name) {
55
+ const safe = normalizeDashboardName(name);
56
+ return path.join(getDashboardsDir(), `${safe}.html`);
57
+ }
58
+ /**
59
+ * Write a dashboard's HTML file and upsert its tab entry in workspace.json.
60
+ * Returns the normalized slug.
61
+ */
62
+ export function writeDashboard(opts) {
63
+ const name = normalizeDashboardName(opts.name);
64
+ const dir = getDashboardsDir();
65
+ fs.mkdirSync(dir, { recursive: true });
66
+ fs.writeFileSync(path.join(dir, `${name}.html`), opts.html, "utf-8");
67
+ const ws = loadWorkspace();
68
+ const now = new Date().toISOString();
69
+ const existing = ws.tabs.find((t) => t.name === name);
70
+ if (existing) {
71
+ existing.title = opts.title ?? existing.title;
72
+ if (opts.group !== undefined)
73
+ existing.group = opts.group;
74
+ if (opts.temp !== undefined)
75
+ existing.temp = opts.temp;
76
+ existing.updatedAt = now;
77
+ }
78
+ else {
79
+ ws.tabs.push({
80
+ name,
81
+ title: opts.title ?? name,
82
+ group: opts.group,
83
+ temp: opts.temp,
84
+ updatedAt: now,
85
+ });
86
+ }
87
+ saveWorkspace(ws);
88
+ return name;
89
+ }
90
+ /** Delete a dashboard HTML file and remove it from workspace.json. */
91
+ export function deleteDashboard(rawName) {
92
+ const name = normalizeDashboardName(rawName);
93
+ const file = path.join(getDashboardsDir(), `${name}.html`);
94
+ if (fs.existsSync(file))
95
+ fs.unlinkSync(file);
96
+ const ws = loadWorkspace();
97
+ ws.tabs = ws.tabs.filter((t) => t.name !== name);
98
+ for (const group of ws.sidebar) {
99
+ group.items = group.items.filter((i) => i !== name);
100
+ }
101
+ saveWorkspace(ws);
102
+ }
103
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/webapp/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function renderWorkspaceHtml(agentName: string): string;
2
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/webapp/ui.ts"],"names":[],"mappings":"AAOA,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAuT7D"}