@agent-relay/dashboard-server 2.0.82 → 2.0.84

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 (393) hide show
  1. package/dist/index.d.ts +3 -21
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +3 -23
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/attachment-storage.d.ts +10 -0
  6. package/dist/lib/attachment-storage.d.ts.map +1 -0
  7. package/dist/lib/attachment-storage.js +53 -0
  8. package/dist/lib/attachment-storage.js.map +1 -0
  9. package/dist/lib/broadcast.d.ts +18 -0
  10. package/dist/lib/broadcast.d.ts.map +1 -0
  11. package/dist/lib/broadcast.js +118 -0
  12. package/dist/lib/broadcast.js.map +1 -0
  13. package/dist/lib/channel-state.d.ts +32 -0
  14. package/dist/lib/channel-state.d.ts.map +1 -0
  15. package/dist/lib/channel-state.js +146 -0
  16. package/dist/lib/channel-state.js.map +1 -0
  17. package/dist/lib/cli-auth.d.ts +40 -0
  18. package/dist/lib/cli-auth.d.ts.map +1 -0
  19. package/dist/lib/cli-auth.js +144 -0
  20. package/dist/lib/cli-auth.js.map +1 -0
  21. package/dist/lib/cloud-persistence.d.ts +6 -0
  22. package/dist/lib/cloud-persistence.d.ts.map +1 -0
  23. package/dist/lib/cloud-persistence.js +130 -0
  24. package/dist/lib/cloud-persistence.js.map +1 -0
  25. package/dist/lib/data-assembly.d.ts +136 -0
  26. package/dist/lib/data-assembly.d.ts.map +1 -0
  27. package/dist/lib/data-assembly.js +550 -0
  28. package/dist/lib/data-assembly.js.map +1 -0
  29. package/dist/lib/file-search.d.ts +8 -0
  30. package/dist/lib/file-search.d.ts.map +1 -0
  31. package/dist/lib/file-search.js +90 -0
  32. package/dist/lib/file-search.js.map +1 -0
  33. package/dist/lib/identity.d.ts +54 -0
  34. package/dist/lib/identity.d.ts.map +1 -0
  35. package/dist/lib/identity.js +124 -0
  36. package/dist/lib/identity.js.map +1 -0
  37. package/dist/lib/log-line-cleaner.d.ts +20 -0
  38. package/dist/lib/log-line-cleaner.d.ts.map +1 -0
  39. package/dist/lib/log-line-cleaner.js +117 -0
  40. package/dist/lib/log-line-cleaner.js.map +1 -0
  41. package/dist/lib/log-reader.d.ts +14 -0
  42. package/dist/lib/log-reader.d.ts.map +1 -0
  43. package/dist/lib/log-reader.js +80 -0
  44. package/dist/lib/log-reader.js.map +1 -0
  45. package/dist/lib/message-id.d.ts +30 -0
  46. package/dist/lib/message-id.d.ts.map +1 -0
  47. package/dist/lib/message-id.js +50 -0
  48. package/dist/lib/message-id.js.map +1 -0
  49. package/dist/lib/process-metrics.d.ts +11 -0
  50. package/dist/lib/process-metrics.d.ts.map +1 -0
  51. package/dist/lib/process-metrics.js +252 -0
  52. package/dist/lib/process-metrics.js.map +1 -0
  53. package/dist/lib/proxy-route-table.d.ts +16 -0
  54. package/dist/lib/proxy-route-table.d.ts.map +1 -0
  55. package/dist/lib/proxy-route-table.js +73 -0
  56. package/dist/lib/proxy-route-table.js.map +1 -0
  57. package/dist/lib/send-strategy.d.ts +61 -0
  58. package/dist/lib/send-strategy.d.ts.map +1 -0
  59. package/dist/lib/send-strategy.js +134 -0
  60. package/dist/lib/send-strategy.js.map +1 -0
  61. package/dist/lib/server-state.d.ts +115 -0
  62. package/dist/lib/server-state.d.ts.map +1 -0
  63. package/dist/lib/server-state.js +138 -0
  64. package/dist/lib/server-state.js.map +1 -0
  65. package/dist/lib/spawned-agents.d.ts +35 -0
  66. package/dist/lib/spawned-agents.d.ts.map +1 -0
  67. package/dist/lib/spawned-agents.js +323 -0
  68. package/dist/lib/spawned-agents.js.map +1 -0
  69. package/dist/lib/types.d.ts +117 -0
  70. package/dist/lib/types.d.ts.map +1 -0
  71. package/dist/lib/types.js +12 -0
  72. package/dist/lib/types.js.map +1 -0
  73. package/dist/lib/utils.d.ts +71 -0
  74. package/dist/lib/utils.d.ts.map +1 -0
  75. package/dist/lib/utils.js +332 -0
  76. package/dist/lib/utils.js.map +1 -0
  77. package/dist/lib/websocket-runtime.d.ts +17 -0
  78. package/dist/lib/websocket-runtime.d.ts.map +1 -0
  79. package/dist/lib/websocket-runtime.js +76 -0
  80. package/dist/lib/websocket-runtime.js.map +1 -0
  81. package/dist/mocks/fixtures.d.ts +2 -2
  82. package/dist/mocks/fixtures.js +1 -1
  83. package/dist/mocks/routes.d.ts.map +1 -1
  84. package/dist/mocks/routes.js +30 -3
  85. package/dist/mocks/routes.js.map +1 -1
  86. package/dist/mocks/types.d.ts +1 -1
  87. package/dist/mocks/types.js +1 -1
  88. package/dist/proxy-server.d.ts +7 -33
  89. package/dist/proxy-server.d.ts.map +1 -1
  90. package/dist/proxy-server.js +292 -200
  91. package/dist/proxy-server.js.map +1 -1
  92. package/dist/relaycast-provider-helpers.d.ts +40 -0
  93. package/dist/relaycast-provider-helpers.d.ts.map +1 -0
  94. package/dist/relaycast-provider-helpers.js +284 -0
  95. package/dist/relaycast-provider-helpers.js.map +1 -0
  96. package/dist/relaycast-provider-types.d.ts +116 -0
  97. package/dist/relaycast-provider-types.d.ts.map +1 -0
  98. package/dist/relaycast-provider-types.js +6 -0
  99. package/dist/relaycast-provider-types.js.map +1 -0
  100. package/dist/relaycast-provider.d.ts +42 -0
  101. package/dist/relaycast-provider.d.ts.map +1 -0
  102. package/dist/relaycast-provider.js +277 -0
  103. package/dist/relaycast-provider.js.map +1 -0
  104. package/dist/routes/agents.d.ts +7 -0
  105. package/dist/routes/agents.d.ts.map +1 -0
  106. package/dist/routes/agents.js +180 -0
  107. package/dist/routes/agents.js.map +1 -0
  108. package/dist/routes/auth.d.ts +45 -0
  109. package/dist/routes/auth.d.ts.map +1 -0
  110. package/dist/routes/auth.js +261 -0
  111. package/dist/routes/auth.js.map +1 -0
  112. package/dist/routes/broker-proxy.d.ts +7 -0
  113. package/dist/routes/broker-proxy.d.ts.map +1 -0
  114. package/dist/routes/broker-proxy.js +114 -0
  115. package/dist/routes/broker-proxy.js.map +1 -0
  116. package/dist/routes/channels-integrated.d.ts +84 -0
  117. package/dist/routes/channels-integrated.d.ts.map +1 -0
  118. package/dist/routes/channels-integrated.js +644 -0
  119. package/dist/routes/channels-integrated.js.map +1 -0
  120. package/dist/routes/channels.d.ts +7 -0
  121. package/dist/routes/channels.d.ts.map +1 -0
  122. package/dist/routes/channels.js +453 -0
  123. package/dist/routes/channels.js.map +1 -0
  124. package/dist/routes/data.d.ts +7 -0
  125. package/dist/routes/data.d.ts.map +1 -0
  126. package/dist/routes/data.js +108 -0
  127. package/dist/routes/data.js.map +1 -0
  128. package/dist/routes/decisions.d.ts +31 -0
  129. package/dist/routes/decisions.d.ts.map +1 -0
  130. package/dist/routes/decisions.js +109 -0
  131. package/dist/routes/decisions.js.map +1 -0
  132. package/dist/routes/fleet.d.ts +24 -0
  133. package/dist/routes/fleet.d.ts.map +1 -0
  134. package/dist/routes/fleet.js +131 -0
  135. package/dist/routes/fleet.js.map +1 -0
  136. package/dist/routes/health.d.ts +7 -0
  137. package/dist/routes/health.d.ts.map +1 -0
  138. package/dist/routes/health.js +55 -0
  139. package/dist/routes/health.js.map +1 -0
  140. package/dist/routes/history-relaycast.d.ts +8 -0
  141. package/dist/routes/history-relaycast.d.ts.map +1 -0
  142. package/dist/routes/history-relaycast.js +165 -0
  143. package/dist/routes/history-relaycast.js.map +1 -0
  144. package/dist/routes/history.d.ts +13 -0
  145. package/dist/routes/history.d.ts.map +1 -0
  146. package/dist/routes/history.js +205 -0
  147. package/dist/routes/history.js.map +1 -0
  148. package/dist/routes/messaging.d.ts +31 -0
  149. package/dist/routes/messaging.d.ts.map +1 -0
  150. package/dist/routes/messaging.js +182 -0
  151. package/dist/routes/messaging.js.map +1 -0
  152. package/dist/routes/metrics.d.ts +26 -0
  153. package/dist/routes/metrics.d.ts.map +1 -0
  154. package/dist/routes/metrics.js +276 -0
  155. package/dist/routes/metrics.js.map +1 -0
  156. package/dist/routes/reactions.d.ts +9 -0
  157. package/dist/routes/reactions.d.ts.map +1 -0
  158. package/dist/routes/reactions.js +76 -0
  159. package/dist/routes/reactions.js.map +1 -0
  160. package/dist/routes/relay-config.d.ts +4 -0
  161. package/dist/routes/relay-config.d.ts.map +1 -0
  162. package/dist/routes/relay-config.js +50 -0
  163. package/dist/routes/relay-config.js.map +1 -0
  164. package/dist/routes/settings.d.ts +6 -0
  165. package/dist/routes/settings.d.ts.map +1 -0
  166. package/dist/routes/settings.js +119 -0
  167. package/dist/routes/settings.js.map +1 -0
  168. package/dist/routes/spawn.d.ts +74 -0
  169. package/dist/routes/spawn.d.ts.map +1 -0
  170. package/dist/routes/spawn.js +520 -0
  171. package/dist/routes/spawn.js.map +1 -0
  172. package/dist/routes/system.d.ts +21 -0
  173. package/dist/routes/system.d.ts.map +1 -0
  174. package/dist/routes/system.js +186 -0
  175. package/dist/routes/system.js.map +1 -0
  176. package/dist/routes/tasks.d.ts +27 -0
  177. package/dist/routes/tasks.d.ts.map +1 -0
  178. package/dist/routes/tasks.js +103 -0
  179. package/dist/routes/tasks.js.map +1 -0
  180. package/dist/routes/ui.d.ts +6 -0
  181. package/dist/routes/ui.d.ts.map +1 -0
  182. package/dist/routes/ui.js +114 -0
  183. package/dist/routes/ui.js.map +1 -0
  184. package/dist/server.d.ts.map +1 -1
  185. package/dist/server.js +337 -6072
  186. package/dist/server.js.map +1 -1
  187. package/dist/services/broker-spawn-reader.d.ts +40 -0
  188. package/dist/services/broker-spawn-reader.d.ts.map +1 -0
  189. package/dist/services/broker-spawn-reader.js +155 -0
  190. package/dist/services/broker-spawn-reader.js.map +1 -0
  191. package/dist/services/health-worker-manager.d.ts +9 -60
  192. package/dist/services/health-worker-manager.d.ts.map +1 -1
  193. package/dist/services/health-worker-manager.js +18 -148
  194. package/dist/services/health-worker-manager.js.map +1 -1
  195. package/dist/services/index.d.ts +3 -3
  196. package/dist/services/index.d.ts.map +1 -1
  197. package/dist/services/index.js +3 -3
  198. package/dist/services/index.js.map +1 -1
  199. package/dist/services/metrics.d.ts +11 -104
  200. package/dist/services/metrics.d.ts.map +1 -1
  201. package/dist/services/metrics.js +21 -190
  202. package/dist/services/metrics.js.map +1 -1
  203. package/dist/services/needs-attention.d.ts +21 -22
  204. package/dist/services/needs-attention.d.ts.map +1 -1
  205. package/dist/services/needs-attention.js +46 -71
  206. package/dist/services/needs-attention.js.map +1 -1
  207. package/dist/services/user-bridge.d.ts +0 -3
  208. package/dist/services/user-bridge.d.ts.map +1 -1
  209. package/dist/services/user-bridge.js +0 -5
  210. package/dist/services/user-bridge.js.map +1 -1
  211. package/dist/start.d.ts +4 -4
  212. package/dist/start.js +96 -89
  213. package/dist/start.js.map +1 -1
  214. package/dist/types/index.d.ts +13 -16
  215. package/dist/types/index.d.ts.map +1 -1
  216. package/dist/websocket/bridge.d.ts +12 -0
  217. package/dist/websocket/bridge.d.ts.map +1 -0
  218. package/dist/websocket/bridge.js +33 -0
  219. package/dist/websocket/bridge.js.map +1 -0
  220. package/dist/websocket/logs.d.ts +30 -0
  221. package/dist/websocket/logs.d.ts.map +1 -0
  222. package/dist/websocket/logs.js +577 -0
  223. package/dist/websocket/logs.js.map +1 -0
  224. package/dist/websocket/main.d.ts +15 -0
  225. package/dist/websocket/main.d.ts.map +1 -0
  226. package/dist/websocket/main.js +84 -0
  227. package/dist/websocket/main.js.map +1 -0
  228. package/dist/websocket/mock.d.ts +6 -0
  229. package/dist/websocket/mock.d.ts.map +1 -0
  230. package/dist/websocket/mock.js +49 -0
  231. package/dist/websocket/mock.js.map +1 -0
  232. package/dist/websocket/presence.d.ts +74 -0
  233. package/dist/websocket/presence.d.ts.map +1 -0
  234. package/dist/websocket/presence.js +330 -0
  235. package/dist/websocket/presence.js.map +1 -0
  236. package/dist/websocket/proxy.d.ts +6 -0
  237. package/dist/websocket/proxy.d.ts.map +1 -0
  238. package/dist/websocket/proxy.js +39 -0
  239. package/dist/websocket/proxy.js.map +1 -0
  240. package/dist/websocket/standalone.d.ts +17 -0
  241. package/dist/websocket/standalone.d.ts.map +1 -0
  242. package/dist/websocket/standalone.js +268 -0
  243. package/dist/websocket/standalone.js.map +1 -0
  244. package/out/404.html +1 -1
  245. package/out/_next/static/chunks/1028-da5d75e35d1420f1.js +1 -0
  246. package/out/_next/static/chunks/1528-78b17000a7e10bc6.js +2 -0
  247. package/out/_next/static/chunks/1695-4a5d33ba715e09b4.js +1 -0
  248. package/out/_next/static/chunks/1705-36c2180d00a4a569.js +1 -0
  249. package/out/_next/static/chunks/1dd3208c-e1f87c7b3dc1a820.js +1 -0
  250. package/out/_next/static/chunks/3663-47290254b8f6f5dd.js +1 -0
  251. package/out/_next/static/chunks/3677-4b225baf4801d9b9.js +73 -0
  252. package/out/_next/static/chunks/5118-7e8ada2df38eef07.js +1 -0
  253. package/out/_next/static/chunks/5888-15cbe97c90ed5fae.js +1 -0
  254. package/out/_next/static/chunks/6773-a45343a98df3abb5.js +1 -0
  255. package/out/_next/static/chunks/6940-b824612b605e79b3.js +9 -0
  256. package/out/_next/static/chunks/7894-f4a15249082a680d.js +1 -0
  257. package/out/_next/static/chunks/9175-b3617c1e5cbfed0e.js +1 -0
  258. package/out/_next/static/chunks/9372-1a804b8d08c7a236.js +1 -0
  259. package/out/_next/static/chunks/{ab6c8a12-0a58072fbb505134.js → ab6c8a12-91438a812d94ecf0.js} +1 -1
  260. package/out/_next/static/chunks/app/_not-found/page-8e8842f82d204726.js +1 -0
  261. package/out/_next/static/chunks/app/about/page-b78577a7da8fa459.js +1 -0
  262. package/out/_next/static/chunks/app/app/[[...slug]]/page-3dffd65b6344f53e.js +1 -0
  263. package/out/_next/static/chunks/app/app/onboarding/page-b89be9aa6264a5e1.js +1 -0
  264. package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-fbd00893ef69e499.js +1 -0
  265. package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-de2ea13649d0b6d3.js +1 -0
  266. package/out/_next/static/chunks/app/blog/page-a08e263c57a156fa.js +1 -0
  267. package/out/_next/static/chunks/app/careers/page-02228e1d6969b232.js +1 -0
  268. package/out/_next/static/chunks/app/changelog/page-1b5c1d79efc6e53a.js +1 -0
  269. package/out/_next/static/chunks/app/cloud/link/page-99654edffffb3af2.js +1 -0
  270. package/out/_next/static/chunks/app/complete-profile/page-59d146e5ddeafc5c.js +1 -0
  271. package/out/_next/static/chunks/app/connect-repos/page-995e16a976a6632c.js +1 -0
  272. package/out/_next/static/chunks/app/contact/page-273396a5ad57bcee.js +1 -0
  273. package/out/_next/static/chunks/app/dev/cli-tools/page-a71b80dcb2d5fc8d.js +1 -0
  274. package/out/_next/static/chunks/app/dev/log-viewer/page-46a6151ae1be0796.js +1 -0
  275. package/out/_next/static/chunks/app/docs/page-7c7cb603b24b7c40.js +1 -0
  276. package/out/_next/static/chunks/app/history/page-0c5cab1dab4e8886.js +1 -0
  277. package/out/_next/static/chunks/app/layout-96d72ba8ef8a43a0.js +1 -0
  278. package/out/_next/static/chunks/app/login/page-0ccbab34213df842.js +1 -0
  279. package/out/_next/static/chunks/app/metrics/page-8616272aeab9c8b0.js +1 -0
  280. package/out/_next/static/chunks/app/page-09ce10603ad9a251.js +1 -0
  281. package/out/_next/static/chunks/app/pricing/page-91c975079120c941.js +1 -0
  282. package/out/_next/static/chunks/app/privacy/{page-c21d51ac2dee3a88.js → page-a49ab271cc686644.js} +1 -1
  283. package/out/_next/static/chunks/app/providers/{page-59114505f4353512.js → page-d775d6eb5bc29e96.js} +1 -1
  284. package/out/_next/static/chunks/app/providers/setup/[provider]/page-ec4ef3cd80de807e.js +1 -0
  285. package/out/_next/static/chunks/app/security/page-d9da9bd9191e8f95.js +1 -0
  286. package/out/_next/static/chunks/app/signup/page-930eca0bf5fd299d.js +1 -0
  287. package/out/_next/static/chunks/app/terms/page-3e4827620b98613c.js +1 -0
  288. package/out/_next/static/chunks/framework-648e1ae7da590300.js +1 -0
  289. package/out/_next/static/chunks/{main-acb1b24265295d6a.js → main-2b1990080c292d92.js} +1 -1
  290. package/out/_next/static/chunks/main-app-9f6b7ff9e754a8f5.js +1 -0
  291. package/out/_next/static/chunks/pages/_app-a077b72e02273ab1.js +1 -0
  292. package/out/_next/static/chunks/pages/_error-84001666436a04e4.js +1 -0
  293. package/out/_next/static/chunks/{webpack-dd93b81e2659669c.js → webpack-7586035f1585f2db.js} +1 -1
  294. package/out/_next/static/css/eb9fc69d1e3d2bed.css +1 -0
  295. package/out/_next/static/{IxfA6RZu4trcsEMYlkQra → g3G0LMdB7lxcrU5mdM54m}/_buildManifest.js +1 -1
  296. package/out/about.html +2 -2
  297. package/out/about.txt +2 -2
  298. package/out/app/onboarding.html +1 -1
  299. package/out/app/onboarding.txt +2 -2
  300. package/out/app.html +1 -1
  301. package/out/app.txt +2 -2
  302. package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +3 -3
  303. package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
  304. package/out/blog/let-them-cook-multi-agent-orchestration.html +2 -2
  305. package/out/blog/let-them-cook-multi-agent-orchestration.txt +2 -2
  306. package/out/blog.html +2 -2
  307. package/out/blog.txt +1 -1
  308. package/out/careers.html +2 -2
  309. package/out/careers.txt +2 -2
  310. package/out/changelog.html +2 -2
  311. package/out/changelog.txt +2 -2
  312. package/out/cloud/link.html +1 -1
  313. package/out/cloud/link.txt +2 -2
  314. package/out/complete-profile.html +2 -2
  315. package/out/complete-profile.txt +2 -2
  316. package/out/connect-repos.html +1 -1
  317. package/out/connect-repos.txt +2 -2
  318. package/out/contact.html +2 -2
  319. package/out/contact.txt +2 -2
  320. package/out/dev/cli-tools.html +1 -0
  321. package/out/dev/cli-tools.txt +7 -0
  322. package/out/dev/log-viewer.html +23 -0
  323. package/out/dev/log-viewer.txt +7 -0
  324. package/out/docs.html +2 -2
  325. package/out/docs.txt +2 -2
  326. package/out/history.html +1 -1
  327. package/out/history.txt +2 -2
  328. package/out/index.html +1 -1
  329. package/out/index.txt +2 -2
  330. package/out/login.html +2 -2
  331. package/out/login.txt +2 -2
  332. package/out/metrics.html +1 -1
  333. package/out/metrics.txt +2 -2
  334. package/out/pricing.html +2 -2
  335. package/out/pricing.txt +2 -2
  336. package/out/privacy.html +2 -2
  337. package/out/privacy.txt +2 -2
  338. package/out/providers/setup/claude.html +1 -1
  339. package/out/providers/setup/claude.txt +2 -2
  340. package/out/providers/setup/codex.html +1 -1
  341. package/out/providers/setup/codex.txt +2 -2
  342. package/out/providers/setup/cursor.html +1 -1
  343. package/out/providers/setup/cursor.txt +2 -2
  344. package/out/providers.html +1 -1
  345. package/out/providers.txt +2 -2
  346. package/out/security.html +2 -2
  347. package/out/security.txt +2 -2
  348. package/out/signup.html +2 -2
  349. package/out/signup.txt +2 -2
  350. package/out/terms.html +2 -2
  351. package/out/terms.txt +2 -2
  352. package/package.json +10 -11
  353. package/out/_next/static/chunks/11-9a2993a37266dcb3.js +0 -9
  354. package/out/_next/static/chunks/118-ae2b650136a5a5fc.js +0 -1
  355. package/out/_next/static/chunks/1dd3208c-40ab0fc0f60392b8.js +0 -1
  356. package/out/_next/static/chunks/202-fc0763dd7488e58f.js +0 -1
  357. package/out/_next/static/chunks/259-83b77fa1b91ba5aa.js +0 -1
  358. package/out/_next/static/chunks/407-0c82986cf79c8ecb.js +0 -1
  359. package/out/_next/static/chunks/528-f5f676996d613c25.js +0 -2
  360. package/out/_next/static/chunks/663-ddb04081febc3678.js +0 -1
  361. package/out/_next/static/chunks/687-88b6b139a6bb0e2e.js +0 -1
  362. package/out/_next/static/chunks/695-51d25b1988644374.js +0 -1
  363. package/out/_next/static/chunks/773-54a2641043c81e55.js +0 -1
  364. package/out/_next/static/chunks/app/_not-found/page-6da9b72091e5b511.js +0 -1
  365. package/out/_next/static/chunks/app/about/page-fff7c6457683f243.js +0 -1
  366. package/out/_next/static/chunks/app/app/[[...slug]]/page-f7eca1b66fb4249b.js +0 -1
  367. package/out/_next/static/chunks/app/app/onboarding/page-129abc5da2e67971.js +0 -1
  368. package/out/_next/static/chunks/app/blog/go-to-bed-wake-up-to-a-finished-product/page-5d5f28fd126b692f.js +0 -1
  369. package/out/_next/static/chunks/app/blog/let-them-cook-multi-agent-orchestration/page-b194f207fbd91862.js +0 -1
  370. package/out/_next/static/chunks/app/blog/page-b9bd9d8703fca76a.js +0 -1
  371. package/out/_next/static/chunks/app/careers/page-a4bd8d5f4de8f4eb.js +0 -1
  372. package/out/_next/static/chunks/app/changelog/page-9a1f6ad1743d63c5.js +0 -1
  373. package/out/_next/static/chunks/app/cloud/link/page-0844c5699b027c3b.js +0 -1
  374. package/out/_next/static/chunks/app/complete-profile/page-39ed5a67916beb87.js +0 -1
  375. package/out/_next/static/chunks/app/connect-repos/page-297eddee0c39f2a3.js +0 -1
  376. package/out/_next/static/chunks/app/contact/page-3c1dd8690217fade.js +0 -1
  377. package/out/_next/static/chunks/app/docs/page-1875e981f2c3fd13.js +0 -1
  378. package/out/_next/static/chunks/app/history/page-2d5c5695c9e8b40c.js +0 -1
  379. package/out/_next/static/chunks/app/layout-0a4b99656da25511.js +0 -1
  380. package/out/_next/static/chunks/app/login/page-f69c076f5a6fc520.js +0 -1
  381. package/out/_next/static/chunks/app/metrics/page-bebbee055669a17e.js +0 -1
  382. package/out/_next/static/chunks/app/page-0ee604f7070d14c0.js +0 -1
  383. package/out/_next/static/chunks/app/pricing/page-eeae7d594af333b6.js +0 -1
  384. package/out/_next/static/chunks/app/providers/setup/[provider]/page-daf9b3e05e77ae19.js +0 -1
  385. package/out/_next/static/chunks/app/security/page-cd562730fe84a0a2.js +0 -1
  386. package/out/_next/static/chunks/app/signup/page-c242ca08101a84ff.js +0 -1
  387. package/out/_next/static/chunks/app/terms/page-c7001720e7941dc6.js +0 -1
  388. package/out/_next/static/chunks/framework-3664cab31236a9fa.js +0 -1
  389. package/out/_next/static/chunks/main-app-7f73a939a312a228.js +0 -1
  390. package/out/_next/static/chunks/pages/_app-10a93ab5b7c32eb3.js +0 -1
  391. package/out/_next/static/chunks/pages/_error-2d792b2a41857be4.js +0 -1
  392. package/out/_next/static/css/8968d98ed4c4d33f.css +0 -1
  393. /package/out/_next/static/{IxfA6RZu4trcsEMYlkQra → g3G0LMdB7lxcrU5mdM54m}/_ssgManifest.js +0 -0
@@ -1,63 +1,108 @@
1
1
  /**
2
2
  * Relay Dashboard Server
3
3
  *
4
- * A flexible server that can operate in two modes:
5
- * 1. Proxy mode (default): Proxies API/WebSocket requests to a relay daemon
6
- * 2. Mock mode: Returns fixture data for standalone testing/demos
7
- *
8
- * This allows the dashboard to run independently without any external dependencies.
4
+ * A flexible server that can operate in three modes:
5
+ * 1. Proxy mode (default): static files + Relaycast data + broker proxy
6
+ * 2. Standalone mode: static files + Relaycast data (no broker proxy)
7
+ * 3. Mock mode: fixture-backed standalone mode for demos/tests
9
8
  */
10
9
  import express from 'express';
11
10
  import { createServer as createHttpServer } from 'http';
12
- import { createProxyMiddleware } from 'http-proxy-middleware';
13
- import { WebSocketServer, WebSocket } from 'ws';
11
+ import { WebSocketServer } from 'ws';
12
+ import fs from 'fs';
14
13
  import path from 'path';
15
14
  import { fileURLToPath } from 'url';
16
15
  import { registerMockRoutes } from './mocks/routes.js';
17
- import { mockAgents, mockMessages, mockSessions, } from './mocks/fixtures.js';
16
+ import { fetchAgents, fetchChannels, loadRelaycastConfig, } from './relaycast-provider.js';
17
+ import { createSendStrategy } from './lib/send-strategy.js';
18
+ import { DASHBOARD_DISPLAY_NAME } from './relaycast-provider-types.js';
19
+ import { resolveIdentity } from './lib/identity.js';
20
+ import { EMPTY_DASHBOARD_SNAPSHOT } from './lib/types.js';
21
+ import { normalizeRelayUrl, normalizeName, isDirectRecipient, sendHtmlFileOrFallback, getBindHost, mapChannelForDashboard, } from './lib/utils.js';
22
+ import { filterPhantomAgents, mergeBrokerSpawnedAgents, createSpawnedAgentsCaches, } from './lib/spawned-agents.js';
23
+ import { handleMockWebSocket } from './websocket/mock.js';
24
+ import { handleStandaloneWebSocket, handleHybridWebSocket } from './websocket/standalone.js';
25
+ import { handleStandaloneLogWebSocket } from './websocket/logs.js';
26
+ import { registerHealthRoutes } from './routes/health.js';
27
+ import { registerDataRoutes } from './routes/data.js';
28
+ import { registerAgentRoutes } from './routes/agents.js';
29
+ import { registerChannelRoutes } from './routes/channels.js';
30
+ import { registerBrokerProxyRoutes } from './routes/broker-proxy.js';
31
+ import { registerMetricsRoutes } from './routes/metrics.js';
32
+ import { registerReactionRoutes } from './routes/reactions.js';
33
+ import { registerRelayConfigRoutes } from './routes/relay-config.js';
34
+ import { registerRelaycastHistoryRoutes } from './routes/history-relaycast.js';
18
35
  const __filename = fileURLToPath(import.meta.url);
19
36
  const __dirname = path.dirname(__filename);
20
- /**
21
- * Get the host to bind to.
22
- * In cloud environments, bind to '::' (IPv6 any) which also accepts IPv4 on dual-stack.
23
- * This is required for Fly.io's internal IPv6 network (6PN) connectivity.
24
- * Locally, let Node.js use its default behavior.
25
- */
26
- function getBindHost() {
27
- // Explicit override via env var
28
- if (process.env.BIND_HOST) {
29
- return process.env.BIND_HOST;
37
+ function resolveMetricsPagePath(staticDir) {
38
+ const candidates = [
39
+ path.join(staticDir, 'metrics.html'),
40
+ path.join(staticDir, 'metrics', 'index.html'),
41
+ path.join(staticDir, 'app.html'),
42
+ path.join(staticDir, 'index.html'),
43
+ ];
44
+ for (const candidate of candidates) {
45
+ if (fs.existsSync(candidate)) {
46
+ return candidate;
47
+ }
30
48
  }
31
- // Cloud environment detection - bind to :: for IPv6 + IPv4 dual-stack
32
- // Fly.io internal network uses IPv6 (fdaa:...), so 0.0.0.0 won't work
33
- const isCloudEnvironment = process.env.FLY_APP_NAME || // Fly.io
34
- process.env.WORKSPACE_ID || // Agent Relay workspace
35
- process.env.RELAY_WORKSPACE_ID || // Alternative workspace ID
36
- process.env.RUNNING_IN_DOCKER === 'true'; // Docker container
37
- return isCloudEnvironment ? '::' : undefined;
49
+ return candidates[0];
38
50
  }
51
+ const asString = (value) => {
52
+ if (typeof value === 'string' && value.length > 0)
53
+ return value;
54
+ if (Array.isArray(value)) {
55
+ for (const item of value) {
56
+ if (typeof item === 'string' && item.length > 0)
57
+ return item;
58
+ }
59
+ }
60
+ return undefined;
61
+ };
62
+ const getWorkspaceHeader = (headers) => {
63
+ if (!headers)
64
+ return undefined;
65
+ const direct = headers['x-workspace-id'];
66
+ if (typeof direct === 'string' && direct.length > 0)
67
+ return direct;
68
+ for (const [key, value] of Object.entries(headers)) {
69
+ if (key.toLowerCase() === 'x-workspace-id' && typeof value === 'string' && value.length > 0) {
70
+ return value;
71
+ }
72
+ }
73
+ return undefined;
74
+ };
39
75
  /**
40
76
  * Create the dashboard server without starting it
41
77
  */
42
78
  export function createServer(options = {}) {
43
- const { port = parseInt(process.env.PORT || '3888', 10), relayUrl = process.env.RELAY_URL || 'http://localhost:3889', staticDir = process.env.STATIC_DIR || path.join(__dirname, '..', 'out'), verbose = process.env.VERBOSE === 'true', mock = process.env.MOCK === 'true', corsOrigins = process.env.CORS_ORIGINS || '', requestTimeout = parseInt(process.env.REQUEST_TIMEOUT || '30000', 10), } = options;
79
+ const { relayUrl: relayUrlOption, staticDir = process.env.STATIC_DIR || path.join(__dirname, '..', 'out'), dataDir = process.env.DATA_DIR || path.join(process.cwd(), '.agent-relay'), verbose = process.env.VERBOSE === 'true', mock = process.env.MOCK === 'true', corsOrigins = process.env.CORS_ORIGINS || '', requestTimeout = parseInt(process.env.REQUEST_TIMEOUT || '60000', 10), } = options;
80
+ const resolvedDataDir = path.resolve(dataDir);
81
+ if (!process.env.AGENT_RELAY_PROJECT) {
82
+ process.env.AGENT_RELAY_PROJECT = path.dirname(resolvedDataDir);
83
+ }
84
+ const relayUrl = normalizeRelayUrl(relayUrlOption ?? process.env.RELAY_URL);
85
+ const mode = mock ? 'mock' : (relayUrl ? 'proxy' : 'standalone');
86
+ const brokerProxyEnabled = mode === 'proxy' && Boolean(relayUrl);
87
+ const defaultWorkspaceId = process.env.RELAY_WORKSPACE_ID ?? process.env.AGENT_RELAY_WORKSPACE_ID;
88
+ const resolveWorkspaceId = (req) => {
89
+ const fromQuery = asString(req.query?.workspaceId);
90
+ const fromBody = asString(req.body?.workspaceId);
91
+ const fromHeader = getWorkspaceHeader(req.headers);
92
+ return fromQuery || fromBody || fromHeader || defaultWorkspaceId;
93
+ };
44
94
  const app = express();
45
95
  const server = createHttpServer(app);
46
- const mode = mock ? 'mock' : 'proxy';
47
- // Set request timeout
48
96
  server.timeout = requestTimeout;
49
- // Parse JSON bodies
50
97
  app.use(express.json({ limit: '10mb' }));
51
- // CORS middleware - configurable for cross-origin deployments
52
98
  if (corsOrigins) {
53
99
  app.use((req, res, next) => {
54
100
  const origin = req.headers.origin;
55
- // Check if origin is allowed
56
101
  if (corsOrigins === '*') {
57
102
  res.header('Access-Control-Allow-Origin', '*');
58
103
  }
59
104
  else if (origin) {
60
- const allowedOrigins = corsOrigins.split(',').map(o => o.trim());
105
+ const allowedOrigins = corsOrigins.split(',').map((value) => value.trim());
61
106
  if (allowedOrigins.includes(origin)) {
62
107
  res.header('Access-Control-Allow-Origin', origin);
63
108
  }
@@ -66,7 +111,6 @@ export function createServer(options = {}) {
66
111
  res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-CSRF-Token');
67
112
  res.header('Access-Control-Allow-Credentials', 'true');
68
113
  res.header('Access-Control-Expose-Headers', 'X-CSRF-Token');
69
- // Handle preflight requests
70
114
  if (req.method === 'OPTIONS') {
71
115
  res.sendStatus(204);
72
116
  return;
@@ -74,99 +118,250 @@ export function createServer(options = {}) {
74
118
  next();
75
119
  });
76
120
  }
77
- // Logging middleware
78
121
  if (verbose) {
79
122
  app.use((req, _res, next) => {
80
123
  console.log(`[dashboard] ${req.method} ${req.url}`);
81
124
  next();
82
125
  });
83
126
  }
84
- // Health check endpoint (always local)
85
- app.get('/health', (_req, res) => {
86
- res.json({
87
- status: 'ok',
88
- service: 'relay-dashboard',
89
- mode,
90
- uptime: process.uptime(),
91
- });
92
- });
93
- // Keep-alive endpoint
94
- app.get('/keep-alive', (_req, res) => {
95
- res.json({ ok: true });
127
+ // --- Build shared context ---
128
+ const resolveRelaycastConfig = () => loadRelaycastConfig(dataDir);
129
+ const { getSpawnedAgents, getLocalAgentNames } = createSpawnedAgentsCaches({
130
+ brokerProxyEnabled,
131
+ relayUrl,
132
+ dataDir,
133
+ verbose,
96
134
  });
135
+ const getRelaycastSnapshot = async () => {
136
+ const config = resolveRelaycastConfig();
137
+ if (!config) {
138
+ return { ...EMPTY_DASHBOARD_SNAPSHOT };
139
+ }
140
+ const [agents, spawnedAgents, localAgentNames] = await Promise.all([
141
+ fetchAgents(config),
142
+ brokerProxyEnabled ? getSpawnedAgents() : Promise.resolve({ names: null, agents: null }),
143
+ brokerProxyEnabled ? Promise.resolve(null) : Promise.resolve(getLocalAgentNames()),
144
+ ]);
145
+ const filteredAgents = filterPhantomAgents(agents, spawnedAgents.names, localAgentNames);
146
+ const mergedAgents = mergeBrokerSpawnedAgents(filteredAgents, spawnedAgents.agents);
147
+ return {
148
+ agents: mergedAgents,
149
+ users: [],
150
+ messages: [],
151
+ activity: [],
152
+ sessions: [],
153
+ summaries: [],
154
+ };
155
+ };
156
+ const getRelaycastChannels = async () => {
157
+ const config = resolveRelaycastConfig();
158
+ if (!config) {
159
+ return { channels: [], archivedChannels: [] };
160
+ }
161
+ const channels = await fetchChannels(config);
162
+ const activeChannels = [];
163
+ const archivedChannels = [];
164
+ for (const channel of channels) {
165
+ const mapped = mapChannelForDashboard({ ...channel, is_archived: channel.is_archived ?? false });
166
+ if (mapped.status === 'archived') {
167
+ archivedChannels.push(mapped);
168
+ }
169
+ else {
170
+ activeChannels.push(mapped);
171
+ }
172
+ }
173
+ activeChannels.sort((a, b) => a.name.localeCompare(b.name));
174
+ archivedChannels.sort((a, b) => a.name.localeCompare(b.name));
175
+ return { channels: activeChannels, archivedChannels };
176
+ };
177
+ const sendRelaycastMessage = async (params) => {
178
+ const sendTimeout = Math.max(requestTimeout - 5000, 10000);
179
+ const sendStart = Date.now();
180
+ const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Send timed out')), sendTimeout));
181
+ try {
182
+ return await Promise.race([
183
+ (async () => {
184
+ const config = resolveRelaycastConfig();
185
+ const rawTarget = params.to.trim();
186
+ const message = params.message.trim();
187
+ let resolvedTarget = rawTarget;
188
+ if (isDirectRecipient(rawTarget) && config) {
189
+ const relayAgents = await fetchAgents(config);
190
+ const relayMatch = relayAgents.find((agent) => normalizeName(agent.name) === normalizeName(rawTarget));
191
+ if (relayMatch) {
192
+ resolvedTarget = relayMatch.name;
193
+ }
194
+ }
195
+ const projectIdentity = config?.agentName?.trim()
196
+ || path.basename(path.resolve(dataDir, '..'))
197
+ || DASHBOARD_DISPLAY_NAME;
198
+ const senderInput = params.from?.trim() ?? '';
199
+ const senderName = mode === 'proxy'
200
+ ? resolveIdentity(senderInput || projectIdentity, {
201
+ projectIdentity: projectIdentity.trim(),
202
+ relayAgentName: config?.agentName?.trim(),
203
+ })
204
+ : (senderInput || projectIdentity);
205
+ const strategy = createSendStrategy({
206
+ brokerProxyEnabled,
207
+ brokerUrl: relayUrl,
208
+ relaycastConfig: config,
209
+ dataDir,
210
+ });
211
+ if (!strategy) {
212
+ return {
213
+ success: false,
214
+ status: 503,
215
+ error: `Relaycast credentials not found in ${path.join(dataDir, 'relaycast.json')}`,
216
+ };
217
+ }
218
+ console.log(`[dashboard] /api/send request: to=${resolvedTarget}, from=${senderName}, relayUrl=${relayUrl}, timeoutMs=${sendTimeout}`);
219
+ const outcome = await strategy.send({ to: resolvedTarget, message, from: senderName });
220
+ console.log(`[dashboard] /api/send completed in ${Date.now() - sendStart}ms with status=${outcome.success ? 200 : outcome.status}`);
221
+ // Enrich "agent not found" errors with available agent names
222
+ if (!outcome.success && isDirectRecipient(params.to) && config) {
223
+ if (/agent\s+\".+\"\s+not\s+found/i.test(outcome.error)) {
224
+ const relayAgents = await fetchAgents(config);
225
+ const available = relayAgents.map((agent) => agent.name).sort();
226
+ const suffix = available.length > 0
227
+ ? ` Available relay agents: ${available.join(', ')}.`
228
+ : ' No relay agents are currently online.';
229
+ return {
230
+ success: false,
231
+ status: 404,
232
+ error: `${outcome.error}.${suffix}`,
233
+ };
234
+ }
235
+ }
236
+ return outcome;
237
+ })(),
238
+ timeoutPromise,
239
+ ]);
240
+ }
241
+ catch (err) {
242
+ console.error(`[dashboard] /api/send failed after ${Date.now() - sendStart}ms: ${err.message}`);
243
+ return {
244
+ success: false,
245
+ status: 504,
246
+ error: err.message || 'Send request timed out',
247
+ };
248
+ }
249
+ };
250
+ const ctx = {
251
+ mode,
252
+ dataDir,
253
+ staticDir,
254
+ verbose,
255
+ relayUrl,
256
+ brokerProxyEnabled,
257
+ resolveRelaycastConfig,
258
+ getRelaycastSnapshot,
259
+ getRelaycastChannels,
260
+ sendRelaycastMessage,
261
+ getSpawnedAgents,
262
+ getLocalAgentNames,
263
+ filterPhantomAgents,
264
+ };
265
+ // --- Register routes ---
266
+ registerHealthRoutes(app, ctx);
97
267
  if (mock) {
98
- // ===== MOCK MODE =====
99
- // Register mock API routes for standalone operation
100
- console.log('[dashboard] Running in MOCK mode - no relay daemon required');
268
+ console.log('[dashboard] Running in MOCK mode - no relay broker required');
101
269
  registerMockRoutes(app, verbose);
102
270
  }
103
271
  else {
104
- // ===== PROXY MODE =====
105
- // Proxy all API requests to the relay daemon
106
- console.log(`[dashboard] Running in PROXY mode - forwarding to ${relayUrl}`);
107
- const apiProxyOptions = {
108
- target: relayUrl,
109
- changeOrigin: true,
110
- ws: false, // WebSocket handled separately
111
- logger: verbose ? console : undefined,
112
- on: {
113
- error: (err, _req, res) => {
114
- console.error('[dashboard] API proxy error:', err.message);
115
- if (res && 'writeHead' in res && typeof res.writeHead === 'function') {
116
- res.writeHead(502, { 'Content-Type': 'application/json' });
117
- res.end(JSON.stringify({
118
- error: 'Relay daemon unavailable',
119
- message: err.message,
120
- }));
121
- }
122
- },
123
- },
124
- };
125
- app.use('/api', createProxyMiddleware(apiProxyOptions));
126
- app.use('/auth', createProxyMiddleware(apiProxyOptions));
127
- app.use('/metrics', createProxyMiddleware(apiProxyOptions));
272
+ if (mode === 'proxy' && relayUrl) {
273
+ console.log(`[dashboard] Running in PROXY mode - relaycast + broker proxy (${relayUrl})`);
274
+ }
275
+ else {
276
+ console.log('[dashboard] Running in STANDALONE mode - relaycast only (read-only broker surface)');
277
+ }
278
+ registerAgentRoutes(app, ctx);
279
+ registerDataRoutes(app, ctx);
280
+ registerRelayConfigRoutes(app, ctx);
281
+ registerChannelRoutes(app, ctx);
282
+ registerReactionRoutes(app, ctx);
283
+ registerMetricsRoutes(app, {
284
+ teamDir: path.join(dataDir, 'team'),
285
+ resolveWorkspaceId,
286
+ });
287
+ registerRelaycastHistoryRoutes(app, ctx);
288
+ registerBrokerProxyRoutes(app, ctx);
128
289
  }
129
- // Serve static files
290
+ // --- Static files and SPA fallback ---
291
+ const fallbackHtml = `<!doctype html>
292
+ <html lang="en">
293
+ <head>
294
+ <meta charset="utf-8" />
295
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
296
+ <title>Relay Dashboard</title>
297
+ </head>
298
+ <body>
299
+ <h1>Relay Dashboard</h1>
300
+ <p>Dashboard static build not found.</p>
301
+ </body>
302
+ </html>`;
303
+ app.get('/metrics', (_req, res) => {
304
+ const metricsPath = resolveMetricsPagePath(staticDir);
305
+ sendHtmlFileOrFallback(res, metricsPath, fallbackHtml, 200);
306
+ });
307
+ app.get('/app', (_req, res) => {
308
+ const appHtmlPath = path.join(staticDir, 'app.html');
309
+ sendHtmlFileOrFallback(res, appHtmlPath, fallbackHtml, 200);
310
+ });
311
+ app.get('/app/{*path}', (_req, res) => {
312
+ const appHtmlPath = path.join(staticDir, 'app.html');
313
+ sendHtmlFileOrFallback(res, appHtmlPath, fallbackHtml, 200);
314
+ });
130
315
  app.use(express.static(staticDir, {
131
316
  extensions: ['html'],
132
317
  }));
133
- // SPA fallback - serve appropriate HTML file for unmatched routes
134
- // Express 5 requires named parameter instead of bare *
318
+ app.get('/', (_req, res) => {
319
+ const indexPath = path.join(staticDir, 'index.html');
320
+ sendHtmlFileOrFallback(res, indexPath, fallbackHtml, 200);
321
+ });
135
322
  app.get('/{*path}', (req, res) => {
136
- // Don't serve HTML for API routes or static assets
323
+ // WebSocket endpoints require upgrade - return 426 for regular HTTP requests
324
+ if (req.path === '/ws' || req.path.startsWith('/ws/')) {
325
+ res.status(426).json({ error: 'Upgrade Required', message: 'WebSocket upgrade required' });
326
+ return;
327
+ }
137
328
  if (req.path.startsWith('/api') || req.path.startsWith('/auth') || req.path.includes('.')) {
138
329
  res.status(404).json({ error: 'Not found' });
139
330
  return;
140
331
  }
141
- // For /app/* routes (including /app/channel/*, /app/agent/*, /app/dm/*, /app/settings/*),
142
- // serve the app.html which handles client-side routing
143
332
  if (req.path.startsWith('/app')) {
144
- res.sendFile(path.join(staticDir, 'app.html'));
333
+ const appHtmlPath = path.join(staticDir, 'app.html');
334
+ sendHtmlFileOrFallback(res, appHtmlPath, fallbackHtml, 200);
145
335
  return;
146
336
  }
147
- // For other routes, serve index.html
148
- res.sendFile(path.join(staticDir, 'index.html'));
337
+ const indexPath = path.join(staticDir, 'index.html');
338
+ sendHtmlFileOrFallback(res, indexPath, fallbackHtml, 200);
149
339
  });
150
- // WebSocket server
340
+ // --- WebSocket ---
151
341
  const wss = new WebSocketServer({ noServer: true });
152
- // Handle WebSocket upgrade
153
342
  server.on('upgrade', (request, socket, head) => {
154
343
  const pathname = request.url ? new URL(request.url, `http://${request.headers.host}`).pathname : '';
155
344
  if (pathname === '/ws') {
156
345
  wss.handleUpgrade(request, socket, head, (ws) => {
157
- if (mock) {
158
- // Mock WebSocket - send periodic updates with fixture data
346
+ if (mode === 'mock') {
159
347
  handleMockWebSocket(ws, verbose);
160
348
  }
349
+ else if (mode === 'proxy' && relayUrl) {
350
+ handleHybridWebSocket(ws, getRelaycastSnapshot, relayUrl, verbose);
351
+ }
161
352
  else {
162
- // Proxy WebSocket to relay daemon
163
- handleProxyWebSocket(ws, relayUrl, verbose);
353
+ handleStandaloneWebSocket(ws, getRelaycastSnapshot, verbose);
164
354
  }
165
355
  });
356
+ return;
166
357
  }
167
- else {
168
- socket.destroy();
358
+ if (mode !== 'mock' && (pathname === '/ws/logs' || pathname.startsWith('/ws/logs/'))) {
359
+ wss.handleUpgrade(request, socket, head, (ws) => {
360
+ handleStandaloneLogWebSocket(ws, pathname, dataDir, getLocalAgentNames, verbose);
361
+ });
362
+ return;
169
363
  }
364
+ socket.destroy();
170
365
  });
171
366
  const close = () => {
172
367
  return new Promise((resolve) => {
@@ -180,110 +375,7 @@ export function createServer(options = {}) {
180
375
  return { app, server, wss, close, mode };
181
376
  }
182
377
  /**
183
- * Handle mock WebSocket connections
184
- * Sends periodic updates with fixture data
185
- */
186
- function handleMockWebSocket(ws, verbose) {
187
- if (verbose) {
188
- console.log('[dashboard] Mock WebSocket client connected');
189
- }
190
- // Send initial data
191
- const sendData = () => {
192
- if (ws.readyState === WebSocket.OPEN) {
193
- ws.send(JSON.stringify({
194
- agents: mockAgents,
195
- messages: mockMessages,
196
- sessions: mockSessions,
197
- }));
198
- }
199
- };
200
- // Send initial data immediately
201
- sendData();
202
- // Send updates every 5 seconds
203
- const interval = setInterval(sendData, 5000);
204
- // Handle messages from client
205
- ws.on('message', (data) => {
206
- try {
207
- const msg = JSON.parse(data.toString());
208
- if (verbose) {
209
- console.log('[dashboard] Mock WS received:', msg);
210
- }
211
- // Echo back acknowledgment for certain message types
212
- if (msg.type === 'ping') {
213
- ws.send(JSON.stringify({ type: 'pong' }));
214
- }
215
- else if (msg.type === 'subscribe') {
216
- // Send current data when client subscribes
217
- sendData();
218
- }
219
- }
220
- catch {
221
- // Ignore parse errors
222
- }
223
- });
224
- ws.on('close', () => {
225
- if (verbose) {
226
- console.log('[dashboard] Mock WebSocket client disconnected');
227
- }
228
- clearInterval(interval);
229
- });
230
- ws.on('error', (err) => {
231
- console.error('[dashboard] Mock WebSocket error:', err.message);
232
- clearInterval(interval);
233
- });
234
- }
235
- /**
236
- * Handle proxy WebSocket connections
237
- * Forwards messages bidirectionally to relay daemon
238
- */
239
- function handleProxyWebSocket(ws, relayUrl, verbose) {
240
- const relayUrlObj = new URL(relayUrl);
241
- const wsRelayUrl = `ws://${relayUrlObj.host}`;
242
- // Create connection to relay daemon
243
- const relayWs = new WebSocket(`${wsRelayUrl}/ws`);
244
- relayWs.on('open', () => {
245
- if (verbose) {
246
- console.log('[dashboard] WebSocket connected to relay daemon');
247
- }
248
- });
249
- // Forward messages from client to relay
250
- ws.on('message', (data) => {
251
- if (relayWs.readyState === WebSocket.OPEN) {
252
- relayWs.send(data);
253
- }
254
- });
255
- // Forward messages from relay to client
256
- relayWs.on('message', (data) => {
257
- if (ws.readyState === WebSocket.OPEN) {
258
- ws.send(data);
259
- }
260
- });
261
- // Handle client disconnect
262
- ws.on('close', () => {
263
- if (verbose) {
264
- console.log('[dashboard] Client WebSocket closed');
265
- }
266
- relayWs.close();
267
- });
268
- // Handle relay disconnect
269
- relayWs.on('close', () => {
270
- if (verbose) {
271
- console.log('[dashboard] Relay WebSocket closed');
272
- }
273
- ws.close();
274
- });
275
- // Handle errors
276
- ws.on('error', (err) => {
277
- console.error('[dashboard] Client WebSocket error:', err.message);
278
- relayWs.close();
279
- });
280
- relayWs.on('error', (err) => {
281
- console.error('[dashboard] Relay WebSocket error:', err.message);
282
- ws.close();
283
- });
284
- }
285
- /**
286
- * Try to listen on a port, returns the port if successful or null if in use
378
+ * Try to listen on a port, returns the port if successful or null if in use.
287
379
  */
288
380
  function tryListen(server, port) {
289
381
  return new Promise((resolve) => {
@@ -310,7 +402,7 @@ function tryListen(server, port) {
310
402
  });
311
403
  }
312
404
  /**
313
- * Find an available port starting from the preferred port
405
+ * Find an available port starting from the preferred port.
314
406
  */
315
407
  async function findAvailablePort(server, preferredPort, maxAttempts = 10) {
316
408
  for (let i = 0; i < maxAttempts; i++) {
@@ -319,19 +411,16 @@ async function findAvailablePort(server, preferredPort, maxAttempts = 10) {
319
411
  if (result !== null) {
320
412
  return result;
321
413
  }
322
- // Close and recreate listener for next attempt
323
414
  server.close();
324
415
  }
325
416
  throw new Error(`Could not find available port after ${maxAttempts} attempts starting from ${preferredPort}`);
326
417
  }
327
418
  /**
328
- * Start the dashboard server
329
- * Automatically finds an available port if the preferred port is in use
419
+ * Start the dashboard server.
330
420
  */
331
421
  export async function startServer(options = {}) {
332
422
  const preferredPort = options.port || parseInt(process.env.PORT || '3888', 10);
333
423
  const dashboard = createServer(options);
334
- // Try preferred port first, then search for available port
335
424
  const actualPort = await findAvailablePort(dashboard.server, preferredPort);
336
425
  if (actualPort !== preferredPort) {
337
426
  console.log(`[dashboard] Port ${preferredPort} in use, using port ${actualPort}`);
@@ -340,8 +429,11 @@ export async function startServer(options = {}) {
340
429
  if (dashboard.mode === 'mock') {
341
430
  console.log('[dashboard] Using mock data - ready for standalone testing');
342
431
  }
432
+ else if (dashboard.mode === 'proxy') {
433
+ console.log(`[dashboard] Proxy mode enabled - broker URL ${normalizeRelayUrl(options.relayUrl ?? process.env.RELAY_URL)}`);
434
+ }
343
435
  else {
344
- console.log(`[dashboard] Proxying to relay daemon at ${options.relayUrl || process.env.RELAY_URL || 'http://localhost:3889'}`);
436
+ console.log('[dashboard] Standalone mode enabled - relaycast data only');
345
437
  }
346
438
  return dashboard;
347
439
  }