agent-relay 1.6.0 → 2.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 (1313) hide show
  1. package/.cursor/mcp.json +11 -0
  2. package/.gitleaks.toml +26 -0
  3. package/.mcp.json +11 -0
  4. package/.nvmrc +1 -1
  5. package/.turbo/cache/013415461711937f-meta.json +1 -0
  6. package/.turbo/cache/013415461711937f.tar.zst +0 -0
  7. package/.turbo/cache/0562b1ff326acd6d-meta.json +1 -0
  8. package/.turbo/cache/0562b1ff326acd6d.tar.zst +0 -0
  9. package/.turbo/cache/0b46e0e17254882f-meta.json +1 -0
  10. package/.turbo/cache/0b46e0e17254882f.tar.zst +0 -0
  11. package/.turbo/cache/3799eda981d53d14-meta.json +1 -0
  12. package/.turbo/cache/3799eda981d53d14.tar.zst +0 -0
  13. package/.turbo/cache/47e9d8f404ed064d-meta.json +1 -0
  14. package/.turbo/cache/47e9d8f404ed064d.tar.zst +0 -0
  15. package/.turbo/cache/4cde1d1e5b298099-meta.json +1 -0
  16. package/.turbo/cache/4cde1d1e5b298099.tar.zst +0 -0
  17. package/.turbo/cache/538eea955c0936ef-meta.json +1 -0
  18. package/.turbo/cache/538eea955c0936ef.tar.zst +0 -0
  19. package/.turbo/cache/5dceac7f229f5d5d-meta.json +1 -0
  20. package/.turbo/cache/5dceac7f229f5d5d.tar.zst +0 -0
  21. package/.turbo/cache/64c15b201819367d-meta.json +1 -0
  22. package/.turbo/cache/64c15b201819367d.tar.zst +0 -0
  23. package/.turbo/cache/6d6a21a05efca434-meta.json +1 -0
  24. package/.turbo/cache/6d6a21a05efca434.tar.zst +0 -0
  25. package/.turbo/cache/7562610cb03ec040-meta.json +1 -0
  26. package/.turbo/cache/7562610cb03ec040.tar.zst +0 -0
  27. package/.turbo/cache/81a2456e17af4d7f-meta.json +1 -0
  28. package/.turbo/cache/81a2456e17af4d7f.tar.zst +0 -0
  29. package/.turbo/cache/823fc2a7b12f724c-meta.json +1 -0
  30. package/.turbo/cache/823fc2a7b12f724c.tar.zst +0 -0
  31. package/.turbo/cache/9daad16a073d1f91-meta.json +1 -0
  32. package/.turbo/cache/9daad16a073d1f91.tar.zst +0 -0
  33. package/.turbo/cache/b81ccbab0a606b60-meta.json +1 -0
  34. package/.turbo/cache/b81ccbab0a606b60.tar.zst +0 -0
  35. package/.turbo/cache/cf98487988bfcf91-meta.json +1 -0
  36. package/.turbo/cache/cf98487988bfcf91.tar.zst +0 -0
  37. package/.turbo/cache/cfdf7c57dca71f27-meta.json +1 -0
  38. package/.turbo/cache/cfdf7c57dca71f27.tar.zst +0 -0
  39. package/.turbo/cache/d3063ef43811b1e5-meta.json +1 -0
  40. package/.turbo/cache/d3063ef43811b1e5.tar.zst +0 -0
  41. package/.turbo/cache/de28892eb7678e65-meta.json +1 -0
  42. package/.turbo/cache/de28892eb7678e65.tar.zst +0 -0
  43. package/.turbo/cache/ec29adce408132ba-meta.json +1 -0
  44. package/.turbo/cache/ec29adce408132ba.tar.zst +0 -0
  45. package/.turbo/cache/f70450d8d305f172-meta.json +1 -0
  46. package/.turbo/cache/f70450d8d305f172.tar.zst +0 -0
  47. package/.turbo/cache/fe384d5d6b7a983a-meta.json +1 -0
  48. package/.turbo/cache/fe384d5d6b7a983a.tar.zst +0 -0
  49. package/ARCHITECTURE.md +10 -10
  50. package/CHANGELOG.md +38 -0
  51. package/LICENSE +185 -17
  52. package/README.md +43 -5
  53. package/SESSION_HANDOFF.md +67 -0
  54. package/bin/relay-pty +0 -0
  55. package/bin/relay-pty-darwin-arm64 +0 -0
  56. package/bin/relay-pty-darwin-x64 +0 -0
  57. package/bin/relay-pty-linux-x64 +0 -0
  58. package/deploy/workspace/entrypoint.sh +79 -11
  59. package/deploy/workspace/git-credential-relay +152 -27
  60. package/deploy/workspace/git-credential-relay.test.sh +230 -0
  61. package/dist/dashboard/out/404.html +1 -1
  62. package/dist/dashboard/out/_next/static/chunks/116-a883fca163f3a5bc.js +1 -0
  63. package/dist/dashboard/out/_next/static/chunks/320-900169c942e31422.js +1 -0
  64. package/dist/dashboard/out/_next/static/chunks/631-af51bad94027527a.js +1 -0
  65. package/dist/dashboard/out/_next/static/chunks/766-2aea80818f7eb0d8.js +1 -0
  66. package/dist/dashboard/out/_next/static/chunks/891-5cb1513eeb97a891.js +1 -0
  67. package/dist/dashboard/out/_next/static/chunks/app/app/page-2e525b1dcc790967.js +1 -0
  68. package/dist/dashboard/out/_next/static/chunks/app/page-4e64923d73c35bc9.js +1 -0
  69. package/dist/dashboard/out/_next/static/chunks/app/providers/page-e65a0010da6ea5be.js +1 -0
  70. package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-84161c802b020a1f.js +1 -0
  71. package/dist/dashboard/out/_next/static/css/99c2552394077586.css +1 -0
  72. package/dist/dashboard/out/app/onboarding.html +1 -1
  73. package/dist/dashboard/out/app/onboarding.txt +1 -1
  74. package/dist/dashboard/out/app.html +1 -1
  75. package/dist/dashboard/out/app.txt +2 -2
  76. package/dist/dashboard/out/cloud/link.html +1 -1
  77. package/dist/dashboard/out/cloud/link.txt +2 -2
  78. package/dist/dashboard/out/connect-repos.html +1 -1
  79. package/dist/dashboard/out/connect-repos.txt +1 -1
  80. package/dist/dashboard/out/history.html +1 -1
  81. package/dist/dashboard/out/history.txt +2 -2
  82. package/dist/dashboard/out/index.html +1 -1
  83. package/dist/dashboard/out/index.txt +2 -2
  84. package/dist/dashboard/out/login.html +2 -2
  85. package/dist/dashboard/out/login.txt +1 -1
  86. package/dist/dashboard/out/metrics.html +1 -1
  87. package/dist/dashboard/out/metrics.txt +2 -2
  88. package/dist/dashboard/out/pricing.html +3 -3
  89. package/dist/dashboard/out/pricing.txt +2 -2
  90. package/dist/dashboard/out/providers/setup/claude.html +1 -1
  91. package/dist/dashboard/out/providers/setup/claude.txt +2 -2
  92. package/dist/dashboard/out/providers/setup/codex.html +1 -1
  93. package/dist/dashboard/out/providers/setup/codex.txt +2 -2
  94. package/dist/dashboard/out/providers/setup/cursor.html +1 -0
  95. package/dist/dashboard/out/providers/setup/cursor.txt +8 -0
  96. package/dist/dashboard/out/providers.html +1 -1
  97. package/dist/dashboard/out/providers.txt +2 -2
  98. package/dist/dashboard/out/signup.html +2 -2
  99. package/dist/dashboard/out/signup.txt +1 -1
  100. package/dist/src/bridge/index.d.ts +8 -0
  101. package/dist/src/bridge/index.js +8 -0
  102. package/dist/src/cli/index.js +3089 -0
  103. package/dist/src/cloud/index.d.ts +8 -0
  104. package/dist/src/cloud/index.js +8 -0
  105. package/dist/src/config/relay-config.d.ts +5 -0
  106. package/dist/src/config/relay-config.js +5 -0
  107. package/dist/src/continuity/index.d.ts +5 -0
  108. package/dist/src/continuity/index.js +5 -0
  109. package/dist/src/daemon/index.d.ts +8 -0
  110. package/dist/src/daemon/index.js +9 -0
  111. package/dist/src/dashboard-server/index.d.ts +8 -0
  112. package/dist/src/dashboard-server/index.js +8 -0
  113. package/dist/src/hooks/index.d.ts +10 -0
  114. package/dist/src/hooks/index.js +10 -0
  115. package/dist/src/index.d.ts +13 -0
  116. package/dist/src/index.js +16 -0
  117. package/dist/src/memory/index.d.ts +5 -0
  118. package/dist/src/memory/index.js +5 -0
  119. package/dist/src/policy/index.d.ts +5 -0
  120. package/dist/src/policy/index.js +5 -0
  121. package/dist/src/protocol/index.d.ts +8 -0
  122. package/dist/src/protocol/index.js +8 -0
  123. package/dist/src/resiliency/index.d.ts +5 -0
  124. package/dist/src/resiliency/index.js +5 -0
  125. package/dist/src/shared/cli-auth-config.d.ts +5 -0
  126. package/dist/src/shared/cli-auth-config.js +5 -0
  127. package/dist/src/state/index.d.ts +5 -0
  128. package/dist/src/state/index.js +5 -0
  129. package/dist/src/storage/index.d.ts +8 -0
  130. package/dist/src/storage/index.js +8 -0
  131. package/dist/src/trajectory/index.d.ts +5 -0
  132. package/dist/src/trajectory/index.js +5 -0
  133. package/dist/src/utils/index.d.ts +5 -0
  134. package/dist/src/utils/index.js +5 -0
  135. package/dist/src/wrapper/index.d.ts +8 -0
  136. package/dist/src/wrapper/index.js +11 -0
  137. package/package.json +64 -19
  138. package/packages/api-types/dist/index.d.ts +21 -0
  139. package/packages/api-types/dist/index.js +22 -0
  140. package/packages/api-types/dist/schemas/agent.d.ts +259 -0
  141. package/packages/api-types/dist/schemas/agent.js +102 -0
  142. package/packages/api-types/dist/schemas/api.d.ts +290 -0
  143. package/packages/api-types/dist/schemas/api.js +162 -0
  144. package/packages/api-types/dist/schemas/decision.d.ts +230 -0
  145. package/packages/api-types/dist/schemas/decision.js +104 -0
  146. package/packages/api-types/dist/schemas/fleet.d.ts +615 -0
  147. package/packages/api-types/dist/schemas/fleet.js +71 -0
  148. package/packages/api-types/dist/schemas/history.d.ts +180 -0
  149. package/packages/api-types/dist/schemas/history.js +72 -0
  150. package/packages/api-types/dist/schemas/index.d.ts +14 -0
  151. package/packages/api-types/dist/schemas/index.js +22 -0
  152. package/packages/api-types/dist/schemas/message.d.ts +456 -0
  153. package/packages/api-types/dist/schemas/message.js +88 -0
  154. package/packages/api-types/dist/schemas/session.d.ts +60 -0
  155. package/packages/api-types/dist/schemas/session.js +36 -0
  156. package/packages/api-types/dist/schemas/task.d.ts +111 -0
  157. package/packages/api-types/dist/schemas/task.js +64 -0
  158. package/packages/api-types/package.json +61 -0
  159. package/packages/api-types/scripts/generate-openapi.ts +106 -0
  160. package/packages/bridge/dist/index.d.ts +8 -0
  161. package/packages/bridge/dist/index.js +9 -0
  162. package/packages/bridge/dist/multi-project-client.d.ts +99 -0
  163. package/packages/bridge/dist/multi-project-client.js +389 -0
  164. package/packages/bridge/dist/shadow-cli.js +75 -0
  165. package/packages/bridge/dist/spawner.d.ts +210 -0
  166. package/packages/bridge/dist/spawner.js +1276 -0
  167. package/packages/bridge/dist/types.d.ts +131 -0
  168. package/packages/bridge/dist/utils.d.ts +15 -0
  169. package/packages/bridge/dist/utils.js +60 -0
  170. package/packages/bridge/package.json +40 -0
  171. package/packages/cloud/dist/api/admin.js +225 -0
  172. package/packages/cloud/dist/api/billing.js +564 -0
  173. package/packages/cloud/dist/api/cli-pty-runner.d.ts +53 -0
  174. package/packages/cloud/dist/api/cli-pty-runner.js +193 -0
  175. package/packages/cloud/dist/api/codex-auth-helper.js +327 -0
  176. package/packages/cloud/dist/api/consensus.js +261 -0
  177. package/packages/cloud/dist/api/coordinators.js +750 -0
  178. package/packages/cloud/dist/api/daemons.js +535 -0
  179. package/packages/cloud/dist/api/generic-webhooks.js +129 -0
  180. package/packages/cloud/dist/api/github-app.js +223 -0
  181. package/packages/cloud/dist/api/monitoring.js +578 -0
  182. package/packages/cloud/dist/api/nango-auth.js +674 -0
  183. package/packages/cloud/dist/api/onboarding.d.ts +15 -0
  184. package/packages/cloud/dist/api/onboarding.js +679 -0
  185. package/packages/cloud/dist/api/policy.js +229 -0
  186. package/packages/cloud/dist/api/provider-env.d.ts +14 -0
  187. package/packages/cloud/dist/api/provider-env.js +75 -0
  188. package/packages/cloud/dist/api/providers.js +564 -0
  189. package/packages/cloud/dist/api/repos.js +577 -0
  190. package/packages/cloud/dist/api/sessions.d.ts +11 -0
  191. package/packages/cloud/dist/api/sessions.js +302 -0
  192. package/packages/cloud/dist/api/teams.js +281 -0
  193. package/packages/cloud/dist/api/test-helpers.js +745 -0
  194. package/packages/cloud/dist/api/workspaces.js +1799 -0
  195. package/packages/cloud/dist/billing/plans.js +245 -0
  196. package/packages/cloud/dist/config.d.ts +5 -0
  197. package/packages/cloud/dist/config.js +5 -0
  198. package/packages/cloud/dist/db/drizzle.d.ts +256 -0
  199. package/packages/cloud/dist/db/drizzle.js +1286 -0
  200. package/packages/cloud/dist/db/schema.d.ts +4873 -0
  201. package/packages/cloud/dist/db/schema.js +620 -0
  202. package/packages/cloud/dist/index.d.ts +11 -0
  203. package/packages/cloud/dist/index.js +38 -0
  204. package/packages/cloud/dist/provisioner/index.d.ts +207 -0
  205. package/packages/cloud/dist/provisioner/index.js +2114 -0
  206. package/packages/cloud/dist/server.js +1924 -0
  207. package/packages/cloud/dist/services/index.d.ts +17 -0
  208. package/packages/cloud/dist/services/index.js +25 -0
  209. package/packages/cloud/dist/services/intro-expiration.d.ts +60 -0
  210. package/packages/cloud/dist/services/intro-expiration.js +252 -0
  211. package/packages/cloud/dist/services/nango.d.ts +201 -0
  212. package/packages/cloud/dist/services/nango.js +392 -0
  213. package/packages/cloud/dist/services/persistence.d.ts +131 -0
  214. package/packages/cloud/dist/shims/consensus.d.ts +23 -0
  215. package/packages/cloud/dist/shims/consensus.js +5 -0
  216. package/packages/cloud/package.json +55 -0
  217. package/packages/config/dist/bridge-config.d.ts +52 -0
  218. package/packages/config/dist/bridge-config.js +143 -0
  219. package/packages/config/dist/bridge-utils.d.ts +30 -0
  220. package/packages/config/dist/bridge-utils.js +54 -0
  221. package/packages/config/dist/cli-auth-config.js +391 -0
  222. package/packages/config/dist/cloud-config.d.ts +75 -0
  223. package/packages/config/dist/cloud-config.js +109 -0
  224. package/packages/config/dist/index.d.ts +13 -0
  225. package/packages/config/dist/index.js +13 -0
  226. package/packages/config/dist/project-namespace.d.ts +73 -0
  227. package/packages/config/dist/project-namespace.js +280 -0
  228. package/packages/config/dist/relay-config.d.ts +25 -0
  229. package/packages/config/dist/relay-config.js +25 -0
  230. package/packages/config/dist/relay-file-writer.d.ts +200 -0
  231. package/packages/config/dist/relay-file-writer.js +407 -0
  232. package/packages/config/dist/schemas.d.ts +672 -0
  233. package/packages/config/dist/schemas.js +180 -0
  234. package/packages/config/dist/shadow-config.d.ts +87 -0
  235. package/packages/config/dist/trajectory-config.d.ts +102 -0
  236. package/packages/config/dist/trajectory-config.js +185 -0
  237. package/packages/config/package.json +98 -0
  238. package/packages/continuity/dist/index.d.ts +9 -0
  239. package/packages/continuity/dist/index.js +9 -0
  240. package/packages/continuity/dist/types.d.ts +180 -0
  241. package/packages/continuity/dist/types.js +2 -0
  242. package/packages/continuity/package.json +32 -0
  243. package/packages/daemon/dist/agent-manager.d.ts +134 -0
  244. package/packages/daemon/dist/agent-manager.js +578 -0
  245. package/packages/daemon/dist/agent-registry.js +213 -0
  246. package/packages/daemon/dist/api.d.ts +106 -0
  247. package/packages/daemon/dist/api.js +876 -0
  248. package/packages/daemon/dist/channel-membership-store.d.ts +55 -0
  249. package/packages/daemon/dist/channel-membership-store.js +176 -0
  250. package/packages/daemon/dist/cli-auth.d.ts +89 -0
  251. package/packages/daemon/dist/cli-auth.js +792 -0
  252. package/packages/daemon/dist/cloud-sync.d.ts +150 -0
  253. package/packages/daemon/dist/cloud-sync.js +446 -0
  254. package/packages/daemon/dist/connection.d.ts +130 -0
  255. package/packages/daemon/dist/connection.js +438 -0
  256. package/packages/daemon/dist/consensus-integration.js +371 -0
  257. package/packages/daemon/dist/delivery-tracker.d.ts +34 -0
  258. package/packages/daemon/dist/delivery-tracker.js +104 -0
  259. package/packages/daemon/dist/enhanced-features.d.ts +118 -0
  260. package/packages/daemon/dist/enhanced-features.js +176 -0
  261. package/packages/daemon/dist/index.d.ts +31 -0
  262. package/packages/daemon/dist/index.js +37 -0
  263. package/packages/daemon/dist/migrations/index.d.ts +73 -0
  264. package/packages/daemon/dist/migrations/index.js +241 -0
  265. package/packages/daemon/dist/orchestrator.d.ts +217 -0
  266. package/packages/daemon/dist/orchestrator.js +1143 -0
  267. package/packages/daemon/dist/relay-ledger.d.ts +261 -0
  268. package/packages/daemon/dist/relay-ledger.js +532 -0
  269. package/packages/daemon/dist/relay-watchdog.d.ts +125 -0
  270. package/packages/daemon/dist/relay-watchdog.js +611 -0
  271. package/packages/daemon/dist/repo-manager.js +384 -0
  272. package/packages/daemon/dist/router.d.ts +370 -0
  273. package/packages/daemon/dist/router.js +1437 -0
  274. package/packages/daemon/dist/server.d.ts +174 -0
  275. package/packages/daemon/dist/server.js +1001 -0
  276. package/packages/daemon/dist/spawn-manager.d.ts +78 -0
  277. package/packages/daemon/dist/spawn-manager.js +165 -0
  278. package/packages/daemon/dist/sync-queue.d.ts +116 -0
  279. package/packages/daemon/dist/sync-queue.js +361 -0
  280. package/packages/daemon/dist/types.d.ts +133 -0
  281. package/packages/daemon/dist/workspace-manager.js +314 -0
  282. package/packages/daemon/package.json +52 -0
  283. package/packages/dashboard/README.md +48 -0
  284. package/packages/dashboard/dist/health-worker-manager.d.ts +62 -0
  285. package/packages/dashboard/dist/health-worker-manager.js +144 -0
  286. package/packages/dashboard/dist/health-worker.d.ts +9 -0
  287. package/packages/dashboard/dist/health-worker.js +79 -0
  288. package/packages/dashboard/dist/index.d.ts +20 -0
  289. package/packages/dashboard/dist/index.js +19 -0
  290. package/packages/dashboard/dist/metrics.d.ts +105 -0
  291. package/packages/dashboard/dist/metrics.js +193 -0
  292. package/packages/dashboard/dist/needs-attention.d.ts +24 -0
  293. package/packages/dashboard/dist/needs-attention.js +78 -0
  294. package/packages/dashboard/dist/server.d.ts +25 -0
  295. package/packages/dashboard/dist/server.js +5107 -0
  296. package/packages/dashboard/dist/start.d.ts +6 -0
  297. package/packages/dashboard/dist/start.js +13 -0
  298. package/packages/dashboard/dist/types/threading.d.ts +8 -0
  299. package/packages/dashboard/dist/types/threading.js +2 -0
  300. package/packages/dashboard/dist/user-bridge.d.ts +154 -0
  301. package/packages/dashboard/dist/user-bridge.js +372 -0
  302. package/packages/dashboard/package.json +72 -0
  303. package/packages/dashboard/ui/.next/BUILD_ID +1 -0
  304. package/packages/dashboard/ui/.next/app-build-manifest.json +135 -0
  305. package/packages/dashboard/ui/.next/app-path-routes-manifest.json +1 -0
  306. package/packages/dashboard/ui/.next/build-manifest.json +32 -0
  307. package/packages/dashboard/ui/.next/cache/config.json +7 -0
  308. package/packages/dashboard/ui/.next/cache/eslint/.cache_1asv1h5 +1 -0
  309. package/packages/dashboard/ui/.next/cache/webpack/client-production/0.pack +0 -0
  310. package/packages/dashboard/ui/.next/cache/webpack/client-production/index.pack +0 -0
  311. package/packages/dashboard/ui/.next/cache/webpack/edge-server-production/0.pack +0 -0
  312. package/packages/dashboard/ui/.next/cache/webpack/edge-server-production/index.pack +0 -0
  313. package/packages/dashboard/ui/.next/cache/webpack/server-production/0.pack +0 -0
  314. package/packages/dashboard/ui/.next/cache/webpack/server-production/index.pack +0 -0
  315. package/packages/dashboard/ui/.next/export-detail.json +1 -0
  316. package/packages/dashboard/ui/.next/export-marker.json +1 -0
  317. package/packages/dashboard/ui/.next/images-manifest.json +1 -0
  318. package/packages/dashboard/ui/.next/next-minimal-server.js.nft.json +1 -0
  319. package/packages/dashboard/ui/.next/next-server.js.nft.json +1 -0
  320. package/packages/dashboard/ui/.next/package.json +1 -0
  321. package/packages/dashboard/ui/.next/prerender-manifest.json +1 -0
  322. package/packages/dashboard/ui/.next/react-loadable-manifest.json +1970 -0
  323. package/packages/dashboard/ui/.next/required-server-files.json +1 -0
  324. package/packages/dashboard/ui/.next/routes-manifest.json +1 -0
  325. package/packages/dashboard/ui/.next/server/app/_not-found/page.js +1 -0
  326. package/packages/dashboard/ui/.next/server/app/_not-found/page.js.nft.json +1 -0
  327. package/packages/dashboard/ui/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
  328. package/packages/dashboard/ui/.next/server/app/_not-found.html +1 -0
  329. package/packages/dashboard/ui/.next/server/app/_not-found.meta +6 -0
  330. package/packages/dashboard/ui/.next/server/app/_not-found.rsc +9 -0
  331. package/packages/dashboard/ui/.next/server/app/app/onboarding/page.js +6 -0
  332. package/packages/dashboard/ui/.next/server/app/app/onboarding/page.js.nft.json +1 -0
  333. package/packages/dashboard/ui/.next/server/app/app/onboarding/page_client-reference-manifest.js +1 -0
  334. package/packages/dashboard/ui/.next/server/app/app/onboarding.html +1 -0
  335. package/packages/dashboard/ui/.next/server/app/app/onboarding.meta +5 -0
  336. package/packages/dashboard/ui/.next/server/app/app/onboarding.rsc +7 -0
  337. package/packages/dashboard/ui/.next/server/app/app/page.js +436 -0
  338. package/packages/dashboard/ui/.next/server/app/app/page.js.nft.json +1 -0
  339. package/packages/dashboard/ui/.next/server/app/app/page_client-reference-manifest.js +1 -0
  340. package/packages/dashboard/ui/.next/server/app/app.html +1 -0
  341. package/packages/dashboard/ui/.next/server/app/app.meta +5 -0
  342. package/packages/dashboard/ui/.next/server/app/app.rsc +7 -0
  343. package/packages/dashboard/ui/.next/server/app/apple-icon.png/route.js +12 -0
  344. package/packages/dashboard/ui/.next/server/app/apple-icon.png/route.js.nft.json +1 -0
  345. package/packages/dashboard/ui/.next/server/app/apple-icon.png.body +0 -0
  346. package/packages/dashboard/ui/.next/server/app/apple-icon.png.meta +1 -0
  347. package/packages/dashboard/ui/.next/server/app/cloud/link/page.js +1 -0
  348. package/packages/dashboard/ui/.next/server/app/cloud/link/page.js.nft.json +1 -0
  349. package/packages/dashboard/ui/.next/server/app/cloud/link/page_client-reference-manifest.js +1 -0
  350. package/packages/dashboard/ui/.next/server/app/cloud/link.html +1 -0
  351. package/packages/dashboard/ui/.next/server/app/cloud/link.meta +5 -0
  352. package/packages/dashboard/ui/.next/server/app/cloud/link.rsc +7 -0
  353. package/packages/dashboard/ui/.next/server/app/connect-repos/page.js +6 -0
  354. package/packages/dashboard/ui/.next/server/app/connect-repos/page.js.nft.json +1 -0
  355. package/packages/dashboard/ui/.next/server/app/connect-repos/page_client-reference-manifest.js +1 -0
  356. package/packages/dashboard/ui/.next/server/app/connect-repos.html +1 -0
  357. package/packages/dashboard/ui/.next/server/app/connect-repos.meta +5 -0
  358. package/packages/dashboard/ui/.next/server/app/connect-repos.rsc +7 -0
  359. package/packages/dashboard/ui/.next/server/app/history/page.js +1 -0
  360. package/packages/dashboard/ui/.next/server/app/history/page.js.nft.json +1 -0
  361. package/packages/dashboard/ui/.next/server/app/history/page_client-reference-manifest.js +1 -0
  362. package/packages/dashboard/ui/.next/server/app/history.html +1 -0
  363. package/packages/dashboard/ui/.next/server/app/history.meta +5 -0
  364. package/packages/dashboard/ui/.next/server/app/history.rsc +7 -0
  365. package/packages/dashboard/ui/.next/server/app/index.html +1 -0
  366. package/packages/dashboard/ui/.next/server/app/index.meta +5 -0
  367. package/packages/dashboard/ui/.next/server/app/index.rsc +7 -0
  368. package/packages/dashboard/ui/.next/server/app/login/page.js +6 -0
  369. package/packages/dashboard/ui/.next/server/app/login/page.js.nft.json +1 -0
  370. package/packages/dashboard/ui/.next/server/app/login/page_client-reference-manifest.js +1 -0
  371. package/packages/dashboard/ui/.next/server/app/login.html +5 -0
  372. package/packages/dashboard/ui/.next/server/app/login.meta +5 -0
  373. package/packages/dashboard/ui/.next/server/app/login.rsc +7 -0
  374. package/packages/dashboard/ui/.next/server/app/metrics/page.js +1 -0
  375. package/packages/dashboard/ui/.next/server/app/metrics/page.js.nft.json +1 -0
  376. package/packages/dashboard/ui/.next/server/app/metrics/page_client-reference-manifest.js +1 -0
  377. package/packages/dashboard/ui/.next/server/app/metrics.html +1 -0
  378. package/packages/dashboard/ui/.next/server/app/metrics.meta +5 -0
  379. package/packages/dashboard/ui/.next/server/app/metrics.rsc +7 -0
  380. package/packages/dashboard/ui/.next/server/app/page.js +1 -0
  381. package/packages/dashboard/ui/.next/server/app/page.js.nft.json +1 -0
  382. package/packages/dashboard/ui/.next/server/app/page_client-reference-manifest.js +1 -0
  383. package/packages/dashboard/ui/.next/server/app/pricing/page.js +5 -0
  384. package/packages/dashboard/ui/.next/server/app/pricing/page.js.nft.json +1 -0
  385. package/packages/dashboard/ui/.next/server/app/pricing/page_client-reference-manifest.js +1 -0
  386. package/packages/dashboard/ui/.next/server/app/pricing.html +13 -0
  387. package/packages/dashboard/ui/.next/server/app/pricing.meta +5 -0
  388. package/packages/dashboard/ui/.next/server/app/pricing.rsc +7 -0
  389. package/packages/dashboard/ui/.next/server/app/providers/page.js +2 -0
  390. package/packages/dashboard/ui/.next/server/app/providers/page.js.nft.json +1 -0
  391. package/packages/dashboard/ui/.next/server/app/providers/page_client-reference-manifest.js +1 -0
  392. package/packages/dashboard/ui/.next/server/app/providers/setup/[provider]/page.js +1 -0
  393. package/packages/dashboard/ui/.next/server/app/providers/setup/[provider]/page.js.nft.json +1 -0
  394. package/packages/dashboard/ui/.next/server/app/providers/setup/[provider]/page_client-reference-manifest.js +1 -0
  395. package/packages/dashboard/ui/.next/server/app/providers/setup/claude.html +1 -0
  396. package/packages/dashboard/ui/.next/server/app/providers/setup/claude.meta +5 -0
  397. package/packages/dashboard/ui/.next/server/app/providers/setup/claude.rsc +8 -0
  398. package/packages/dashboard/ui/.next/server/app/providers/setup/codex.html +1 -0
  399. package/packages/dashboard/ui/.next/server/app/providers/setup/codex.meta +5 -0
  400. package/packages/dashboard/ui/.next/server/app/providers/setup/codex.rsc +8 -0
  401. package/packages/dashboard/ui/.next/server/app/providers/setup/cursor.html +1 -0
  402. package/packages/dashboard/ui/.next/server/app/providers/setup/cursor.meta +5 -0
  403. package/packages/dashboard/ui/.next/server/app/providers/setup/cursor.rsc +8 -0
  404. package/packages/dashboard/ui/.next/server/app/providers.html +1 -0
  405. package/packages/dashboard/ui/.next/server/app/providers.meta +5 -0
  406. package/packages/dashboard/ui/.next/server/app/providers.rsc +7 -0
  407. package/packages/dashboard/ui/.next/server/app/signup/page.js +6 -0
  408. package/packages/dashboard/ui/.next/server/app/signup/page.js.nft.json +1 -0
  409. package/packages/dashboard/ui/.next/server/app/signup/page_client-reference-manifest.js +1 -0
  410. package/packages/dashboard/ui/.next/server/app/signup.html +6 -0
  411. package/packages/dashboard/ui/.next/server/app/signup.meta +5 -0
  412. package/packages/dashboard/ui/.next/server/app/signup.rsc +7 -0
  413. package/packages/dashboard/ui/.next/server/app-paths-manifest.json +16 -0
  414. package/packages/dashboard/ui/.next/server/chunks/190.js +1 -0
  415. package/packages/dashboard/ui/.next/server/chunks/205.js +1 -0
  416. package/packages/dashboard/ui/.next/server/chunks/251.js +9 -0
  417. package/packages/dashboard/ui/.next/server/chunks/288.js +1 -0
  418. package/packages/dashboard/ui/.next/server/chunks/434.js +1 -0
  419. package/packages/dashboard/ui/.next/server/chunks/471.js +2 -0
  420. package/packages/dashboard/ui/.next/server/chunks/621.js +1 -0
  421. package/packages/dashboard/ui/.next/server/chunks/680.js +5 -0
  422. package/packages/dashboard/ui/.next/server/chunks/682.js +6 -0
  423. package/packages/dashboard/ui/.next/server/chunks/684.js +1 -0
  424. package/packages/dashboard/ui/.next/server/chunks/71.js +196 -0
  425. package/packages/dashboard/ui/.next/server/chunks/711.js +1 -0
  426. package/packages/dashboard/ui/.next/server/chunks/90.js +17 -0
  427. package/packages/dashboard/ui/.next/server/chunks/948.js +2 -0
  428. package/packages/dashboard/ui/.next/server/chunks/font-manifest.json +1 -0
  429. package/packages/dashboard/ui/.next/server/font-manifest.json +1 -0
  430. package/packages/dashboard/ui/.next/server/functions-config-manifest.json +1 -0
  431. package/packages/dashboard/ui/.next/server/interception-route-rewrite-manifest.js +1 -0
  432. package/packages/dashboard/ui/.next/server/middleware-build-manifest.js +1 -0
  433. package/packages/dashboard/ui/.next/server/middleware-manifest.json +6 -0
  434. package/packages/dashboard/ui/.next/server/middleware-react-loadable-manifest.js +1 -0
  435. package/packages/dashboard/ui/.next/server/next-font-manifest.js +1 -0
  436. package/packages/dashboard/ui/.next/server/next-font-manifest.json +1 -0
  437. package/packages/dashboard/ui/.next/server/pages/404.html +1 -0
  438. package/packages/dashboard/ui/.next/server/pages/500.html +1 -0
  439. package/packages/dashboard/ui/.next/server/pages/_app.js +1 -0
  440. package/packages/dashboard/ui/.next/server/pages/_app.js.nft.json +1 -0
  441. package/packages/dashboard/ui/.next/server/pages/_document.js +1 -0
  442. package/packages/dashboard/ui/.next/server/pages/_document.js.nft.json +1 -0
  443. package/packages/dashboard/ui/.next/server/pages/_error.js +1 -0
  444. package/packages/dashboard/ui/.next/server/pages/_error.js.nft.json +1 -0
  445. package/packages/dashboard/ui/.next/server/pages-manifest.json +1 -0
  446. package/packages/dashboard/ui/.next/server/server-reference-manifest.js +1 -0
  447. package/packages/dashboard/ui/.next/server/server-reference-manifest.json +1 -0
  448. package/packages/dashboard/ui/.next/server/webpack-runtime.js +1 -0
  449. package/packages/dashboard/ui/.next/static/HR7W9z1PPVPFqUboUVZFZ/_buildManifest.js +1 -0
  450. package/packages/dashboard/ui/.next/static/HR7W9z1PPVPFqUboUVZFZ/_ssgManifest.js +1 -0
  451. package/packages/dashboard/ui/.next/static/chunks/116-a883fca163f3a5bc.js +1 -0
  452. package/packages/dashboard/ui/.next/static/chunks/117-c8afed19e821a35d.js +2 -0
  453. package/packages/dashboard/ui/.next/static/chunks/282-980c2eb8fff20123.js +1 -0
  454. package/packages/dashboard/ui/.next/static/chunks/532-bace199897eeab37.js +9 -0
  455. package/packages/dashboard/ui/.next/static/chunks/631-af51bad94027527a.js +1 -0
  456. package/packages/dashboard/ui/.next/static/chunks/648-acb2ff9f77cbfbd3.js +1 -0
  457. package/packages/dashboard/ui/.next/static/chunks/677-30e60cb0b47875b6.js +1 -0
  458. package/packages/dashboard/ui/.next/static/chunks/766-2aea80818f7eb0d8.js +1 -0
  459. package/packages/dashboard/ui/.next/static/chunks/83-4f08122d4e7e79a6.js +1 -0
  460. package/packages/dashboard/ui/.next/static/chunks/847-f1f467060f32afff.js +1 -0
  461. package/packages/dashboard/ui/.next/static/chunks/891-5cb1513eeb97a891.js +1 -0
  462. package/packages/dashboard/ui/.next/static/chunks/app/_not-found/page-60501fddbafba9dc.js +1 -0
  463. package/packages/dashboard/ui/.next/static/chunks/app/app/onboarding/page-9914652442f7e4fb.js +1 -0
  464. package/packages/dashboard/ui/.next/static/chunks/app/app/page-44813aa26ad19681.js +1 -0
  465. package/packages/dashboard/ui/.next/static/chunks/app/cloud/link/page-fa1d5842aa90e8a6.js +1 -0
  466. package/packages/dashboard/ui/.next/static/chunks/app/connect-repos/page-113060009ef35bc2.js +1 -0
  467. package/packages/dashboard/ui/.next/static/chunks/app/history/page-9965d2483011b846.js +1 -0
  468. package/packages/dashboard/ui/.next/static/chunks/app/layout-6b91e33784c20610.js +1 -0
  469. package/packages/dashboard/ui/.next/static/chunks/app/login/page-a0ca6f7ca6a100b8.js +1 -0
  470. package/packages/dashboard/ui/.next/static/chunks/app/metrics/page-1e37ef8e73940b40.js +1 -0
  471. package/packages/dashboard/ui/.next/static/chunks/app/page-7993778218818ace.js +1 -0
  472. package/packages/dashboard/ui/.next/static/chunks/app/pricing/page-9db3ebdfa567a7c9.js +1 -0
  473. package/packages/dashboard/ui/.next/static/chunks/app/providers/page-bcf46064ac4474ce.js +1 -0
  474. package/packages/dashboard/ui/.next/static/chunks/app/providers/setup/[provider]/page-4dbe33f0f7691b7c.js +1 -0
  475. package/packages/dashboard/ui/.next/static/chunks/app/signup/page-1ede2205b58649ca.js +1 -0
  476. package/packages/dashboard/ui/.next/static/chunks/e868780c-48e5f147c90a3a41.js +18 -0
  477. package/packages/dashboard/ui/.next/static/chunks/fd9d1056-609918ca7b6280bb.js +1 -0
  478. package/packages/dashboard/ui/.next/static/chunks/framework-f66176bb897dc684.js +1 -0
  479. package/packages/dashboard/ui/.next/static/chunks/main-5a40a5ae29646e1b.js +1 -0
  480. package/packages/dashboard/ui/.next/static/chunks/main-app-fdbeb09028f57c9f.js +1 -0
  481. package/packages/dashboard/ui/.next/static/chunks/pages/_app-72b849fbd24ac258.js +1 -0
  482. package/packages/dashboard/ui/.next/static/chunks/pages/_error-7ba65e1336b92748.js +1 -0
  483. package/packages/dashboard/ui/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  484. package/packages/dashboard/ui/.next/static/chunks/webpack-1cdd8ed57114d5e1.js +1 -0
  485. package/packages/dashboard/ui/.next/static/css/4034f236dd1a3178.css +1 -0
  486. package/packages/dashboard/ui/.next/static/css/99c2552394077586.css +1 -0
  487. package/packages/dashboard/ui/.next/trace +63 -0
  488. package/packages/dashboard/ui/.next/types/app/app/onboarding/page.ts +79 -0
  489. package/packages/dashboard/ui/.next/types/app/app/page.ts +79 -0
  490. package/packages/dashboard/ui/.next/types/app/cloud/link/page.ts +79 -0
  491. package/packages/dashboard/ui/.next/types/app/connect-repos/page.ts +79 -0
  492. package/packages/dashboard/ui/.next/types/app/history/page.ts +79 -0
  493. package/packages/dashboard/ui/.next/types/app/layout.ts +79 -0
  494. package/packages/dashboard/ui/.next/types/app/login/page.ts +79 -0
  495. package/packages/dashboard/ui/.next/types/app/metrics/page.ts +79 -0
  496. package/packages/dashboard/ui/.next/types/app/page.ts +79 -0
  497. package/packages/dashboard/ui/.next/types/app/pricing/page.ts +79 -0
  498. package/packages/dashboard/ui/.next/types/app/providers/page.ts +79 -0
  499. package/packages/dashboard/ui/.next/types/app/providers/setup/[provider]/page.ts +79 -0
  500. package/packages/dashboard/ui/.next/types/app/signup/page.ts +79 -0
  501. package/packages/dashboard/ui/.next/types/package.json +1 -0
  502. package/packages/dashboard/ui/app/app/onboarding/page.tsx +394 -0
  503. package/packages/dashboard/ui/app/app/page.tsx +667 -0
  504. package/packages/dashboard/ui/app/apple-icon.png +0 -0
  505. package/packages/dashboard/ui/app/cloud/link/page.tsx +464 -0
  506. package/packages/dashboard/ui/app/connect-repos/page.tsx +410 -0
  507. package/packages/dashboard/ui/app/favicon.png +0 -0
  508. package/packages/dashboard/ui/app/globals.css +59 -0
  509. package/packages/dashboard/ui/app/history/page.tsx +658 -0
  510. package/packages/dashboard/ui/app/layout.tsx +25 -0
  511. package/packages/dashboard/ui/app/login/page.tsx +280 -0
  512. package/packages/dashboard/ui/app/metrics/page.tsx +751 -0
  513. package/packages/dashboard/ui/app/page.tsx +59 -0
  514. package/packages/dashboard/ui/app/pricing/page.tsx +7 -0
  515. package/packages/dashboard/ui/app/providers/page.tsx +193 -0
  516. package/packages/dashboard/ui/app/providers/setup/[provider]/ProviderSetupClient.tsx +148 -0
  517. package/packages/dashboard/ui/app/providers/setup/[provider]/constants.ts +35 -0
  518. package/packages/dashboard/ui/app/providers/setup/[provider]/page.tsx +42 -0
  519. package/packages/dashboard/ui/app/signup/page.tsx +343 -0
  520. package/packages/dashboard/ui/index.ts +49 -0
  521. package/packages/dashboard/ui/landing/LandingPage.tsx +713 -0
  522. package/packages/dashboard/ui/landing/PricingPage.tsx +559 -0
  523. package/packages/dashboard/ui/landing/index.ts +6 -0
  524. package/packages/dashboard/ui/landing/styles.css +2850 -0
  525. package/packages/dashboard/ui/lib/agent-merge.ts +35 -0
  526. package/packages/dashboard/ui/lib/api.ts +1155 -0
  527. package/packages/dashboard/ui/lib/cloudApi.ts +876 -0
  528. package/packages/dashboard/ui/lib/colors.ts +218 -0
  529. package/packages/dashboard/ui/lib/hierarchy.ts +242 -0
  530. package/packages/dashboard/ui/lib/stuckDetection.ts +142 -0
  531. package/packages/dashboard/ui/next-env.d.ts +5 -0
  532. package/packages/dashboard/ui/next.config.js +41 -0
  533. package/packages/dashboard/ui/package-lock.json +2882 -0
  534. package/packages/dashboard/ui/package.json +33 -0
  535. package/packages/dashboard/ui/postcss.config.js +5 -0
  536. package/packages/dashboard/ui/react-components/ActivityFeed.tsx +216 -0
  537. package/packages/dashboard/ui/react-components/AddWorkspaceModal.tsx +170 -0
  538. package/packages/dashboard/ui/react-components/AgentCard.tsx +587 -0
  539. package/packages/dashboard/ui/react-components/AgentList.tsx +411 -0
  540. package/packages/dashboard/ui/react-components/AgentProfilePanel.tsx +564 -0
  541. package/packages/dashboard/ui/react-components/App.tsx +3447 -0
  542. package/packages/dashboard/ui/react-components/BillingPanel.tsx +922 -0
  543. package/packages/dashboard/ui/react-components/BillingResult.tsx +447 -0
  544. package/packages/dashboard/ui/react-components/BroadcastComposer.tsx +690 -0
  545. package/packages/dashboard/ui/react-components/ChannelAdminPanel.tsx +773 -0
  546. package/packages/dashboard/ui/react-components/ChannelBrowser.tsx +385 -0
  547. package/packages/dashboard/ui/react-components/ChannelChat.tsx +307 -0
  548. package/packages/dashboard/ui/react-components/ChannelSidebar.tsx +399 -0
  549. package/packages/dashboard/ui/react-components/CloudSessionProvider.tsx +130 -0
  550. package/packages/dashboard/ui/react-components/CommandPalette.tsx +815 -0
  551. package/packages/dashboard/ui/react-components/ConfirmationDialog.tsx +133 -0
  552. package/packages/dashboard/ui/react-components/ConversationHistory.tsx +518 -0
  553. package/packages/dashboard/ui/react-components/CoordinatorPanel.tsx +944 -0
  554. package/packages/dashboard/ui/react-components/DecisionQueue.tsx +717 -0
  555. package/packages/dashboard/ui/react-components/DirectMessageView.tsx +164 -0
  556. package/packages/dashboard/ui/react-components/FileAutocomplete.tsx +368 -0
  557. package/packages/dashboard/ui/react-components/FleetOverview.tsx +278 -0
  558. package/packages/dashboard/ui/react-components/LogViewer.tsx +310 -0
  559. package/packages/dashboard/ui/react-components/LogViewerPanel.tsx +482 -0
  560. package/packages/dashboard/ui/react-components/Logo.tsx +284 -0
  561. package/packages/dashboard/ui/react-components/MentionAutocomplete.tsx +384 -0
  562. package/packages/dashboard/ui/react-components/MessageList.tsx +649 -0
  563. package/packages/dashboard/ui/react-components/MessageSenderName.tsx +91 -0
  564. package/packages/dashboard/ui/react-components/MessageStatusIndicator.tsx +142 -0
  565. package/packages/dashboard/ui/react-components/NewConversationModal.tsx +400 -0
  566. package/packages/dashboard/ui/react-components/NotificationToast.tsx +488 -0
  567. package/packages/dashboard/ui/react-components/OnlineUsersIndicator.tsx +164 -0
  568. package/packages/dashboard/ui/react-components/Pagination.tsx +124 -0
  569. package/packages/dashboard/ui/react-components/PricingPlans.tsx +386 -0
  570. package/packages/dashboard/ui/react-components/ProjectList.tsx +625 -0
  571. package/packages/dashboard/ui/react-components/ProviderAuthFlow.tsx +843 -0
  572. package/packages/dashboard/ui/react-components/ProviderConnectionList.tsx +363 -0
  573. package/packages/dashboard/ui/react-components/ProvisioningProgress.tsx +730 -0
  574. package/packages/dashboard/ui/react-components/RepoAccessPanel.tsx +392 -0
  575. package/packages/dashboard/ui/react-components/ServerCard.tsx +202 -0
  576. package/packages/dashboard/ui/react-components/SessionExpiredModal.tsx +128 -0
  577. package/packages/dashboard/ui/react-components/SpawnModal.tsx +704 -0
  578. package/packages/dashboard/ui/react-components/TaskAssignmentUI.tsx +375 -0
  579. package/packages/dashboard/ui/react-components/TerminalProviderSetup.tsx +608 -0
  580. package/packages/dashboard/ui/react-components/ThemeProvider.tsx +325 -0
  581. package/packages/dashboard/ui/react-components/ThinkingIndicator.tsx +231 -0
  582. package/packages/dashboard/ui/react-components/ThreadList.tsx +198 -0
  583. package/packages/dashboard/ui/react-components/ThreadPanel.tsx +346 -0
  584. package/packages/dashboard/ui/react-components/TrajectoryViewer.tsx +698 -0
  585. package/packages/dashboard/ui/react-components/TypingIndicator.tsx +69 -0
  586. package/packages/dashboard/ui/react-components/UsageBanner.tsx +231 -0
  587. package/packages/dashboard/ui/react-components/UserProfilePanel.tsx +233 -0
  588. package/packages/dashboard/ui/react-components/WorkspaceContext.tsx +107 -0
  589. package/packages/dashboard/ui/react-components/WorkspaceSelector.tsx +234 -0
  590. package/packages/dashboard/ui/react-components/WorkspaceStatusIndicator.tsx +370 -0
  591. package/packages/dashboard/ui/react-components/XTermInteractive.tsx +510 -0
  592. package/packages/dashboard/ui/react-components/XTermLogViewer.tsx +719 -0
  593. package/packages/dashboard/ui/react-components/channels/ChannelDialogs.tsx +1411 -0
  594. package/packages/dashboard/ui/react-components/channels/ChannelHeader.tsx +317 -0
  595. package/packages/dashboard/ui/react-components/channels/ChannelMessageList.tsx +463 -0
  596. package/packages/dashboard/ui/react-components/channels/ChannelViewV1.tsx +146 -0
  597. package/packages/dashboard/ui/react-components/channels/MessageInput.tsx +288 -0
  598. package/packages/dashboard/ui/react-components/channels/SearchInput.tsx +172 -0
  599. package/packages/dashboard/ui/react-components/channels/SearchResults.tsx +336 -0
  600. package/packages/dashboard/ui/react-components/channels/api.ts +697 -0
  601. package/packages/dashboard/ui/react-components/channels/index.ts +76 -0
  602. package/packages/dashboard/ui/react-components/channels/mockApi.ts +344 -0
  603. package/packages/dashboard/ui/react-components/channels/types.ts +566 -0
  604. package/packages/dashboard/ui/react-components/hooks/index.ts +57 -0
  605. package/packages/dashboard/ui/react-components/hooks/useAgentLogs.ts +394 -0
  606. package/packages/dashboard/ui/react-components/hooks/useAgents.ts +127 -0
  607. package/packages/dashboard/ui/react-components/hooks/useBroadcastDedup.ts +86 -0
  608. package/packages/dashboard/ui/react-components/hooks/useChannelAdmin.ts +329 -0
  609. package/packages/dashboard/ui/react-components/hooks/useChannelBrowser.ts +239 -0
  610. package/packages/dashboard/ui/react-components/hooks/useChannelCommands.ts +138 -0
  611. package/packages/dashboard/ui/react-components/hooks/useChannels.ts +328 -0
  612. package/packages/dashboard/ui/react-components/hooks/useDebounce.ts +29 -0
  613. package/packages/dashboard/ui/react-components/hooks/useDirectMessage.ts +141 -0
  614. package/packages/dashboard/ui/react-components/hooks/useMessages.ts +309 -0
  615. package/packages/dashboard/ui/react-components/hooks/useOrchestrator.ts +364 -0
  616. package/packages/dashboard/ui/react-components/hooks/usePinnedAgents.ts +140 -0
  617. package/packages/dashboard/ui/react-components/hooks/usePresence.ts +340 -0
  618. package/packages/dashboard/ui/react-components/hooks/useRecentRepos.ts +130 -0
  619. package/packages/dashboard/ui/react-components/hooks/useSession.ts +209 -0
  620. package/packages/dashboard/ui/react-components/hooks/useTrajectory.ts +265 -0
  621. package/packages/dashboard/ui/react-components/hooks/useWebSocket.ts +169 -0
  622. package/packages/dashboard/ui/react-components/hooks/useWorkspaceMembers.ts +120 -0
  623. package/packages/dashboard/ui/react-components/hooks/useWorkspaceRepos.ts +73 -0
  624. package/packages/dashboard/ui/react-components/hooks/useWorkspaceStatus.ts +237 -0
  625. package/packages/dashboard/ui/react-components/index.ts +81 -0
  626. package/packages/dashboard/ui/react-components/layout/Header.tsx +355 -0
  627. package/packages/dashboard/ui/react-components/layout/RepoContextHeader.tsx +361 -0
  628. package/packages/dashboard/ui/react-components/layout/Sidebar.archive.test.tsx +126 -0
  629. package/packages/dashboard/ui/react-components/layout/Sidebar.test.tsx +691 -0
  630. package/packages/dashboard/ui/react-components/layout/Sidebar.tsx +930 -0
  631. package/packages/dashboard/ui/react-components/layout/index.ts +7 -0
  632. package/packages/dashboard/ui/react-components/settings/BillingSettingsPanel.tsx +564 -0
  633. package/packages/dashboard/ui/react-components/settings/SettingsPage.tsx +544 -0
  634. package/packages/dashboard/ui/react-components/settings/TeamSettingsPanel.tsx +560 -0
  635. package/packages/dashboard/ui/react-components/settings/WorkspaceSettingsPanel.tsx +1329 -0
  636. package/packages/dashboard/ui/react-components/settings/index.ts +11 -0
  637. package/packages/dashboard/ui/react-components/settings/types.ts +53 -0
  638. package/packages/dashboard/ui/react-components/utils/messageFormatting.tsx +370 -0
  639. package/packages/dashboard/ui/tailwind.config.js +148 -0
  640. package/packages/dashboard/ui/types/index.ts +304 -0
  641. package/packages/dashboard/ui/types/threading.ts +7 -0
  642. package/packages/dashboard/ui-dist/404.html +1 -0
  643. package/packages/dashboard/ui-dist/_next/static/HR7W9z1PPVPFqUboUVZFZ/_buildManifest.js +1 -0
  644. package/packages/dashboard/ui-dist/_next/static/HR7W9z1PPVPFqUboUVZFZ/_ssgManifest.js +1 -0
  645. package/packages/dashboard/ui-dist/_next/static/ZCFjHbkF8yDKS2md3lVgb/_buildManifest.js +1 -0
  646. package/packages/dashboard/ui-dist/_next/static/ZCFjHbkF8yDKS2md3lVgb/_ssgManifest.js +1 -0
  647. package/packages/dashboard/ui-dist/_next/static/chunks/116-a883fca163f3a5bc.js +1 -0
  648. package/packages/dashboard/ui-dist/_next/static/chunks/117-c8afed19e821a35d.js +2 -0
  649. package/packages/dashboard/ui-dist/_next/static/chunks/282-980c2eb8fff20123.js +1 -0
  650. package/packages/dashboard/ui-dist/_next/static/chunks/320-900169c942e31422.js +1 -0
  651. package/packages/dashboard/ui-dist/_next/static/chunks/532-bace199897eeab37.js +9 -0
  652. package/packages/dashboard/ui-dist/_next/static/chunks/631-af51bad94027527a.js +1 -0
  653. package/packages/dashboard/ui-dist/_next/static/chunks/648-acb2ff9f77cbfbd3.js +1 -0
  654. package/packages/dashboard/ui-dist/_next/static/chunks/677-30e60cb0b47875b6.js +1 -0
  655. package/packages/dashboard/ui-dist/_next/static/chunks/766-2aea80818f7eb0d8.js +1 -0
  656. package/packages/dashboard/ui-dist/_next/static/chunks/83-4f08122d4e7e79a6.js +1 -0
  657. package/packages/dashboard/ui-dist/_next/static/chunks/847-f1f467060f32afff.js +1 -0
  658. package/packages/dashboard/ui-dist/_next/static/chunks/891-5cb1513eeb97a891.js +1 -0
  659. package/packages/dashboard/ui-dist/_next/static/chunks/app/_not-found/page-60501fddbafba9dc.js +1 -0
  660. package/packages/dashboard/ui-dist/_next/static/chunks/app/app/onboarding/page-9914652442f7e4fb.js +1 -0
  661. package/packages/dashboard/ui-dist/_next/static/chunks/app/app/onboarding/page-f746f29e01fffc43.js +1 -0
  662. package/packages/dashboard/ui-dist/_next/static/chunks/app/app/page-2e525b1dcc790967.js +1 -0
  663. package/packages/dashboard/ui-dist/_next/static/chunks/app/app/page-44813aa26ad19681.js +1 -0
  664. package/packages/dashboard/ui-dist/_next/static/chunks/app/cloud/link/page-5011ae044b90449d.js +1 -0
  665. package/packages/dashboard/ui-dist/_next/static/chunks/app/cloud/link/page-fa1d5842aa90e8a6.js +1 -0
  666. package/packages/dashboard/ui-dist/_next/static/chunks/app/connect-repos/page-03ac6f35a6654ea6.js +1 -0
  667. package/packages/dashboard/ui-dist/_next/static/chunks/app/connect-repos/page-113060009ef35bc2.js +1 -0
  668. package/packages/dashboard/ui-dist/_next/static/chunks/app/history/page-9965d2483011b846.js +1 -0
  669. package/packages/dashboard/ui-dist/_next/static/chunks/app/history/page-b2ce7c96ed0931da.js +1 -0
  670. package/packages/dashboard/ui-dist/_next/static/chunks/app/layout-6b91e33784c20610.js +1 -0
  671. package/packages/dashboard/ui-dist/_next/static/chunks/app/layout-c0d118c0f92d969c.js +1 -0
  672. package/packages/dashboard/ui-dist/_next/static/chunks/app/login/page-6ec54eee75877971.js +1 -0
  673. package/packages/dashboard/ui-dist/_next/static/chunks/app/login/page-a0ca6f7ca6a100b8.js +1 -0
  674. package/packages/dashboard/ui-dist/_next/static/chunks/app/metrics/page-1e37ef8e73940b40.js +1 -0
  675. package/packages/dashboard/ui-dist/_next/static/chunks/app/metrics/page-bf2cb1e5915bc92d.js +1 -0
  676. package/packages/dashboard/ui-dist/_next/static/chunks/app/page-4e64923d73c35bc9.js +1 -0
  677. package/packages/dashboard/ui-dist/_next/static/chunks/app/page-7993778218818ace.js +1 -0
  678. package/packages/dashboard/ui-dist/_next/static/chunks/app/pricing/page-0efa024c28ba4597.js +1 -0
  679. package/packages/dashboard/ui-dist/_next/static/chunks/app/pricing/page-9db3ebdfa567a7c9.js +1 -0
  680. package/packages/dashboard/ui-dist/_next/static/chunks/app/providers/page-bcf46064ac4474ce.js +1 -0
  681. package/packages/dashboard/ui-dist/_next/static/chunks/app/providers/page-e65a0010da6ea5be.js +1 -0
  682. package/packages/dashboard/ui-dist/_next/static/chunks/app/providers/setup/[provider]/page-4dbe33f0f7691b7c.js +1 -0
  683. package/packages/dashboard/ui-dist/_next/static/chunks/app/providers/setup/[provider]/page-84161c802b020a1f.js +1 -0
  684. package/packages/dashboard/ui-dist/_next/static/chunks/app/signup/page-18a4665665f6be11.js +1 -0
  685. package/packages/dashboard/ui-dist/_next/static/chunks/app/signup/page-1ede2205b58649ca.js +1 -0
  686. package/packages/dashboard/ui-dist/_next/static/chunks/e868780c-48e5f147c90a3a41.js +18 -0
  687. package/packages/dashboard/ui-dist/_next/static/chunks/fd9d1056-609918ca7b6280bb.js +1 -0
  688. package/packages/dashboard/ui-dist/_next/static/chunks/framework-f66176bb897dc684.js +1 -0
  689. package/packages/dashboard/ui-dist/_next/static/chunks/main-5a40a5ae29646e1b.js +1 -0
  690. package/packages/dashboard/ui-dist/_next/static/chunks/main-app-6e8e8d3ef4e0192a.js +1 -0
  691. package/packages/dashboard/ui-dist/_next/static/chunks/main-app-fdbeb09028f57c9f.js +1 -0
  692. package/packages/dashboard/ui-dist/_next/static/chunks/pages/_app-72b849fbd24ac258.js +1 -0
  693. package/packages/dashboard/ui-dist/_next/static/chunks/pages/_error-7ba65e1336b92748.js +1 -0
  694. package/packages/dashboard/ui-dist/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  695. package/packages/dashboard/ui-dist/_next/static/chunks/webpack-1cdd8ed57114d5e1.js +1 -0
  696. package/packages/dashboard/ui-dist/_next/static/css/4034f236dd1a3178.css +1 -0
  697. package/packages/dashboard/ui-dist/_next/static/css/99c2552394077586.css +1 -0
  698. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo-128.png +0 -0
  699. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo-256.png +0 -0
  700. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo-32.png +0 -0
  701. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo-512.png +0 -0
  702. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo-64.png +0 -0
  703. package/packages/dashboard/ui-dist/alt-logos/agent-relay-logo.svg +45 -0
  704. package/packages/dashboard/ui-dist/alt-logos/logo.svg +38 -0
  705. package/packages/dashboard/ui-dist/alt-logos/monogram-logo-128.png +0 -0
  706. package/packages/dashboard/ui-dist/alt-logos/monogram-logo-256.png +0 -0
  707. package/packages/dashboard/ui-dist/alt-logos/monogram-logo-32.png +0 -0
  708. package/packages/dashboard/ui-dist/alt-logos/monogram-logo-512.png +0 -0
  709. package/packages/dashboard/ui-dist/alt-logos/monogram-logo-64.png +0 -0
  710. package/packages/dashboard/ui-dist/alt-logos/monogram-logo.svg +38 -0
  711. package/packages/dashboard/ui-dist/app/onboarding.html +1 -0
  712. package/packages/dashboard/ui-dist/app/onboarding.txt +7 -0
  713. package/packages/dashboard/ui-dist/app.html +1 -0
  714. package/packages/dashboard/ui-dist/app.txt +7 -0
  715. package/packages/dashboard/ui-dist/apple-icon.png +0 -0
  716. package/packages/dashboard/ui-dist/cloud/link.html +1 -0
  717. package/packages/dashboard/ui-dist/cloud/link.txt +7 -0
  718. package/packages/dashboard/ui-dist/connect-repos.html +1 -0
  719. package/packages/dashboard/ui-dist/connect-repos.txt +7 -0
  720. package/packages/dashboard/ui-dist/history.html +1 -0
  721. package/packages/dashboard/ui-dist/history.txt +7 -0
  722. package/packages/dashboard/ui-dist/index.html +1 -0
  723. package/packages/dashboard/ui-dist/index.txt +7 -0
  724. package/packages/dashboard/ui-dist/login.html +5 -0
  725. package/packages/dashboard/ui-dist/login.txt +7 -0
  726. package/packages/dashboard/ui-dist/metrics.html +1 -0
  727. package/packages/dashboard/ui-dist/metrics.txt +7 -0
  728. package/packages/dashboard/ui-dist/pricing.html +13 -0
  729. package/packages/dashboard/ui-dist/pricing.txt +7 -0
  730. package/packages/dashboard/ui-dist/providers/setup/claude.html +1 -0
  731. package/packages/dashboard/ui-dist/providers/setup/claude.txt +8 -0
  732. package/packages/dashboard/ui-dist/providers/setup/codex.html +1 -0
  733. package/packages/dashboard/ui-dist/providers/setup/codex.txt +8 -0
  734. package/packages/dashboard/ui-dist/providers/setup/cursor.html +1 -0
  735. package/packages/dashboard/ui-dist/providers/setup/cursor.txt +8 -0
  736. package/packages/dashboard/ui-dist/providers.html +1 -0
  737. package/packages/dashboard/ui-dist/providers.txt +7 -0
  738. package/packages/dashboard/ui-dist/signup.html +6 -0
  739. package/packages/dashboard/ui-dist/signup.txt +7 -0
  740. package/packages/dashboard-server/dist/health-worker-manager.d.ts +62 -0
  741. package/packages/dashboard-server/dist/health-worker-manager.js +144 -0
  742. package/packages/dashboard-server/dist/health-worker.d.ts +9 -0
  743. package/packages/dashboard-server/dist/health-worker.js +79 -0
  744. package/packages/dashboard-server/dist/index.d.ts +18 -0
  745. package/packages/dashboard-server/dist/index.js +17 -0
  746. package/packages/dashboard-server/dist/server.js +5099 -0
  747. package/packages/dashboard-server/dist/start.js +13 -0
  748. package/packages/dashboard-server/dist/types/threading.d.ts +8 -0
  749. package/packages/dashboard-server/dist/types/threading.js +2 -0
  750. package/packages/dashboard-server/dist/user-bridge.d.ts +154 -0
  751. package/packages/dashboard-server/dist/user-bridge.js +372 -0
  752. package/packages/dashboard-server/package.json +49 -0
  753. package/packages/hooks/dist/browser.d.ts +2 -0
  754. package/packages/hooks/dist/browser.js +3 -0
  755. package/packages/hooks/dist/index.d.ts +11 -0
  756. package/packages/hooks/dist/index.js +11 -0
  757. package/packages/hooks/dist/registry.js +476 -0
  758. package/packages/hooks/dist/trajectory-hooks.js +183 -0
  759. package/packages/hooks/dist/types.d.ts +285 -0
  760. package/packages/hooks/dist/types.js +10 -0
  761. package/packages/hooks/package.json +52 -0
  762. package/packages/mcp/LICENSE +190 -0
  763. package/packages/mcp/README.md +214 -0
  764. package/packages/mcp/SPEC.md +1922 -0
  765. package/packages/mcp/STAFFING_PLAN.md +294 -0
  766. package/packages/mcp/dist/bin.d.ts +12 -0
  767. package/packages/mcp/dist/bin.js +127 -0
  768. package/packages/mcp/dist/client.d.ts +68 -0
  769. package/packages/mcp/dist/client.js +115 -0
  770. package/packages/mcp/dist/cloud.d.ts +108 -0
  771. package/packages/mcp/dist/cloud.js +279 -0
  772. package/packages/mcp/dist/errors.d.ts +27 -0
  773. package/packages/mcp/dist/errors.js +48 -0
  774. package/packages/mcp/dist/index.d.ts +10 -0
  775. package/packages/mcp/dist/index.js +16 -0
  776. package/packages/mcp/dist/install-cli.d.ts +35 -0
  777. package/packages/mcp/dist/install-cli.js +157 -0
  778. package/packages/mcp/dist/install.d.ts +101 -0
  779. package/packages/mcp/dist/install.js +398 -0
  780. package/packages/mcp/dist/prompts/index.d.ts +2 -0
  781. package/packages/mcp/dist/prompts/index.js +2 -0
  782. package/packages/mcp/dist/prompts/protocol.d.ts +11 -0
  783. package/packages/mcp/dist/prompts/protocol.js +168 -0
  784. package/packages/mcp/dist/resources/agents.d.ts +11 -0
  785. package/packages/mcp/dist/resources/agents.js +17 -0
  786. package/packages/mcp/dist/resources/inbox.d.ts +11 -0
  787. package/packages/mcp/dist/resources/inbox.js +17 -0
  788. package/packages/mcp/dist/resources/index.d.ts +4 -0
  789. package/packages/mcp/dist/resources/index.js +4 -0
  790. package/packages/mcp/dist/resources/project.d.ts +11 -0
  791. package/packages/mcp/dist/resources/project.js +21 -0
  792. package/packages/mcp/dist/server.d.ts +19 -0
  793. package/packages/mcp/dist/server.js +215 -0
  794. package/packages/mcp/dist/simple.d.ts +173 -0
  795. package/packages/mcp/dist/simple.js +120 -0
  796. package/packages/mcp/dist/tools/index.d.ts +10 -0
  797. package/packages/mcp/dist/tools/index.js +10 -0
  798. package/packages/mcp/dist/tools/relay-health.d.ts +23 -0
  799. package/packages/mcp/dist/tools/relay-health.js +138 -0
  800. package/packages/mcp/dist/tools/relay-inbox.d.ts +26 -0
  801. package/packages/mcp/dist/tools/relay-inbox.js +58 -0
  802. package/packages/mcp/dist/tools/relay-logs.d.ts +20 -0
  803. package/packages/mcp/dist/tools/relay-logs.js +88 -0
  804. package/packages/mcp/dist/tools/relay-metrics.d.ts +20 -0
  805. package/packages/mcp/dist/tools/relay-metrics.js +135 -0
  806. package/packages/mcp/dist/tools/relay-release.d.ts +20 -0
  807. package/packages/mcp/dist/tools/relay-release.js +44 -0
  808. package/packages/mcp/dist/tools/relay-send.d.ts +29 -0
  809. package/packages/mcp/dist/tools/relay-send.js +71 -0
  810. package/packages/mcp/dist/tools/relay-spawn.d.ts +36 -0
  811. package/packages/mcp/dist/tools/relay-spawn.js +73 -0
  812. package/packages/mcp/dist/tools/relay-status.d.ts +11 -0
  813. package/packages/mcp/dist/tools/relay-status.js +43 -0
  814. package/packages/mcp/dist/tools/relay-who.d.ts +20 -0
  815. package/packages/mcp/dist/tools/relay-who.js +47 -0
  816. package/packages/mcp/package.json +69 -0
  817. package/packages/memory/dist/memory-hooks.d.ts +60 -0
  818. package/packages/memory/package.json +35 -0
  819. package/packages/policy/dist/agent-policy.js +665 -0
  820. package/packages/policy/dist/index.d.ts +12 -0
  821. package/packages/policy/dist/index.js +12 -0
  822. package/packages/policy/package.json +35 -0
  823. package/packages/protocol/dist/channels.d.ts +137 -0
  824. package/packages/protocol/dist/channels.js +154 -0
  825. package/packages/protocol/dist/framing.d.ts +80 -0
  826. package/packages/protocol/dist/framing.js +206 -0
  827. package/packages/protocol/dist/index.d.ts +5 -0
  828. package/packages/protocol/dist/index.js +5 -0
  829. package/packages/protocol/dist/relay-pty-schemas.d.ts +258 -0
  830. package/packages/protocol/dist/types.d.ts +341 -0
  831. package/packages/protocol/dist/types.js +8 -0
  832. package/packages/protocol/package.json +56 -0
  833. package/packages/resiliency/dist/memory-monitor.js +599 -0
  834. package/packages/resiliency/dist/provider-context.d.ts +100 -0
  835. package/packages/resiliency/package.json +33 -0
  836. package/packages/sdk/README.md +171 -0
  837. package/packages/sdk/dist/client.d.ts +181 -0
  838. package/packages/sdk/dist/client.js +695 -0
  839. package/packages/sdk/dist/index.d.ts +32 -0
  840. package/packages/sdk/dist/index.js +36 -0
  841. package/packages/sdk/dist/protocol/framing.d.ts +80 -0
  842. package/packages/sdk/dist/protocol/framing.js +206 -0
  843. package/packages/sdk/dist/protocol/index.d.ts +6 -0
  844. package/packages/sdk/dist/protocol/index.js +6 -0
  845. package/packages/sdk/dist/protocol/types.d.ts +341 -0
  846. package/packages/sdk/dist/protocol/types.js +8 -0
  847. package/packages/sdk/dist/standalone.d.ts +87 -0
  848. package/packages/sdk/dist/standalone.js +126 -0
  849. package/packages/sdk/package.json +80 -0
  850. package/packages/spawner/API.md +256 -0
  851. package/packages/spawner/dist/index.d.ts +8 -0
  852. package/packages/spawner/dist/index.js +8 -0
  853. package/packages/spawner/dist/types.d.ts +552 -0
  854. package/packages/spawner/dist/types.js +193 -0
  855. package/packages/spawner/package.json +47 -0
  856. package/packages/state/dist/agent-state.js +120 -0
  857. package/packages/state/dist/index.d.ts +8 -0
  858. package/packages/state/dist/index.js +8 -0
  859. package/packages/state/package.json +32 -0
  860. package/packages/storage/dist/adapter.d.ts +156 -0
  861. package/packages/storage/dist/batched-sqlite-adapter.d.ts +75 -0
  862. package/packages/storage/dist/batched-sqlite-adapter.js +189 -0
  863. package/packages/storage/dist/index.d.ts +5 -0
  864. package/packages/storage/dist/index.js +6 -0
  865. package/packages/storage/dist/sqlite-adapter.d.ts +113 -0
  866. package/packages/storage/dist/sqlite-adapter.js +752 -0
  867. package/packages/storage/package.json +69 -0
  868. package/packages/trajectory/dist/index.d.ts +2 -0
  869. package/packages/trajectory/dist/index.js +2 -0
  870. package/packages/trajectory/dist/integration.js +987 -0
  871. package/packages/trajectory/package.json +35 -0
  872. package/packages/user-directory/dist/index.d.ts +7 -0
  873. package/packages/user-directory/dist/index.js +7 -0
  874. package/packages/user-directory/dist/user-directory.d.ts +121 -0
  875. package/packages/user-directory/dist/user-directory.js +267 -0
  876. package/packages/user-directory/package.json +35 -0
  877. package/packages/utils/dist/command-resolver.js +80 -0
  878. package/packages/utils/dist/error-tracking.d.ts +103 -0
  879. package/packages/utils/dist/error-tracking.js +149 -0
  880. package/packages/utils/dist/index.d.ts +9 -0
  881. package/packages/utils/dist/index.js +9 -0
  882. package/packages/utils/dist/model-mapping.d.ts +28 -0
  883. package/packages/utils/dist/model-mapping.js +55 -0
  884. package/packages/utils/package.json +75 -0
  885. package/packages/wrapper/dist/__fixtures__/claude-outputs.d.ts +49 -0
  886. package/packages/wrapper/dist/__fixtures__/claude-outputs.js +443 -0
  887. package/packages/wrapper/dist/__fixtures__/codex-outputs.d.ts +9 -0
  888. package/packages/wrapper/dist/__fixtures__/codex-outputs.js +94 -0
  889. package/packages/wrapper/dist/__fixtures__/gemini-outputs.d.ts +19 -0
  890. package/packages/wrapper/dist/__fixtures__/gemini-outputs.js +144 -0
  891. package/packages/wrapper/dist/__fixtures__/index.d.ts +68 -0
  892. package/packages/wrapper/dist/__fixtures__/index.js +44 -0
  893. package/packages/wrapper/dist/base-wrapper.d.ts +225 -0
  894. package/packages/wrapper/dist/base-wrapper.js +572 -0
  895. package/packages/wrapper/dist/client.d.ts +254 -0
  896. package/packages/wrapper/dist/client.js +801 -0
  897. package/packages/wrapper/dist/id-generator.d.ts +35 -0
  898. package/packages/wrapper/dist/id-generator.js +60 -0
  899. package/packages/wrapper/dist/idle-detector.d.ts +110 -0
  900. package/packages/wrapper/dist/idle-detector.js +304 -0
  901. package/packages/wrapper/dist/index.d.ts +37 -0
  902. package/packages/wrapper/dist/index.js +47 -0
  903. package/packages/wrapper/dist/parser.d.ts +236 -0
  904. package/packages/wrapper/dist/parser.js +1238 -0
  905. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts +407 -0
  906. package/packages/wrapper/dist/relay-pty-orchestrator.js +1885 -0
  907. package/packages/wrapper/dist/shared.d.ts +201 -0
  908. package/packages/wrapper/dist/shared.js +341 -0
  909. package/packages/wrapper/dist/stuck-detector.d.ts +161 -0
  910. package/packages/wrapper/dist/stuck-detector.js +402 -0
  911. package/packages/wrapper/dist/tmux-wrapper.d.ts +345 -0
  912. package/packages/wrapper/dist/tmux-wrapper.js +1747 -0
  913. package/packages/wrapper/dist/trajectory-integration.d.ts +292 -0
  914. package/packages/wrapper/dist/trajectory-integration.js +979 -0
  915. package/packages/wrapper/dist/wrapper-types.d.ts +41 -0
  916. package/packages/wrapper/dist/wrapper-types.js +7 -0
  917. package/packages/wrapper/package.json +63 -0
  918. package/scripts/setup-stripe-products.ts +312 -0
  919. package/scripts/stress-test-orchestrator-integration.mts +1366 -0
  920. package/scripts/stress-test-orchestrator.mjs +584 -0
  921. package/scripts/stress-test-relay-pty.sh +452 -0
  922. package/scripts/verify-schema.js +1 -1
  923. package/turbo.json +37 -0
  924. package/dist/bridge/config.d.ts +0 -41
  925. package/dist/bridge/config.js +0 -143
  926. package/dist/bridge/index.d.ts +0 -10
  927. package/dist/bridge/index.js +0 -10
  928. package/dist/bridge/multi-project-client.d.ts +0 -99
  929. package/dist/bridge/multi-project-client.js +0 -389
  930. package/dist/bridge/shadow-cli.js +0 -75
  931. package/dist/bridge/shadow-config.d.ts +0 -87
  932. package/dist/bridge/spawner.d.ts +0 -186
  933. package/dist/bridge/spawner.js +0 -920
  934. package/dist/bridge/types.d.ts +0 -129
  935. package/dist/bridge/utils.d.ts +0 -30
  936. package/dist/bridge/utils.js +0 -54
  937. package/dist/cli/index.js +0 -2784
  938. package/dist/cloud/api/admin.js +0 -225
  939. package/dist/cloud/api/billing.js +0 -564
  940. package/dist/cloud/api/cli-pty-runner.d.ts +0 -54
  941. package/dist/cloud/api/cli-pty-runner.js +0 -119
  942. package/dist/cloud/api/codex-auth-helper.js +0 -327
  943. package/dist/cloud/api/consensus.js +0 -259
  944. package/dist/cloud/api/coordinators.js +0 -749
  945. package/dist/cloud/api/daemons.js +0 -535
  946. package/dist/cloud/api/generic-webhooks.js +0 -129
  947. package/dist/cloud/api/github-app.js +0 -223
  948. package/dist/cloud/api/monitoring.js +0 -578
  949. package/dist/cloud/api/nango-auth.js +0 -658
  950. package/dist/cloud/api/onboarding.d.ts +0 -15
  951. package/dist/cloud/api/onboarding.js +0 -666
  952. package/dist/cloud/api/policy.js +0 -229
  953. package/dist/cloud/api/provider-env.d.ts +0 -5
  954. package/dist/cloud/api/provider-env.js +0 -27
  955. package/dist/cloud/api/providers.js +0 -511
  956. package/dist/cloud/api/repos.js +0 -576
  957. package/dist/cloud/api/teams.js +0 -279
  958. package/dist/cloud/api/test-helpers.js +0 -745
  959. package/dist/cloud/api/workspaces.js +0 -1783
  960. package/dist/cloud/billing/plans.js +0 -245
  961. package/dist/cloud/config.d.ts +0 -75
  962. package/dist/cloud/config.js +0 -109
  963. package/dist/cloud/db/drizzle.d.ts +0 -246
  964. package/dist/cloud/db/drizzle.js +0 -1249
  965. package/dist/cloud/db/schema.d.ts +0 -4854
  966. package/dist/cloud/db/schema.js +0 -610
  967. package/dist/cloud/index.d.ts +0 -11
  968. package/dist/cloud/index.js +0 -38
  969. package/dist/cloud/provisioner/index.d.ts +0 -207
  970. package/dist/cloud/provisioner/index.js +0 -2069
  971. package/dist/cloud/server.js +0 -1599
  972. package/dist/cloud/services/index.d.ts +0 -17
  973. package/dist/cloud/services/index.js +0 -25
  974. package/dist/cloud/services/intro-expiration.d.ts +0 -55
  975. package/dist/cloud/services/intro-expiration.js +0 -211
  976. package/dist/cloud/services/nango.d.ts +0 -199
  977. package/dist/cloud/services/nango.js +0 -382
  978. package/dist/cloud/services/persistence.d.ts +0 -131
  979. package/dist/config/relay-config.d.ts +0 -23
  980. package/dist/config/relay-config.js +0 -23
  981. package/dist/continuity/index.d.ts +0 -45
  982. package/dist/continuity/index.js +0 -48
  983. package/dist/continuity/types.d.ts +0 -180
  984. package/dist/continuity/types.js +0 -9
  985. package/dist/daemon/agent-manager.d.ts +0 -134
  986. package/dist/daemon/agent-manager.js +0 -564
  987. package/dist/daemon/agent-registry.js +0 -213
  988. package/dist/daemon/api.d.ts +0 -83
  989. package/dist/daemon/api.js +0 -780
  990. package/dist/daemon/channel-membership-store.d.ts +0 -48
  991. package/dist/daemon/channel-membership-store.js +0 -149
  992. package/dist/daemon/cli-auth.d.ts +0 -82
  993. package/dist/daemon/cli-auth.js +0 -700
  994. package/dist/daemon/cloud-sync.d.ts +0 -150
  995. package/dist/daemon/cloud-sync.js +0 -424
  996. package/dist/daemon/connection.d.ts +0 -130
  997. package/dist/daemon/connection.js +0 -438
  998. package/dist/daemon/consensus-integration.js +0 -371
  999. package/dist/daemon/delivery-tracker.d.ts +0 -34
  1000. package/dist/daemon/delivery-tracker.js +0 -104
  1001. package/dist/daemon/enhanced-features.d.ts +0 -118
  1002. package/dist/daemon/enhanced-features.js +0 -178
  1003. package/dist/daemon/index.d.ts +0 -14
  1004. package/dist/daemon/index.js +0 -17
  1005. package/dist/daemon/orchestrator.d.ts +0 -157
  1006. package/dist/daemon/orchestrator.js +0 -792
  1007. package/dist/daemon/repo-manager.js +0 -384
  1008. package/dist/daemon/router.d.ts +0 -358
  1009. package/dist/daemon/router.js +0 -1333
  1010. package/dist/daemon/server.d.ts +0 -159
  1011. package/dist/daemon/server.js +0 -788
  1012. package/dist/daemon/services/browser-testing.d.ts +0 -88
  1013. package/dist/daemon/services/browser-testing.js +0 -244
  1014. package/dist/daemon/services/container-spawner.d.ts +0 -135
  1015. package/dist/daemon/services/container-spawner.js +0 -313
  1016. package/dist/daemon/sync-queue.d.ts +0 -116
  1017. package/dist/daemon/sync-queue.js +0 -361
  1018. package/dist/daemon/types.d.ts +0 -131
  1019. package/dist/daemon/user-directory.d.ts +0 -111
  1020. package/dist/daemon/user-directory.js +0 -233
  1021. package/dist/daemon/workspace-manager.js +0 -314
  1022. package/dist/dashboard/out/_next/static/chunks/116-eacf84a131b80db9.js +0 -1
  1023. package/dist/dashboard/out/_next/static/chunks/64-f4268c2ac6f4d7d4.js +0 -1
  1024. package/dist/dashboard/out/_next/static/chunks/766-aa7c8c9900ff5f53.js +0 -1
  1025. package/dist/dashboard/out/_next/static/chunks/891-a024fbe4b619cf6f.js +0 -1
  1026. package/dist/dashboard/out/_next/static/chunks/app/app/page-ffad986adfcc8b31.js +0 -1
  1027. package/dist/dashboard/out/_next/static/chunks/app/page-671037943b2f2e43.js +0 -1
  1028. package/dist/dashboard/out/_next/static/chunks/app/providers/page-57cbd738c6a73859.js +0 -1
  1029. package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-5ab0854472b402b0.js +0 -1
  1030. package/dist/dashboard/out/_next/static/css/8f9ed310f454e5a5.css +0 -1
  1031. package/dist/dashboard-server/server.js +0 -4806
  1032. package/dist/dashboard-server/start.js +0 -13
  1033. package/dist/dashboard-server/user-bridge.d.ts +0 -138
  1034. package/dist/dashboard-server/user-bridge.js +0 -348
  1035. package/dist/hooks/index.d.ts +0 -10
  1036. package/dist/hooks/index.js +0 -10
  1037. package/dist/hooks/registry.js +0 -476
  1038. package/dist/hooks/trajectory-hooks.js +0 -183
  1039. package/dist/hooks/types.d.ts +0 -284
  1040. package/dist/hooks/types.js +0 -8
  1041. package/dist/index.d.ts +0 -13
  1042. package/dist/index.js +0 -16
  1043. package/dist/memory/memory-hooks.d.ts +0 -60
  1044. package/dist/policy/agent-policy.js +0 -665
  1045. package/dist/protocol/channels.d.ts +0 -211
  1046. package/dist/protocol/channels.js +0 -154
  1047. package/dist/protocol/framing.d.ts +0 -94
  1048. package/dist/protocol/framing.js +0 -240
  1049. package/dist/protocol/index.d.ts +0 -4
  1050. package/dist/protocol/index.js +0 -4
  1051. package/dist/protocol/relay-pty-schemas.d.ts +0 -209
  1052. package/dist/protocol/types.d.ts +0 -168
  1053. package/dist/protocol/types.js +0 -6
  1054. package/dist/resiliency/memory-monitor.js +0 -593
  1055. package/dist/resiliency/provider-context.d.ts +0 -100
  1056. package/dist/shared/cli-auth-config.js +0 -320
  1057. package/dist/state/agent-state.js +0 -120
  1058. package/dist/storage/adapter.d.ts +0 -154
  1059. package/dist/storage/batched-sqlite-adapter.d.ts +0 -71
  1060. package/dist/storage/batched-sqlite-adapter.js +0 -183
  1061. package/dist/storage/sqlite-adapter.d.ts +0 -107
  1062. package/dist/storage/sqlite-adapter.js +0 -717
  1063. package/dist/trajectory/config.d.ts +0 -102
  1064. package/dist/trajectory/config.js +0 -185
  1065. package/dist/trajectory/index.d.ts +0 -8
  1066. package/dist/trajectory/index.js +0 -8
  1067. package/dist/trajectory/integration.js +0 -987
  1068. package/dist/utils/command-resolver.js +0 -76
  1069. package/dist/utils/index.d.ts +0 -4
  1070. package/dist/utils/index.js +0 -4
  1071. package/dist/utils/project-namespace.d.ts +0 -70
  1072. package/dist/utils/project-namespace.js +0 -216
  1073. package/dist/wrapper/base-wrapper.d.ts +0 -217
  1074. package/dist/wrapper/base-wrapper.js +0 -538
  1075. package/dist/wrapper/client.d.ts +0 -199
  1076. package/dist/wrapper/client.js +0 -677
  1077. package/dist/wrapper/idle-detector.d.ts +0 -102
  1078. package/dist/wrapper/idle-detector.js +0 -279
  1079. package/dist/wrapper/index.d.ts +0 -4
  1080. package/dist/wrapper/index.js +0 -7
  1081. package/dist/wrapper/parser.d.ts +0 -230
  1082. package/dist/wrapper/parser.js +0 -1178
  1083. package/dist/wrapper/pty-wrapper.d.ts +0 -343
  1084. package/dist/wrapper/pty-wrapper.js +0 -1593
  1085. package/dist/wrapper/relay-pty-orchestrator.d.ts +0 -296
  1086. package/dist/wrapper/relay-pty-orchestrator.js +0 -1088
  1087. package/dist/wrapper/shared.d.ts +0 -168
  1088. package/dist/wrapper/shared.js +0 -291
  1089. package/dist/wrapper/stuck-detector.d.ts +0 -101
  1090. package/dist/wrapper/stuck-detector.js +0 -228
  1091. package/dist/wrapper/tmux-wrapper.d.ts +0 -344
  1092. package/dist/wrapper/tmux-wrapper.js +0 -1711
  1093. /package/dist/dashboard/out/_next/static/{BffXAqxm-_rUlj2mAnK26 → ZCFjHbkF8yDKS2md3lVgb}/_buildManifest.js +0 -0
  1094. /package/dist/dashboard/out/_next/static/{BffXAqxm-_rUlj2mAnK26 → ZCFjHbkF8yDKS2md3lVgb}/_ssgManifest.js +0 -0
  1095. /package/dist/dashboard/out/_next/static/chunks/app/cloud/link/{page-cfeb437f08a12ed9.js → page-5011ae044b90449d.js} +0 -0
  1096. /package/dist/dashboard/out/_next/static/chunks/app/history/{page-240f91e8b06ba8ac.js → page-b2ce7c96ed0931da.js} +0 -0
  1097. /package/dist/dashboard/out/_next/static/chunks/app/metrics/{page-82938ab8fcf44694.js → page-bf2cb1e5915bc92d.js} +0 -0
  1098. /package/dist/{cli → src/cli}/index.d.ts +0 -0
  1099. /package/dist/{health-worker-manager.d.ts → src/health-worker-manager.d.ts} +0 -0
  1100. /package/dist/{health-worker-manager.js → src/health-worker-manager.js} +0 -0
  1101. /package/dist/{health-worker.d.ts → src/health-worker.d.ts} +0 -0
  1102. /package/dist/{health-worker.js → src/health-worker.js} +0 -0
  1103. /package/{dist/bridge → packages/bridge/dist}/shadow-cli.d.ts +0 -0
  1104. /package/{dist/bridge → packages/bridge/dist}/types.js +0 -0
  1105. /package/{dist/cloud → packages/cloud/dist}/api/admin.d.ts +0 -0
  1106. /package/{dist/cloud → packages/cloud/dist}/api/auth.d.ts +0 -0
  1107. /package/{dist/cloud → packages/cloud/dist}/api/auth.js +0 -0
  1108. /package/{dist/cloud → packages/cloud/dist}/api/billing.d.ts +0 -0
  1109. /package/{dist/cloud → packages/cloud/dist}/api/codex-auth-helper.d.ts +0 -0
  1110. /package/{dist/cloud → packages/cloud/dist}/api/consensus.d.ts +0 -0
  1111. /package/{dist/cloud → packages/cloud/dist}/api/coordinators.d.ts +0 -0
  1112. /package/{dist/cloud → packages/cloud/dist}/api/daemons.d.ts +0 -0
  1113. /package/{dist/cloud → packages/cloud/dist}/api/generic-webhooks.d.ts +0 -0
  1114. /package/{dist/cloud → packages/cloud/dist}/api/git.d.ts +0 -0
  1115. /package/{dist/cloud → packages/cloud/dist}/api/git.js +0 -0
  1116. /package/{dist/cloud → packages/cloud/dist}/api/github-app.d.ts +0 -0
  1117. /package/{dist/cloud → packages/cloud/dist}/api/middleware/planLimits.d.ts +0 -0
  1118. /package/{dist/cloud → packages/cloud/dist}/api/middleware/planLimits.js +0 -0
  1119. /package/{dist/cloud → packages/cloud/dist}/api/monitoring.d.ts +0 -0
  1120. /package/{dist/cloud → packages/cloud/dist}/api/nango-auth.d.ts +0 -0
  1121. /package/{dist/cloud → packages/cloud/dist}/api/policy.d.ts +0 -0
  1122. /package/{dist/cloud → packages/cloud/dist}/api/providers.d.ts +0 -0
  1123. /package/{dist/cloud → packages/cloud/dist}/api/repos.d.ts +0 -0
  1124. /package/{dist/cloud → packages/cloud/dist}/api/teams.d.ts +0 -0
  1125. /package/{dist/cloud → packages/cloud/dist}/api/test-helpers.d.ts +0 -0
  1126. /package/{dist/cloud → packages/cloud/dist}/api/usage.d.ts +0 -0
  1127. /package/{dist/cloud → packages/cloud/dist}/api/usage.js +0 -0
  1128. /package/{dist/cloud → packages/cloud/dist}/api/webhooks.d.ts +0 -0
  1129. /package/{dist/cloud → packages/cloud/dist}/api/webhooks.js +0 -0
  1130. /package/{dist/cloud → packages/cloud/dist}/api/workspaces.d.ts +0 -0
  1131. /package/{dist/cloud → packages/cloud/dist}/billing/index.d.ts +0 -0
  1132. /package/{dist/cloud → packages/cloud/dist}/billing/index.js +0 -0
  1133. /package/{dist/cloud → packages/cloud/dist}/billing/plans.d.ts +0 -0
  1134. /package/{dist/cloud → packages/cloud/dist}/billing/service.d.ts +0 -0
  1135. /package/{dist/cloud → packages/cloud/dist}/billing/service.js +0 -0
  1136. /package/{dist/cloud → packages/cloud/dist}/billing/types.d.ts +0 -0
  1137. /package/{dist/cloud → packages/cloud/dist}/billing/types.js +0 -0
  1138. /package/{dist/cloud → packages/cloud/dist}/db/bulk-ingest.d.ts +0 -0
  1139. /package/{dist/cloud → packages/cloud/dist}/db/bulk-ingest.js +0 -0
  1140. /package/{dist/cloud → packages/cloud/dist}/db/index.d.ts +0 -0
  1141. /package/{dist/cloud → packages/cloud/dist}/db/index.js +0 -0
  1142. /package/{dist/cloud → packages/cloud/dist}/server.d.ts +0 -0
  1143. /package/{dist/cloud → packages/cloud/dist}/services/auto-scaler.d.ts +0 -0
  1144. /package/{dist/cloud → packages/cloud/dist}/services/auto-scaler.js +0 -0
  1145. /package/{dist/cloud → packages/cloud/dist}/services/capacity-manager.d.ts +0 -0
  1146. /package/{dist/cloud → packages/cloud/dist}/services/capacity-manager.js +0 -0
  1147. /package/{dist/cloud → packages/cloud/dist}/services/ci-agent-spawner.d.ts +0 -0
  1148. /package/{dist/cloud → packages/cloud/dist}/services/ci-agent-spawner.js +0 -0
  1149. /package/{dist/cloud → packages/cloud/dist}/services/cloud-message-bus.d.ts +0 -0
  1150. /package/{dist/cloud → packages/cloud/dist}/services/cloud-message-bus.js +0 -0
  1151. /package/{dist/cloud → packages/cloud/dist}/services/compute-enforcement.d.ts +0 -0
  1152. /package/{dist/cloud → packages/cloud/dist}/services/compute-enforcement.js +0 -0
  1153. /package/{dist/cloud → packages/cloud/dist}/services/coordinator.d.ts +0 -0
  1154. /package/{dist/cloud → packages/cloud/dist}/services/coordinator.js +0 -0
  1155. /package/{dist/cloud → packages/cloud/dist}/services/mention-handler.d.ts +0 -0
  1156. /package/{dist/cloud → packages/cloud/dist}/services/mention-handler.js +0 -0
  1157. /package/{dist/cloud → packages/cloud/dist}/services/persistence.js +0 -0
  1158. /package/{dist/cloud → packages/cloud/dist}/services/planLimits.d.ts +0 -0
  1159. /package/{dist/cloud → packages/cloud/dist}/services/planLimits.js +0 -0
  1160. /package/{dist/cloud → packages/cloud/dist}/services/presence-registry.d.ts +0 -0
  1161. /package/{dist/cloud → packages/cloud/dist}/services/presence-registry.js +0 -0
  1162. /package/{dist/cloud → packages/cloud/dist}/services/scaling-orchestrator.d.ts +0 -0
  1163. /package/{dist/cloud → packages/cloud/dist}/services/scaling-orchestrator.js +0 -0
  1164. /package/{dist/cloud → packages/cloud/dist}/services/scaling-policy.d.ts +0 -0
  1165. /package/{dist/cloud → packages/cloud/dist}/services/scaling-policy.js +0 -0
  1166. /package/{dist/cloud → packages/cloud/dist}/services/ssh-security.d.ts +0 -0
  1167. /package/{dist/cloud → packages/cloud/dist}/services/ssh-security.js +0 -0
  1168. /package/{dist/cloud → packages/cloud/dist}/services/workspace-keepalive.d.ts +0 -0
  1169. /package/{dist/cloud → packages/cloud/dist}/services/workspace-keepalive.js +0 -0
  1170. /package/{dist/cloud → packages/cloud/dist}/webhooks/index.d.ts +0 -0
  1171. /package/{dist/cloud → packages/cloud/dist}/webhooks/index.js +0 -0
  1172. /package/{dist/cloud → packages/cloud/dist}/webhooks/parsers/github.d.ts +0 -0
  1173. /package/{dist/cloud → packages/cloud/dist}/webhooks/parsers/github.js +0 -0
  1174. /package/{dist/cloud → packages/cloud/dist}/webhooks/parsers/index.d.ts +0 -0
  1175. /package/{dist/cloud → packages/cloud/dist}/webhooks/parsers/index.js +0 -0
  1176. /package/{dist/cloud → packages/cloud/dist}/webhooks/parsers/linear.d.ts +0 -0
  1177. /package/{dist/cloud → packages/cloud/dist}/webhooks/parsers/linear.js +0 -0
  1178. /package/{dist/cloud → packages/cloud/dist}/webhooks/parsers/slack.d.ts +0 -0
  1179. /package/{dist/cloud → packages/cloud/dist}/webhooks/parsers/slack.js +0 -0
  1180. /package/{dist/cloud → packages/cloud/dist}/webhooks/responders/github.d.ts +0 -0
  1181. /package/{dist/cloud → packages/cloud/dist}/webhooks/responders/github.js +0 -0
  1182. /package/{dist/cloud → packages/cloud/dist}/webhooks/responders/index.d.ts +0 -0
  1183. /package/{dist/cloud → packages/cloud/dist}/webhooks/responders/index.js +0 -0
  1184. /package/{dist/cloud → packages/cloud/dist}/webhooks/responders/linear.d.ts +0 -0
  1185. /package/{dist/cloud → packages/cloud/dist}/webhooks/responders/linear.js +0 -0
  1186. /package/{dist/cloud → packages/cloud/dist}/webhooks/responders/slack.d.ts +0 -0
  1187. /package/{dist/cloud → packages/cloud/dist}/webhooks/responders/slack.js +0 -0
  1188. /package/{dist/cloud → packages/cloud/dist}/webhooks/router.d.ts +0 -0
  1189. /package/{dist/cloud → packages/cloud/dist}/webhooks/router.js +0 -0
  1190. /package/{dist/cloud → packages/cloud/dist}/webhooks/rules-engine.d.ts +0 -0
  1191. /package/{dist/cloud → packages/cloud/dist}/webhooks/rules-engine.js +0 -0
  1192. /package/{dist/cloud → packages/cloud/dist}/webhooks/types.d.ts +0 -0
  1193. /package/{dist/cloud → packages/cloud/dist}/webhooks/types.js +0 -0
  1194. /package/{dist/utils → packages/config/dist}/agent-config.d.ts +0 -0
  1195. /package/{dist/utils → packages/config/dist}/agent-config.js +0 -0
  1196. /package/{dist/shared → packages/config/dist}/cli-auth-config.d.ts +0 -0
  1197. /package/{dist/bridge → packages/config/dist}/shadow-config.js +0 -0
  1198. /package/{dist/bridge → packages/config/dist}/teams-config.d.ts +0 -0
  1199. /package/{dist/bridge → packages/config/dist}/teams-config.js +0 -0
  1200. /package/{dist/continuity → packages/continuity/dist}/formatter.d.ts +0 -0
  1201. /package/{dist/continuity → packages/continuity/dist}/formatter.js +0 -0
  1202. /package/{dist/continuity → packages/continuity/dist}/handoff-store.d.ts +0 -0
  1203. /package/{dist/continuity → packages/continuity/dist}/handoff-store.js +0 -0
  1204. /package/{dist/continuity → packages/continuity/dist}/ledger-store.d.ts +0 -0
  1205. /package/{dist/continuity → packages/continuity/dist}/ledger-store.js +0 -0
  1206. /package/{dist/continuity → packages/continuity/dist}/manager.d.ts +0 -0
  1207. /package/{dist/continuity → packages/continuity/dist}/manager.js +0 -0
  1208. /package/{dist/continuity → packages/continuity/dist}/parser.d.ts +0 -0
  1209. /package/{dist/continuity → packages/continuity/dist}/parser.js +0 -0
  1210. /package/{dist/daemon → packages/daemon/dist}/agent-registry.d.ts +0 -0
  1211. /package/{dist/daemon → packages/daemon/dist}/agent-signing.d.ts +0 -0
  1212. /package/{dist/daemon → packages/daemon/dist}/agent-signing.js +0 -0
  1213. /package/{dist/daemon → packages/daemon/dist}/auth.d.ts +0 -0
  1214. /package/{dist/daemon → packages/daemon/dist}/auth.js +0 -0
  1215. /package/{dist/daemon → packages/daemon/dist}/consensus-integration.d.ts +0 -0
  1216. /package/{dist/daemon → packages/daemon/dist}/consensus.d.ts +0 -0
  1217. /package/{dist/daemon → packages/daemon/dist}/consensus.js +0 -0
  1218. /package/{dist/daemon → packages/daemon/dist}/rate-limiter.d.ts +0 -0
  1219. /package/{dist/daemon → packages/daemon/dist}/rate-limiter.js +0 -0
  1220. /package/{dist/daemon → packages/daemon/dist}/registry.d.ts +0 -0
  1221. /package/{dist/daemon → packages/daemon/dist}/registry.js +0 -0
  1222. /package/{dist/daemon → packages/daemon/dist}/repo-manager.d.ts +0 -0
  1223. /package/{dist/daemon → packages/daemon/dist}/types.js +0 -0
  1224. /package/{dist/daemon → packages/daemon/dist}/workspace-manager.d.ts +0 -0
  1225. /package/{dist/dashboard-server → packages/dashboard-server/dist}/metrics.d.ts +0 -0
  1226. /package/{dist/dashboard-server → packages/dashboard-server/dist}/metrics.js +0 -0
  1227. /package/{dist/dashboard-server → packages/dashboard-server/dist}/needs-attention.d.ts +0 -0
  1228. /package/{dist/dashboard-server → packages/dashboard-server/dist}/needs-attention.js +0 -0
  1229. /package/{dist/dashboard-server → packages/dashboard-server/dist}/server.d.ts +0 -0
  1230. /package/{dist/dashboard-server → packages/dashboard-server/dist}/start.d.ts +0 -0
  1231. /package/{dist/hooks → packages/hooks/dist}/emitter.d.ts +0 -0
  1232. /package/{dist/hooks → packages/hooks/dist}/emitter.js +0 -0
  1233. /package/{dist/hooks → packages/hooks/dist}/inbox-check/hook.d.ts +0 -0
  1234. /package/{dist/hooks → packages/hooks/dist}/inbox-check/hook.js +0 -0
  1235. /package/{dist/hooks → packages/hooks/dist}/inbox-check/index.d.ts +0 -0
  1236. /package/{dist/hooks → packages/hooks/dist}/inbox-check/index.js +0 -0
  1237. /package/{dist/hooks → packages/hooks/dist}/inbox-check/types.d.ts +0 -0
  1238. /package/{dist/hooks → packages/hooks/dist}/inbox-check/types.js +0 -0
  1239. /package/{dist/hooks → packages/hooks/dist}/inbox-check/utils.d.ts +0 -0
  1240. /package/{dist/hooks → packages/hooks/dist}/inbox-check/utils.js +0 -0
  1241. /package/{dist/hooks → packages/hooks/dist}/registry.d.ts +0 -0
  1242. /package/{dist/hooks → packages/hooks/dist}/trajectory-hooks.d.ts +0 -0
  1243. /package/{dist/memory → packages/memory/dist}/adapters/index.d.ts +0 -0
  1244. /package/{dist/memory → packages/memory/dist}/adapters/index.js +0 -0
  1245. /package/{dist/memory → packages/memory/dist}/adapters/inmemory.d.ts +0 -0
  1246. /package/{dist/memory → packages/memory/dist}/adapters/inmemory.js +0 -0
  1247. /package/{dist/memory → packages/memory/dist}/adapters/supermemory.d.ts +0 -0
  1248. /package/{dist/memory → packages/memory/dist}/adapters/supermemory.js +0 -0
  1249. /package/{dist/memory → packages/memory/dist}/context-compaction.d.ts +0 -0
  1250. /package/{dist/memory → packages/memory/dist}/context-compaction.js +0 -0
  1251. /package/{dist/memory → packages/memory/dist}/factory.d.ts +0 -0
  1252. /package/{dist/memory → packages/memory/dist}/factory.js +0 -0
  1253. /package/{dist/memory → packages/memory/dist}/index.d.ts +0 -0
  1254. /package/{dist/memory → packages/memory/dist}/index.js +0 -0
  1255. /package/{dist/memory → packages/memory/dist}/memory-hooks.js +0 -0
  1256. /package/{dist/memory → packages/memory/dist}/service.d.ts +0 -0
  1257. /package/{dist/memory → packages/memory/dist}/service.js +0 -0
  1258. /package/{dist/memory → packages/memory/dist}/types.d.ts +0 -0
  1259. /package/{dist/memory → packages/memory/dist}/types.js +0 -0
  1260. /package/{dist/policy → packages/policy/dist}/agent-policy.d.ts +0 -0
  1261. /package/{dist/policy → packages/policy/dist}/cloud-policy-fetcher.d.ts +0 -0
  1262. /package/{dist/policy → packages/policy/dist}/cloud-policy-fetcher.js +0 -0
  1263. /package/{dist/utils → packages/protocol/dist}/id-generator.d.ts +0 -0
  1264. /package/{dist/utils → packages/protocol/dist}/id-generator.js +0 -0
  1265. /package/{dist/protocol → packages/protocol/dist}/relay-pty-schemas.js +0 -0
  1266. /package/{dist/resiliency → packages/resiliency/dist}/context-persistence.d.ts +0 -0
  1267. /package/{dist/resiliency → packages/resiliency/dist}/context-persistence.js +0 -0
  1268. /package/{dist/resiliency → packages/resiliency/dist}/crash-insights.d.ts +0 -0
  1269. /package/{dist/resiliency → packages/resiliency/dist}/crash-insights.js +0 -0
  1270. /package/{dist/resiliency → packages/resiliency/dist}/gossip-health.d.ts +0 -0
  1271. /package/{dist/resiliency → packages/resiliency/dist}/gossip-health.js +0 -0
  1272. /package/{dist/resiliency → packages/resiliency/dist}/health-monitor.d.ts +0 -0
  1273. /package/{dist/resiliency → packages/resiliency/dist}/health-monitor.js +0 -0
  1274. /package/{dist/resiliency → packages/resiliency/dist}/index.d.ts +0 -0
  1275. /package/{dist/resiliency → packages/resiliency/dist}/index.js +0 -0
  1276. /package/{dist/resiliency → packages/resiliency/dist}/leader-watchdog.d.ts +0 -0
  1277. /package/{dist/resiliency → packages/resiliency/dist}/leader-watchdog.js +0 -0
  1278. /package/{dist/resiliency → packages/resiliency/dist}/logger.d.ts +0 -0
  1279. /package/{dist/resiliency → packages/resiliency/dist}/logger.js +0 -0
  1280. /package/{dist/resiliency → packages/resiliency/dist}/memory-monitor.d.ts +0 -0
  1281. /package/{dist/resiliency → packages/resiliency/dist}/metrics.d.ts +0 -0
  1282. /package/{dist/resiliency → packages/resiliency/dist}/metrics.js +0 -0
  1283. /package/{dist/resiliency → packages/resiliency/dist}/provider-context.js +0 -0
  1284. /package/{dist/resiliency → packages/resiliency/dist}/stateless-lead.d.ts +0 -0
  1285. /package/{dist/resiliency → packages/resiliency/dist}/stateless-lead.js +0 -0
  1286. /package/{dist/resiliency → packages/resiliency/dist}/supervisor.d.ts +0 -0
  1287. /package/{dist/resiliency → packages/resiliency/dist}/supervisor.js +0 -0
  1288. /package/{dist/state → packages/state/dist}/agent-state.d.ts +0 -0
  1289. /package/{dist/storage → packages/storage/dist}/adapter.js +0 -0
  1290. /package/{dist/storage → packages/storage/dist}/dead-letter-queue.d.ts +0 -0
  1291. /package/{dist/storage → packages/storage/dist}/dead-letter-queue.js +0 -0
  1292. /package/{dist/storage → packages/storage/dist}/dlq-adapter.d.ts +0 -0
  1293. /package/{dist/storage → packages/storage/dist}/dlq-adapter.js +0 -0
  1294. /package/{dist/trajectory → packages/trajectory/dist}/integration.d.ts +0 -0
  1295. /package/{dist/utils → packages/utils/dist}/command-resolver.d.ts +0 -0
  1296. /package/{dist/utils → packages/utils/dist}/git-remote.d.ts +0 -0
  1297. /package/{dist/utils → packages/utils/dist}/git-remote.js +0 -0
  1298. /package/{dist/utils → packages/utils/dist}/logger.d.ts +0 -0
  1299. /package/{dist/utils → packages/utils/dist}/logger.js +0 -0
  1300. /package/{dist/utils → packages/utils/dist}/name-generator.d.ts +0 -0
  1301. /package/{dist/utils → packages/utils/dist}/name-generator.js +0 -0
  1302. /package/{dist/utils → packages/utils/dist}/precompiled-patterns.d.ts +0 -0
  1303. /package/{dist/utils → packages/utils/dist}/precompiled-patterns.js +0 -0
  1304. /package/{dist/utils → packages/utils/dist}/update-checker.d.ts +0 -0
  1305. /package/{dist/utils → packages/utils/dist}/update-checker.js +0 -0
  1306. /package/{dist/wrapper → packages/wrapper/dist}/auth-detection.d.ts +0 -0
  1307. /package/{dist/wrapper → packages/wrapper/dist}/auth-detection.js +0 -0
  1308. /package/{dist/wrapper → packages/wrapper/dist}/inbox.d.ts +0 -0
  1309. /package/{dist/wrapper → packages/wrapper/dist}/inbox.js +0 -0
  1310. /package/{dist/wrapper → packages/wrapper/dist}/prompt-composer.d.ts +0 -0
  1311. /package/{dist/wrapper → packages/wrapper/dist}/prompt-composer.js +0 -0
  1312. /package/{dist/utils → packages/wrapper/dist}/tmux-resolver.d.ts +0 -0
  1313. /package/{dist/utils → packages/wrapper/dist}/tmux-resolver.js +0 -0
package/dist/cli/index.js DELETED
@@ -1,2784 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Agent Relay CLI
4
- *
5
- * Commands:
6
- * relay claude - Start daemon + Dashboard coordinator with Claude
7
- * relay codex - Start daemon + Dasbboard coordinator with Codex
8
- * relay create-agent <cmd> - Wrap agent with real-time messaging
9
- * relay create-agent -n Name cmd - Wrap with specific agent name
10
- * relay up - Start daemon + dashboard
11
- * relay read <id> - Read full message by ID
12
- * relay agents - List connected agents
13
- * relay who - Show currently active agents
14
- */
15
- import { Command } from 'commander';
16
- import { config as dotenvConfig } from 'dotenv';
17
- import { Daemon } from '../daemon/server.js';
18
- import { RelayClient } from '../wrapper/client.js';
19
- import { RelayPtyOrchestrator } from '../wrapper/relay-pty-orchestrator.js';
20
- import { AgentSpawner } from '../bridge/spawner.js';
21
- import { generateAgentName } from '../utils/name-generator.js';
22
- import { getTmuxPath } from '../utils/tmux-resolver.js';
23
- import { readWorkersMetadata, getWorkerLogsDir } from '../bridge/spawner.js';
24
- import { getShadowForAgent } from '../bridge/shadow-config.js';
25
- import { selectShadowCli } from '../bridge/shadow-cli.js';
26
- import { checkForUpdatesInBackground, checkForUpdates } from '../utils/update-checker.js';
27
- import fs from 'node:fs';
28
- import path from 'node:path';
29
- import { promisify } from 'node:util';
30
- import { exec } from 'node:child_process';
31
- import { fileURLToPath } from 'node:url';
32
- dotenvConfig();
33
- const DEFAULT_DASHBOARD_PORT = process.env.AGENT_RELAY_DASHBOARD_PORT || '3888';
34
- // Read version from package.json
35
- const __filename = fileURLToPath(import.meta.url);
36
- const __dirname = path.dirname(__filename);
37
- const packageJsonPath = path.resolve(__dirname, '../../package.json');
38
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
39
- const VERSION = packageJson.version;
40
- const execAsync = promisify(exec);
41
- // Check for updates in background (non-blocking)
42
- // Only show notification for interactive commands, not when wrapping agents or running update
43
- const interactiveCommands = ['up', 'down', 'status', 'agents', 'who', 'version', '--version', '-V', '--help', '-h', 'create-agent', 'claude', 'codex'];
44
- const shouldCheckUpdates = process.argv.length > 2 &&
45
- interactiveCommands.includes(process.argv[2]);
46
- if (shouldCheckUpdates) {
47
- checkForUpdatesInBackground(VERSION);
48
- }
49
- const program = new Command();
50
- function pidFilePathForSocket(socketPath) {
51
- return `${socketPath}.pid`;
52
- }
53
- program
54
- .name('agent-relay')
55
- .description('Agent-to-agent messaging')
56
- .version(VERSION, '-V, --version', 'Output the version number');
57
- // create-agent - Wrap agent with real-time messaging
58
- program
59
- .command('create-agent')
60
- .description('Wrap an agent with real-time messaging')
61
- .option('-n, --name <name>', 'Agent name (auto-generated if not set)')
62
- .option('-d, --debug', 'Enable debug output')
63
- .option('--prefix <pattern>', 'Relay prefix pattern (default: ->relay:)')
64
- .option('--dashboard-port <port>', 'Dashboard port for spawn/release API (auto-detected if not set)')
65
- .option('--shadow <name>', 'Spawn a shadow agent with this name that monitors the primary')
66
- .option('--shadow-role <role>', 'Shadow role: reviewer, auditor, or triggers (comma-separated: SESSION_END,CODE_WRITTEN,REVIEW_REQUEST,EXPLICIT_ASK,ALL_MESSAGES)')
67
- .option('--skip-instructions', 'Skip initial instruction injection (use with --append-system-prompt)')
68
- .argument('<command...>', 'Command to wrap (e.g., claude)')
69
- .action(async (commandParts, options) => {
70
- const { getProjectPaths } = await import('../utils/project-namespace.js');
71
- const { findAgentConfig, isClaudeCli, buildClaudeArgs } = await import('../utils/agent-config.js');
72
- const paths = getProjectPaths();
73
- const [mainCommand, ...commandArgs] = commandParts;
74
- const agentName = options.name ?? generateAgentName();
75
- console.error(`Agent: ${agentName}`);
76
- console.error(`Project: ${paths.projectId}`);
77
- // Auto-detect agent config and inject --model/--agent for Claude CLI
78
- let finalArgs = commandArgs;
79
- if (isClaudeCli(mainCommand)) {
80
- const config = findAgentConfig(agentName, paths.projectRoot);
81
- if (config) {
82
- console.error(`Agent config: ${config.configPath}`);
83
- if (config.model) {
84
- console.error(`Model: ${config.model}`);
85
- }
86
- finalArgs = buildClaudeArgs(agentName, commandArgs, paths.projectRoot);
87
- }
88
- }
89
- // Determine dashboard port for spawn/release API
90
- // Priority: CLI flag > env var > auto-detect default port
91
- let dashboardPort;
92
- if (options.dashboardPort) {
93
- dashboardPort = parseInt(options.dashboardPort, 10);
94
- }
95
- else {
96
- // Try to detect if dashboard is running at common ports
97
- const portsToTry = [
98
- parseInt(DEFAULT_DASHBOARD_PORT, 10),
99
- 3889, 3890, 3891, // Common fallback ports when default is in use
100
- ];
101
- for (const port of portsToTry) {
102
- try {
103
- const response = await fetch(`http://localhost:${port}/api/health`, {
104
- method: 'GET',
105
- signal: AbortSignal.timeout(300), // Quick timeout for detection
106
- });
107
- if (response.ok) {
108
- const health = await response.json();
109
- if (health.status === 'healthy') {
110
- dashboardPort = port;
111
- console.error(`Dashboard detected: http://localhost:${dashboardPort}`);
112
- break;
113
- }
114
- }
115
- }
116
- catch {
117
- // Try next port
118
- }
119
- }
120
- }
121
- // Create spawner as fallback for direct spawn (if dashboard API not available)
122
- const spawner = new AgentSpawner(paths.projectRoot, undefined, dashboardPort);
123
- const wrapper = new RelayPtyOrchestrator({
124
- name: agentName,
125
- command: mainCommand,
126
- args: finalArgs,
127
- socketPath: paths.socketPath,
128
- cwd: paths.projectRoot,
129
- relayPrefix: options.prefix,
130
- skipInstructions: options.skipInstructions,
131
- streamLogs: true,
132
- // Use dashboard API for spawn/release when available (preferred - works from any context)
133
- dashboardPort,
134
- // Wire up spawn/release callbacks as fallback (if no dashboardPort)
135
- onSpawn: async (workerName, workerCli, task) => {
136
- console.error(`[${agentName}] Spawning ${workerName} (${workerCli})...`);
137
- const result = await spawner.spawn({
138
- name: workerName,
139
- cli: workerCli,
140
- task,
141
- // No team by default - agents are flat unless team is specified
142
- });
143
- if (result.success) {
144
- console.error(`[${agentName}] ✓ Spawned ${workerName} [pid: ${result.pid}]`);
145
- }
146
- else {
147
- console.error(`[${agentName}] ✗ Failed to spawn ${workerName}: ${result.error}`);
148
- }
149
- },
150
- onRelease: async (workerName) => {
151
- console.error(`[${agentName}] Releasing ${workerName}...`);
152
- const released = await spawner.release(workerName);
153
- if (released) {
154
- console.error(`[${agentName}] ✓ Released ${workerName}`);
155
- }
156
- else {
157
- console.error(`[${agentName}] ✗ Worker ${workerName} not found`);
158
- }
159
- },
160
- });
161
- process.on('SIGINT', async () => {
162
- await spawner.releaseAll();
163
- await wrapper.stop();
164
- process.exit(0);
165
- });
166
- await wrapper.start();
167
- let shadowName;
168
- let shadowRole;
169
- let speakOn;
170
- let shadowCli;
171
- let shadowPrompt;
172
- const rolePresets = {
173
- reviewer: ['CODE_WRITTEN', 'REVIEW_REQUEST', 'EXPLICIT_ASK'],
174
- auditor: ['SESSION_END', 'EXPLICIT_ASK'],
175
- active: ['ALL_MESSAGES'],
176
- };
177
- if (options.shadow) {
178
- // CLI flags provided
179
- shadowName = options.shadow;
180
- const role = options.shadowRole || 'EXPLICIT_ASK';
181
- shadowRole = role;
182
- if (rolePresets[role.toLowerCase()]) {
183
- speakOn = rolePresets[role.toLowerCase()];
184
- }
185
- else {
186
- speakOn = role.split(',').map((s) => s.trim().toUpperCase());
187
- }
188
- }
189
- else {
190
- // Check config file for shadow configuration
191
- const shadowConfig = getShadowForAgent(paths.projectRoot, agentName);
192
- if (shadowConfig) {
193
- shadowName = shadowConfig.shadowName;
194
- shadowRole = shadowConfig.roleName;
195
- speakOn = shadowConfig.speakOn;
196
- shadowCli = shadowConfig.cli;
197
- shadowPrompt = shadowConfig.prompt;
198
- console.error(`Shadow config: ${shadowName} (from .agent-relay.json)`);
199
- }
200
- }
201
- // Spawn shadow if configured
202
- if (shadowName && speakOn) {
203
- // Decide how to run the shadow (subagent for Claude/OpenCode primaries)
204
- let shadowSelection = null;
205
- try {
206
- shadowSelection = await selectShadowCli(mainCommand, { preferredShadowCli: shadowCli });
207
- console.error(`[shadow] Mode: ${shadowSelection.mode} via ${shadowSelection.command || shadowSelection.cli} (primary: ${mainCommand})`);
208
- }
209
- catch (err) {
210
- console.error(`[shadow] Shadow CLI selection failed: ${err.message}`);
211
- }
212
- // Subagent mode: do not spawn a separate shadow process
213
- if (shadowSelection?.mode === 'subagent') {
214
- console.error(`[shadow] ${shadowName} will run as ${shadowSelection.cli} subagent inside ${agentName}; no separate process spawned`);
215
- return;
216
- }
217
- console.error(`Shadow: ${shadowName} (shadowing ${agentName}, speakOn: ${speakOn.join(',')})`);
218
- // Wait for primary to register before spawning shadow
219
- await new Promise(r => setTimeout(r, 3000));
220
- // Build shadow task prompt
221
- const defaultPrompt = `You are a shadow agent monitoring "${agentName}". You receive copies of their messages. Your role: ${shadowRole || 'observer'}. Stay passive unless your triggers activate.`;
222
- const shadowTask = shadowPrompt || defaultPrompt;
223
- const result = await spawner.spawn({
224
- name: shadowName,
225
- cli: shadowSelection?.command || shadowCli || mainCommand,
226
- task: shadowTask,
227
- shadowOf: agentName,
228
- shadowSpeakOn: speakOn,
229
- });
230
- if (result.success) {
231
- console.error(`Shadow ${shadowName} started [pid: ${result.pid}]`);
232
- }
233
- else {
234
- console.error(`Failed to spawn shadow ${shadowName}: ${result.error}`);
235
- }
236
- }
237
- });
238
- // up - Start daemon + dashboard
239
- program
240
- .command('up')
241
- .description('Start daemon + dashboard')
242
- .option('--no-dashboard', 'Disable web dashboard')
243
- .option('--port <port>', 'Dashboard port', DEFAULT_DASHBOARD_PORT)
244
- .option('--spawn', 'Force spawn all agents from teams.json')
245
- .option('--no-spawn', 'Do not auto-spawn agents (just start daemon)')
246
- .option('--watch', 'Auto-restart daemon on crash (supervisor mode)')
247
- .option('--max-restarts <n>', 'Max restarts in 60s before giving up (default: 5)', '5')
248
- .action(async (options) => {
249
- // If --watch is specified, run in supervisor mode
250
- if (options.watch) {
251
- const { spawn } = await import('node:child_process');
252
- const maxRestarts = parseInt(options.maxRestarts, 10) || 5;
253
- const restartWindow = 60_000; // 60 seconds
254
- const restartTimes = [];
255
- let child = null;
256
- let shuttingDown = false;
257
- const startDaemon = () => {
258
- // Build args without --watch to prevent infinite recursion
259
- const args = ['up'];
260
- if (options.dashboard === false)
261
- args.push('--no-dashboard');
262
- if (options.port)
263
- args.push('--port', options.port);
264
- if (options.spawn === true)
265
- args.push('--spawn');
266
- if (options.spawn === false)
267
- args.push('--no-spawn');
268
- console.log(`[supervisor] Starting daemon...`);
269
- child = spawn(process.execPath, [process.argv[1], ...args], {
270
- stdio: 'inherit',
271
- env: { ...process.env, AGENT_RELAY_SUPERVISED: '1' },
272
- });
273
- child.on('exit', (code, signal) => {
274
- if (shuttingDown) {
275
- process.exit(0);
276
- return;
277
- }
278
- const now = Date.now();
279
- restartTimes.push(now);
280
- // Remove restarts outside the window
281
- while (restartTimes.length > 0 && restartTimes[0] < now - restartWindow) {
282
- restartTimes.shift();
283
- }
284
- if (restartTimes.length >= maxRestarts) {
285
- console.error(`[supervisor] Daemon crashed ${maxRestarts} times in ${restartWindow / 1000}s, giving up`);
286
- process.exit(1);
287
- }
288
- const exitReason = signal ? `signal ${signal}` : `code ${code}`;
289
- console.log(`[supervisor] Daemon exited (${exitReason}), restarting in 2s... (${restartTimes.length}/${maxRestarts} restarts)`);
290
- setTimeout(startDaemon, 2000);
291
- });
292
- };
293
- process.on('SIGINT', () => {
294
- console.log('\n[supervisor] Stopping...');
295
- shuttingDown = true;
296
- if (child)
297
- child.kill('SIGINT');
298
- });
299
- process.on('SIGTERM', () => {
300
- shuttingDown = true;
301
- if (child)
302
- child.kill('SIGTERM');
303
- });
304
- startDaemon();
305
- return;
306
- }
307
- const { ensureProjectDir } = await import('../utils/project-namespace.js');
308
- const { loadTeamsConfig } = await import('../bridge/teams-config.js');
309
- const { AgentSpawner } = await import('../bridge/spawner.js');
310
- const paths = ensureProjectDir();
311
- const socketPath = paths.socketPath;
312
- const dbPath = paths.dbPath;
313
- const pidFilePath = pidFilePathForSocket(socketPath);
314
- console.log(`Project: ${paths.projectRoot}`);
315
- console.log(`Socket: ${socketPath}`);
316
- // Load teams.json if present
317
- const teamsConfig = loadTeamsConfig(paths.projectRoot);
318
- if (teamsConfig) {
319
- console.log(`Team: ${teamsConfig.team} (${teamsConfig.agents.length} agents defined)`);
320
- }
321
- const daemon = new Daemon({
322
- socketPath,
323
- pidFilePath,
324
- storagePath: dbPath,
325
- teamDir: paths.teamDir,
326
- });
327
- // Create spawner for auto-spawn (will be initialized after dashboard starts)
328
- let spawner = null;
329
- // Track if we're already shutting down to prevent double-cleanup
330
- let isShuttingDown = false;
331
- const gracefulShutdown = async (reason) => {
332
- if (isShuttingDown)
333
- return;
334
- isShuttingDown = true;
335
- console.log(`\n[daemon] ${reason}, shutting down...`);
336
- try {
337
- if (spawner)
338
- await spawner.releaseAll();
339
- await daemon.stop();
340
- }
341
- catch (err) {
342
- console.error('[daemon] Error during shutdown:', err);
343
- }
344
- process.exit(1);
345
- };
346
- // Handle uncaught exceptions - log and exit (supervisor will restart)
347
- process.on('uncaughtException', (err) => {
348
- console.error('[daemon] Uncaught exception:', err);
349
- gracefulShutdown('Uncaught exception');
350
- });
351
- // Handle unhandled promise rejections
352
- process.on('unhandledRejection', (reason, promise) => {
353
- console.error('[daemon] Unhandled rejection at:', promise, 'reason:', reason);
354
- // Don't exit on unhandled rejections - just log them
355
- // Most are recoverable (e.g., failed message delivery)
356
- });
357
- process.on('SIGINT', async () => {
358
- console.log('\nStopping...');
359
- if (spawner) {
360
- await spawner.releaseAll();
361
- }
362
- await daemon.stop();
363
- process.exit(0);
364
- });
365
- process.on('SIGTERM', async () => {
366
- if (spawner) {
367
- await spawner.releaseAll();
368
- }
369
- await daemon.stop();
370
- process.exit(0);
371
- });
372
- try {
373
- await daemon.start();
374
- console.log('Daemon started.');
375
- let dashboardPort;
376
- // Dashboard starts by default (use --no-dashboard to disable)
377
- if (options.dashboard !== false) {
378
- const port = parseInt(options.port, 10);
379
- const { startDashboard } = await import('../dashboard-server/server.js');
380
- dashboardPort = await startDashboard({
381
- port,
382
- dataDir: paths.dataDir,
383
- teamDir: paths.teamDir,
384
- dbPath,
385
- enableSpawner: true,
386
- projectRoot: paths.projectRoot,
387
- // Pass spawn tracking callbacks so messages can be queued before HELLO completes
388
- onMarkSpawning: (name) => daemon.markSpawning(name),
389
- onClearSpawning: (name) => daemon.clearSpawning(name),
390
- });
391
- console.log(`Dashboard: http://localhost:${dashboardPort}`);
392
- // Hook daemon log output to dashboard WebSocket
393
- daemon.onLogOutput = (agentName, data, _timestamp) => {
394
- const broadcast = global.__broadcastLogOutput;
395
- if (broadcast) {
396
- broadcast(agentName, data);
397
- }
398
- };
399
- }
400
- // Determine if we should auto-spawn agents
401
- // --spawn: force spawn
402
- // --no-spawn: never spawn
403
- // Neither: check teamsConfig.autoSpawn
404
- const shouldSpawn = options.spawn === true
405
- ? true
406
- : options.spawn === false
407
- ? false
408
- : teamsConfig?.autoSpawn ?? false;
409
- if (shouldSpawn && teamsConfig && teamsConfig.agents.length > 0) {
410
- console.log('');
411
- console.log('Auto-spawning agents from teams.json...');
412
- spawner = new AgentSpawner(paths.projectRoot, undefined, dashboardPort);
413
- for (const agent of teamsConfig.agents) {
414
- console.log(` Spawning ${agent.name} (${agent.cli})...`);
415
- const result = await spawner.spawn({
416
- name: agent.name,
417
- cli: agent.cli,
418
- task: agent.task ?? '',
419
- team: teamsConfig.team,
420
- });
421
- if (result.success) {
422
- console.log(` ✓ ${agent.name} started [pid: ${result.pid}]`);
423
- }
424
- else {
425
- console.error(` ✗ ${agent.name} failed: ${result.error}`);
426
- }
427
- }
428
- console.log('');
429
- }
430
- else if (options.spawn === true && !teamsConfig) {
431
- console.warn('Warning: --spawn specified but no teams.json found');
432
- }
433
- console.log('Press Ctrl+C to stop.');
434
- await new Promise(() => { });
435
- }
436
- catch (err) {
437
- console.error('Failed:', err);
438
- process.exit(1);
439
- }
440
- });
441
- // down - Stop daemon
442
- program
443
- .command('down')
444
- .description('Stop daemon')
445
- .action(async () => {
446
- const { getProjectPaths } = await import('../utils/project-namespace.js');
447
- const paths = getProjectPaths();
448
- const pidPath = pidFilePathForSocket(paths.socketPath);
449
- if (!fs.existsSync(pidPath)) {
450
- console.log('Not running');
451
- return;
452
- }
453
- const pid = Number(fs.readFileSync(pidPath, 'utf-8').trim());
454
- try {
455
- process.kill(pid, 'SIGTERM');
456
- console.log('Stopped');
457
- }
458
- catch {
459
- fs.unlinkSync(pidPath);
460
- console.log('Cleaned up stale pid');
461
- }
462
- });
463
- // System prompt for Dashboard agent - plain text to avoid shell escaping issues
464
- const MEGA_SYSTEM_PROMPT = [
465
- 'You are Dashboard, a lead coordinator in agent-relay.',
466
- 'Your PRIMARY job is to delegate - you should almost NEVER do implementation work yourself.',
467
- 'ALWAYS SPAWN AGENTS: For any non-trivial task, spawn specialized workers.',
468
- ].join(' ');
469
- // Helper function for starting Dashboard coordinator with a specific provider
470
- async function startDashboardCoordinator(operator) {
471
- const { spawn } = await import('node:child_process');
472
- const { getProjectPaths } = await import('../utils/project-namespace.js');
473
- const paths = getProjectPaths();
474
- console.log(`Starting Dashboard with ${operator}...`);
475
- console.log(`Project: ${paths.projectRoot}`);
476
- // Step 1: Check if daemon is already running, start if needed
477
- console.log('\n[1/3] Checking daemon...');
478
- // Check if socket exists (daemon running)
479
- const socketExists = fs.existsSync(paths.socketPath);
480
- // Ports to try for dashboard detection
481
- const portsToTry = [
482
- parseInt(DEFAULT_DASHBOARD_PORT, 10),
483
- 3889, 3890, 3891,
484
- ];
485
- // Check if dashboard is responding for THIS project
486
- let dashboardReady = false;
487
- let detectedPort;
488
- // Helper to check health at a port
489
- const checkPort = async (port) => {
490
- try {
491
- const response = await fetch(`http://localhost:${port}/api/health`, {
492
- signal: AbortSignal.timeout(500),
493
- });
494
- if (response.ok) {
495
- const health = await response.json();
496
- return health.status === 'healthy';
497
- }
498
- }
499
- catch {
500
- // Port not responding
501
- }
502
- return false;
503
- };
504
- if (socketExists) {
505
- for (const port of portsToTry) {
506
- if (await checkPort(port)) {
507
- dashboardReady = true;
508
- detectedPort = port;
509
- break;
510
- }
511
- }
512
- }
513
- if (dashboardReady && detectedPort) {
514
- console.log(`Daemon already running at port ${detectedPort}, reusing...`);
515
- }
516
- else {
517
- console.log('Starting daemon...');
518
- const daemonProc = spawn(process.execPath, [process.argv[1], 'up'], {
519
- stdio: 'ignore',
520
- detached: true,
521
- });
522
- daemonProc.unref();
523
- // Wait for dashboard to be ready (up to 10 seconds)
524
- const maxWait = 10000;
525
- const startTime = Date.now();
526
- while (Date.now() - startTime < maxWait) {
527
- await new Promise((resolve) => setTimeout(resolve, 500));
528
- for (const port of portsToTry) {
529
- if (await checkPort(port)) {
530
- dashboardReady = true;
531
- detectedPort = port;
532
- break;
533
- }
534
- }
535
- if (dashboardReady)
536
- break;
537
- }
538
- if (!dashboardReady) {
539
- console.error('Warning: Dashboard may not be fully ready. Spawn might not work.');
540
- detectedPort = parseInt(DEFAULT_DASHBOARD_PORT, 10); // Fallback
541
- }
542
- }
543
- const dashboardPort = detectedPort || parseInt(DEFAULT_DASHBOARD_PORT, 10);
544
- // Step 2: Install prpm snippet via npx
545
- console.log('[2/3] Installing agent-relay snippet...');
546
- const prpmArgs = operator.toLowerCase() === 'claude'
547
- ? ['prpm', 'install', '@agent-relay/agent-relay-snippet', '--location', 'CLAUDE.md']
548
- : ['prpm', 'install', '@agent-relay/agent-relay-snippet'];
549
- try {
550
- await new Promise((resolve, reject) => {
551
- const prpmProc = spawn('npx', prpmArgs, {
552
- stdio: 'inherit',
553
- });
554
- prpmProc.on('close', (code) => {
555
- if (code === 0)
556
- resolve();
557
- else
558
- reject(new Error(`npx prpm exited with code ${code}`));
559
- });
560
- prpmProc.on('error', reject);
561
- });
562
- }
563
- catch (err) {
564
- console.warn(`Warning: prpm install failed: ${err.message}`);
565
- console.warn('Continuing without snippet installation...');
566
- }
567
- // Step 3: Start Dashboard agent with system prompt
568
- console.log(`[3/3] Starting Dashboard agent with ${operator}...`);
569
- console.log('');
570
- const op = operator.toLowerCase();
571
- // Build CLI-specific arguments for system prompt
572
- // These args go AFTER the operator command, passed through to the CLI
573
- let cliArgs = [];
574
- if (op === 'claude') {
575
- // Claude: --append-system-prompt <content> (takes content directly, not file)
576
- cliArgs = ['--append-system-prompt', MEGA_SYSTEM_PROMPT];
577
- }
578
- else if (op === 'codex') {
579
- // Codex: --config developer_instructions="<content>"
580
- cliArgs = ['--config', `developer_instructions=${MEGA_SYSTEM_PROMPT}`];
581
- }
582
- // Use '--' to separate agent-relay options from the command + its args
583
- // Format: agent-relay create-agent -n Dashboard --skip-instructions --dashboard-port <port> -- claude --append-system-prompt "..."
584
- const agentProc = spawn(process.execPath, [process.argv[1], 'create-agent', '-n', 'Dashboard', '--skip-instructions', '--dashboard-port', String(dashboardPort), '--', operator, ...cliArgs], { stdio: 'inherit' });
585
- // Forward signals to agent process
586
- process.on('SIGINT', () => {
587
- agentProc.kill('SIGINT');
588
- });
589
- process.on('SIGTERM', () => {
590
- agentProc.kill('SIGTERM');
591
- });
592
- agentProc.on('close', (code) => {
593
- process.exit(code ?? 0);
594
- });
595
- }
596
- // claude - Start daemon and spawn Dashboard coordinator with Claude
597
- program
598
- .command('claude')
599
- .description('Start daemon and Dashboard coordinator with Claude')
600
- .action(async () => {
601
- await startDashboardCoordinator('claude');
602
- });
603
- // codex - Start daemon and spawn Dashboard coordinator with Codex
604
- program
605
- .command('codex')
606
- .description('Start daemon and Dashboard coordinator with Codex')
607
- .action(async () => {
608
- await startDashboardCoordinator('codex');
609
- });
610
- // status - Check daemon status
611
- program
612
- .command('status')
613
- .description('Check daemon status')
614
- .action(async () => {
615
- const { getProjectPaths } = await import('../utils/project-namespace.js');
616
- const paths = getProjectPaths();
617
- const relaySessions = await discoverRelaySessions();
618
- if (!fs.existsSync(paths.socketPath)) {
619
- console.log('Status: STOPPED');
620
- logRelaySessions(relaySessions);
621
- return;
622
- }
623
- const client = new RelayClient({
624
- agentName: '__status__',
625
- socketPath: paths.socketPath,
626
- reconnect: false,
627
- });
628
- try {
629
- await client.connect();
630
- console.log('Status: RUNNING');
631
- console.log(`Socket: ${paths.socketPath}`);
632
- logRelaySessions(relaySessions);
633
- client.disconnect();
634
- }
635
- catch {
636
- console.log('Status: STOPPED');
637
- logRelaySessions(relaySessions);
638
- }
639
- });
640
- // agents - List connected agents (from registry file) and spawned workers
641
- program
642
- .command('agents')
643
- .description('List connected agents and spawned workers')
644
- .option('--all', 'Include internal/CLI agents')
645
- .option('--remote', 'Include agents from other linked machines (requires cloud link)')
646
- .option('--json', 'Output as JSON')
647
- .action(async (options) => {
648
- const { getProjectPaths } = await import('../utils/project-namespace.js');
649
- const os = await import('node:os');
650
- const paths = getProjectPaths();
651
- const agentsPath = path.join(paths.teamDir, 'agents.json');
652
- const connectedAgentsPath = path.join(paths.teamDir, 'connected-agents.json');
653
- // Load registered agents
654
- const allAgents = loadAgents(agentsPath);
655
- const agents = options.all
656
- ? allAgents
657
- : allAgents.filter(isVisibleAgent);
658
- // Load spawned workers
659
- const workers = readWorkersMetadata(paths.projectRoot);
660
- // Load currently connected agents (agents with active socket connections)
661
- let connectedAgentNames = new Set();
662
- let connectedUpdatedAt = 0;
663
- try {
664
- if (fs.existsSync(connectedAgentsPath)) {
665
- const connectedData = JSON.parse(fs.readFileSync(connectedAgentsPath, 'utf-8'));
666
- connectedAgentNames = new Set([
667
- ...(connectedData.agents || []),
668
- ...(connectedData.users || []),
669
- ]);
670
- connectedUpdatedAt = connectedData.updatedAt || 0;
671
- }
672
- }
673
- catch {
674
- // If file doesn't exist or is invalid, fall back to registry-based status
675
- }
676
- // Check if connected-agents.json is fresh (within 30 seconds)
677
- const isConnectedAgentsStale = Date.now() - connectedUpdatedAt > 30_000;
678
- const combined = [];
679
- // Add registered agents
680
- agents.forEach((agent) => {
681
- const worker = workers.find(w => w.name === agent.name);
682
- // Use connected-agents.json if fresh, otherwise fall back to registry lastSeen
683
- let status;
684
- if (!isConnectedAgentsStale && connectedAgentNames.size > 0) {
685
- // We have fresh connected-agents data - use actual connection status
686
- status = connectedAgentNames.has(agent.name ?? '') ? 'ONLINE' : 'OFFLINE';
687
- }
688
- else {
689
- // Fall back to registry-based status
690
- status = getAgentStatus(agent);
691
- }
692
- combined.push({
693
- name: agent.name ?? 'unknown',
694
- status,
695
- cli: agent.cli ?? '-',
696
- lastSeen: agent.lastSeen,
697
- team: worker?.team,
698
- pid: worker?.pid,
699
- location: 'local',
700
- });
701
- });
702
- // Add workers not in registry (orphaned or not yet registered)
703
- workers.forEach((worker) => {
704
- const existsInAgents = agents.some(a => a.name === worker.name);
705
- if (!existsInAgents) {
706
- combined.push({
707
- name: worker.name || 'unknown',
708
- status: 'ONLINE',
709
- cli: worker.cli || '-',
710
- team: worker.team,
711
- pid: worker.pid,
712
- location: 'local',
713
- });
714
- }
715
- });
716
- // Include remote agents if --remote flag is set
717
- if (options.remote) {
718
- const dataDir = process.env.AGENT_RELAY_DATA_DIR ||
719
- path.join(os.homedir(), '.local', 'share', 'agent-relay');
720
- const configPath = path.join(dataDir, 'cloud-config.json');
721
- if (fs.existsSync(configPath)) {
722
- try {
723
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
724
- const response = await fetch(`${config.cloudUrl}/api/daemons/agents`, {
725
- method: 'POST',
726
- headers: {
727
- 'Authorization': `Bearer ${config.apiKey}`,
728
- 'Content-Type': 'application/json',
729
- },
730
- body: JSON.stringify({ agents: [] }),
731
- });
732
- if (response.ok) {
733
- const data = await response.json();
734
- // Add remote agents (exclude local ones by name)
735
- const localNames = new Set(combined.map(a => a.name));
736
- for (const agent of data.allAgents) {
737
- if (!localNames.has(agent.name)) {
738
- combined.push({
739
- name: agent.name,
740
- status: agent.status.toUpperCase(),
741
- cli: '-',
742
- location: agent.daemonName,
743
- daemonId: agent.daemonId,
744
- });
745
- }
746
- }
747
- }
748
- }
749
- catch (err) {
750
- console.error('[warn] Failed to fetch remote agents:', err.message);
751
- }
752
- }
753
- else {
754
- console.error('[warn] Cloud not linked. Run `agent-relay cloud link` to see remote agents.');
755
- }
756
- }
757
- if (options.json) {
758
- console.log(JSON.stringify(combined, null, 2));
759
- return;
760
- }
761
- if (!combined.length) {
762
- const hint = options.all ? '' : ' (use --all to include internal/cli agents)';
763
- console.log(`No agents found. Ensure the daemon is running and agents are connected${hint}.`);
764
- return;
765
- }
766
- const hasRemote = combined.some(a => a.location !== 'local');
767
- if (hasRemote) {
768
- console.log('NAME STATUS CLI LOCATION');
769
- console.log('─'.repeat(55));
770
- combined.forEach((agent) => {
771
- const name = agent.name.padEnd(15);
772
- const status = agent.status.padEnd(8);
773
- const cli = agent.cli.padEnd(9);
774
- const location = agent.location ?? 'local';
775
- console.log(`${name} ${status} ${cli} ${location}`);
776
- });
777
- }
778
- else {
779
- console.log('NAME STATUS CLI TEAM');
780
- console.log('─'.repeat(50));
781
- combined.forEach((agent) => {
782
- const name = agent.name.padEnd(15);
783
- const status = agent.status.padEnd(8);
784
- const cli = agent.cli.padEnd(9);
785
- const team = agent.team ?? '-';
786
- console.log(`${name} ${status} ${cli} ${team}`);
787
- });
788
- }
789
- if (workers.length > 0) {
790
- console.log('');
791
- console.log('Commands:');
792
- console.log(' agent-relay agents:logs <name> - View spawned agent output');
793
- console.log(' agent-relay agents:kill <name> - Kill a spawned agent');
794
- }
795
- if (!options.remote) {
796
- console.log('');
797
- console.log('Tip: Use --remote to include agents from other linked machines.');
798
- }
799
- });
800
- // who - Show currently active agents (online within last 30s)
801
- program
802
- .command('who')
803
- .description('Show currently active agents (last seen within 30 seconds)')
804
- .option('--all', 'Include internal/CLI agents')
805
- .option('--json', 'Output as JSON')
806
- .action(async (options) => {
807
- const { getProjectPaths } = await import('../utils/project-namespace.js');
808
- const paths = getProjectPaths();
809
- const agentsPath = path.join(paths.teamDir, 'agents.json');
810
- const allAgents = loadAgents(agentsPath);
811
- const visibleAgents = options.all
812
- ? allAgents
813
- : allAgents.filter(a => !isInternalAgent(a.name));
814
- const onlineAgents = visibleAgents.filter(isAgentOnline);
815
- if (options.json) {
816
- console.log(JSON.stringify(onlineAgents.map(a => ({ ...a, status: getAgentStatus(a) })), null, 2));
817
- return;
818
- }
819
- if (!onlineAgents.length) {
820
- const hint = options.all ? '' : ' (use --all to include internal/cli agents)';
821
- console.log(`No active agents found${hint}.`);
822
- return;
823
- }
824
- console.log('NAME STATUS CLI LAST SEEN');
825
- console.log('---------------------------------------------');
826
- onlineAgents.forEach((agent) => {
827
- const name = (agent.name ?? 'unknown').padEnd(15);
828
- const status = getAgentStatus(agent).padEnd(8);
829
- const cli = (agent.cli ?? '-').padEnd(8);
830
- const lastSeen = formatRelativeTime(agent.lastSeen);
831
- console.log(`${name} ${status} ${cli} ${lastSeen}`);
832
- });
833
- });
834
- // read - Read full message by ID (for truncated messages)
835
- program
836
- .command('read')
837
- .description('Read full message by ID (for truncated messages)')
838
- .argument('<id>', 'Message ID')
839
- .action(async (messageId) => {
840
- const { getProjectPaths } = await import('../utils/project-namespace.js');
841
- const { createStorageAdapter } = await import('../storage/adapter.js');
842
- const paths = getProjectPaths();
843
- const adapter = await createStorageAdapter(paths.dbPath);
844
- if (!adapter.getMessageById) {
845
- console.error('Storage does not support message lookup');
846
- process.exit(1);
847
- }
848
- const msg = await adapter.getMessageById(messageId);
849
- if (!msg) {
850
- console.error(`Message not found: ${messageId}`);
851
- process.exit(1);
852
- }
853
- console.log(`From: ${msg.from}`);
854
- console.log(`To: ${msg.to}`);
855
- console.log(`Time: ${new Date(msg.ts).toISOString()}`);
856
- console.log('---');
857
- console.log(msg.body);
858
- await adapter.close?.();
859
- });
860
- // ============================================
861
- // Hidden commands (for agents, not in --help)
862
- // ============================================
863
- // history - Show recent messages (hidden from help, for agent use)
864
- program
865
- .command('history', { hidden: true })
866
- .description('Show recent messages')
867
- .option('-n, --limit <count>', 'Number of messages to show', '50')
868
- .option('-f, --from <agent>', 'Filter by sender')
869
- .option('-t, --to <agent>', 'Filter by recipient')
870
- .option('--since <time>', 'Since time (e.g., "1h", "2024-01-01")')
871
- .option('--json', 'Output as JSON')
872
- .action(async (options) => {
873
- const { getProjectPaths } = await import('../utils/project-namespace.js');
874
- const { createStorageAdapter } = await import('../storage/adapter.js');
875
- const paths = getProjectPaths();
876
- const adapter = await createStorageAdapter(paths.dbPath);
877
- const limit = Number.parseInt(options.limit ?? '50', 10) || 50;
878
- const sinceTs = parseSince(options.since);
879
- try {
880
- const messages = await adapter.getMessages({
881
- limit,
882
- from: options.from,
883
- to: options.to,
884
- sinceTs,
885
- order: 'desc',
886
- });
887
- if (options.json) {
888
- const payload = messages.map((m) => ({
889
- id: m.id,
890
- ts: m.ts,
891
- timestamp: new Date(m.ts).toISOString(),
892
- from: m.from,
893
- to: m.to,
894
- topic: m.topic,
895
- thread: m.thread,
896
- kind: m.kind,
897
- body: m.body,
898
- }));
899
- console.log(JSON.stringify(payload, null, 2));
900
- return;
901
- }
902
- if (!messages.length) {
903
- console.log('No messages found.');
904
- return;
905
- }
906
- messages.forEach((msg) => {
907
- const ts = new Date(msg.ts).toISOString();
908
- const body = msg.body.length > 120 ? `${msg.body.slice(0, 117)}...` : msg.body;
909
- console.log(`${ts} ${msg.from} -> ${msg.to}:${body}`);
910
- });
911
- }
912
- finally {
913
- await adapter.close?.();
914
- }
915
- });
916
- // version - Show version info
917
- program
918
- .command('version')
919
- .description('Show version information')
920
- .action(() => {
921
- console.log(`agent-relay v${VERSION}`);
922
- });
923
- // update - Check for updates and optionally install
924
- program
925
- .command('update')
926
- .description('Check for updates and install if available')
927
- .option('--check', 'Only check for updates, do not install')
928
- .action(async (options) => {
929
- console.log(`Current version: ${VERSION}`);
930
- console.log('Checking for updates...');
931
- const info = await checkForUpdates(VERSION);
932
- if (info.error) {
933
- console.error(`Failed to check for updates: ${info.error}`);
934
- process.exit(1);
935
- }
936
- if (!info.updateAvailable) {
937
- console.log('You are running the latest version.');
938
- return;
939
- }
940
- console.log(`New version available: ${info.latestVersion}`);
941
- if (options.check) {
942
- console.log('Run `agent-relay update` to install.');
943
- return;
944
- }
945
- console.log('Installing update...');
946
- try {
947
- const { stdout, stderr } = await execAsync('npm install -g agent-relay@latest');
948
- if (stdout)
949
- console.log(stdout);
950
- if (stderr)
951
- console.error(stderr);
952
- console.log(`Successfully updated to ${info.latestVersion}`);
953
- }
954
- catch (err) {
955
- console.error('Failed to install update:', err.message);
956
- console.log('Try running manually: npm install -g agent-relay@latest');
957
- process.exit(1);
958
- }
959
- });
960
- // check-tmux - Check tmux availability (hidden - for diagnostics)
961
- program
962
- .command('check-tmux', { hidden: true })
963
- .description('Check tmux availability and version')
964
- .action(async () => {
965
- const { resolveTmux, checkTmuxVersion } = await import('../utils/tmux-resolver.js');
966
- const info = resolveTmux();
967
- if (!info) {
968
- console.log('tmux: NOT FOUND');
969
- console.log('');
970
- console.log('Install tmux, then reinstall agent-relay:');
971
- console.log(' brew install tmux # macOS');
972
- console.log(' apt install tmux # Ubuntu/Debian');
973
- console.log(' npm install agent-relay # Reinstall to bundle tmux');
974
- process.exit(1);
975
- }
976
- console.log(`tmux: ${info.path}`);
977
- console.log(`Version: ${info.version}`);
978
- console.log(`Source: ${info.isBundled ? 'bundled' : 'system'}`);
979
- const versionCheck = checkTmuxVersion();
980
- if (!versionCheck.ok) {
981
- console.log(`Warning: tmux ${versionCheck.minimum}+ recommended`);
982
- }
983
- });
984
- // bridge - Multi-project orchestration
985
- program
986
- .command('bridge')
987
- .description('Bridge multiple projects as orchestrator')
988
- .argument('[projects...]', 'Project paths to bridge')
989
- .option('--cli <tool>', 'CLI tool override for all projects')
990
- .option('--architect [cli]', 'Spawn an architect agent to coordinate all projects (default: claude)')
991
- .action(async (projectPaths, options) => {
992
- const { resolveProjects, validateDaemons } = await import('../bridge/config.js');
993
- const { MultiProjectClient } = await import('../bridge/multi-project-client.js');
994
- const { getProjectPaths } = await import('../utils/project-namespace.js');
995
- const fs = await import('node:fs');
996
- const pathModule = await import('node:path');
997
- // Resolve projects from args or config
998
- const projects = resolveProjects(projectPaths, options.cli);
999
- if (projects.length === 0) {
1000
- console.error('No projects specified.');
1001
- console.error('Usage: agent-relay bridge ~/project1 ~/project2');
1002
- console.error(' or: Create ~/.agent-relay/bridge.json with project config');
1003
- process.exit(1);
1004
- }
1005
- console.log('Bridge Mode - Multi-Project Orchestration');
1006
- console.log('─'.repeat(40));
1007
- // Check which daemons are running
1008
- const { valid, missing } = validateDaemons(projects);
1009
- if (missing.length > 0) {
1010
- console.error('\nMissing daemons for:');
1011
- for (const p of missing) {
1012
- console.error(` - ${p.path}`);
1013
- console.error(` Run: cd "${p.path}" && agent-relay up`);
1014
- }
1015
- console.error('');
1016
- }
1017
- if (valid.length === 0) {
1018
- console.error('No projects have running daemons. Start them first.');
1019
- process.exit(1);
1020
- }
1021
- console.log('\nConnecting to projects:');
1022
- for (const p of valid) {
1023
- console.log(` - ${p.id} (${p.path})`);
1024
- console.log(` Lead: ${p.leadName}, CLI: ${p.cli}`);
1025
- }
1026
- console.log('');
1027
- // Get data directories for ALL bridged projects (so each project's dashboard can show bridge state)
1028
- const bridgeStatePaths = valid.map(p => {
1029
- const projectPaths = getProjectPaths(p.path);
1030
- // Ensure directory exists
1031
- if (!fs.existsSync(projectPaths.dataDir)) {
1032
- fs.mkdirSync(projectPaths.dataDir, { recursive: true });
1033
- }
1034
- return pathModule.join(projectPaths.dataDir, 'bridge-state.json');
1035
- });
1036
- const bridgeState = {
1037
- projects: valid.map(p => ({
1038
- id: p.id,
1039
- name: pathModule.basename(p.path),
1040
- path: p.path,
1041
- connected: false,
1042
- lead: { name: p.leadName, connected: false },
1043
- agents: [],
1044
- })),
1045
- messages: [],
1046
- connected: false,
1047
- startedAt: new Date().toISOString(),
1048
- };
1049
- // Write bridge state to ALL project data directories
1050
- const writeBridgeState = () => {
1051
- const stateJson = JSON.stringify(bridgeState, null, 2);
1052
- for (const statePath of bridgeStatePaths) {
1053
- try {
1054
- fs.writeFileSync(statePath, stateJson);
1055
- }
1056
- catch (err) {
1057
- console.error(`[bridge] Failed to write state to ${statePath}:`, err);
1058
- }
1059
- }
1060
- };
1061
- // Initial state write
1062
- writeBridgeState();
1063
- console.log(`Bridge state written to ${bridgeStatePaths.length} project(s)`);
1064
- // Connect to all project daemons
1065
- const client = new MultiProjectClient(valid);
1066
- // Track connection state changes (daemon connection, not agent registration)
1067
- // Also track "reconnecting" state for UI feedback
1068
- const wasConnected = new Map();
1069
- client.onProjectStateChange = (projectId, connected) => {
1070
- const project = bridgeState.projects.find(p => p.id === projectId);
1071
- if (project) {
1072
- const hadConnection = wasConnected.get(projectId) || false;
1073
- project.connected = connected;
1074
- // Set reconnecting if we lost connection (had it before, now disconnected)
1075
- project.reconnecting = !connected && hadConnection;
1076
- wasConnected.set(projectId, connected);
1077
- // Note: lead.connected should only be true when an actual lead agent registers
1078
- // The bridge connecting to daemon doesn't mean a lead agent is active
1079
- }
1080
- bridgeState.connected = bridgeState.projects.some(p => p.connected);
1081
- writeBridgeState();
1082
- };
1083
- try {
1084
- await client.connect();
1085
- }
1086
- catch (_err) {
1087
- console.error('Failed to connect to all projects');
1088
- writeBridgeState(); // Write final state before exit
1089
- process.exit(1);
1090
- }
1091
- bridgeState.connected = true;
1092
- writeBridgeState();
1093
- console.log('Connected to all projects.');
1094
- console.log('');
1095
- console.log('Cross-project messaging:');
1096
- console.log(' ->relay:projectId:agent Message');
1097
- console.log(' ->relay:*:lead Broadcast to all leads');
1098
- console.log('');
1099
- // Spawn architect agent if --architect flag is set
1100
- let architectWrapper = null;
1101
- if (options.architect !== undefined) {
1102
- // Determine CLI to use (default to claude)
1103
- const architectCli = typeof options.architect === 'string' ? options.architect : 'claude';
1104
- // Use first project as the base for the architect
1105
- const baseProject = valid[0];
1106
- const basePaths = getProjectPaths(baseProject.path);
1107
- // Build project context for the architect
1108
- const projectContext = valid.map(p => `- ${p.id}: ${p.path} (Lead: ${p.leadName})`).join('\n');
1109
- // Create architect system prompt
1110
- const architectPrompt = `You are the Architect, a cross-project coordinator overseeing multiple codebases.
1111
-
1112
- ## Connected Projects
1113
- ${projectContext}
1114
-
1115
- ## Your Role
1116
- - Coordinate high-level work across all projects
1117
- - Assign tasks to project leads
1118
- - Ensure consistency and resolve cross-project dependencies
1119
- - Review overall architecture decisions
1120
-
1121
- ## Cross-Project Messaging
1122
-
1123
- Write a file to your outbox, then output the trigger. Use project:AgentName syntax:
1124
-
1125
- \`\`\`bash
1126
- # Message specific project lead
1127
- cat > /tmp/relay-outbox/\$AGENT_RELAY_NAME/msg << 'EOF'
1128
- TO: ${valid[0].id}:${valid[0].leadName}
1129
-
1130
- Your message to this project's lead.
1131
- EOF
1132
- \`\`\`
1133
- Then output: \`->relay-file:msg\`
1134
-
1135
- \`\`\`bash
1136
- # Broadcast to all agents in a project
1137
- cat > /tmp/relay-outbox/\$AGENT_RELAY_NAME/broadcast << 'EOF'
1138
- TO: ${valid.length > 1 ? valid[1].id : valid[0].id}:*
1139
-
1140
- Broadcast to all agents in a project.
1141
- EOF
1142
- \`\`\`
1143
- Then output: \`->relay-file:broadcast\`
1144
-
1145
- \`\`\`bash
1146
- # Broadcast to ALL agents in ALL projects
1147
- cat > /tmp/relay-outbox/\$AGENT_RELAY_NAME/all << 'EOF'
1148
- TO: *:*
1149
-
1150
- Broadcast to ALL agents in ALL projects.
1151
- EOF
1152
- \`\`\`
1153
- Then output: \`->relay-file:all\`
1154
-
1155
- ## Getting Started
1156
- 1. Check in with each project lead to understand current status
1157
- 2. Identify cross-project dependencies
1158
- 3. Coordinate work across teams
1159
-
1160
- Start by greeting the project leads and asking for status updates.`;
1161
- console.log('Spawning Architect agent...');
1162
- console.log(` CLI: ${architectCli}`);
1163
- console.log(` Base project: ${baseProject.path}`);
1164
- console.log('');
1165
- // Determine command and args based on CLI
1166
- let command;
1167
- let args = [];
1168
- if (architectCli === 'claude' || architectCli.startsWith('claude:')) {
1169
- command = 'claude';
1170
- args = ['--dangerously-skip-permissions'];
1171
- // Add model if specified (e.g., claude:opus)
1172
- if (architectCli.includes(':')) {
1173
- const model = architectCli.split(':')[1];
1174
- args.push('--model', model);
1175
- }
1176
- }
1177
- else if (architectCli === 'codex') {
1178
- command = 'codex';
1179
- args = ['--dangerously-skip-permissions'];
1180
- }
1181
- else {
1182
- command = architectCli;
1183
- }
1184
- try {
1185
- architectWrapper = new RelayPtyOrchestrator({
1186
- name: 'Architect',
1187
- command,
1188
- args,
1189
- socketPath: basePaths.socketPath,
1190
- cwd: baseProject.path,
1191
- streamLogs: true,
1192
- });
1193
- await architectWrapper.start();
1194
- // Wait for agent to be ready, then inject the prompt
1195
- setTimeout(async () => {
1196
- try {
1197
- await architectWrapper.injectMessage(architectPrompt);
1198
- console.log('Architect agent started and initialized.');
1199
- console.log('');
1200
- }
1201
- catch (err) {
1202
- console.error('Failed to inject architect prompt:', err);
1203
- }
1204
- }, 3000);
1205
- }
1206
- catch (err) {
1207
- console.error('Failed to spawn Architect agent:', err);
1208
- }
1209
- }
1210
- // Handle messages from projects
1211
- client.onMessage = (projectId, from, payload, messageId) => {
1212
- console.log(`[${projectId}] ${from}: ${payload.body.substring(0, 80)}...`);
1213
- // Track message in bridge state
1214
- bridgeState.messages.push({
1215
- id: messageId,
1216
- from,
1217
- to: '*', // Incoming messages are from agents
1218
- body: payload.body,
1219
- sourceProject: projectId,
1220
- timestamp: new Date().toISOString(),
1221
- });
1222
- // Keep last 100 messages
1223
- if (bridgeState.messages.length > 100) {
1224
- bridgeState.messages = bridgeState.messages.slice(-100);
1225
- }
1226
- writeBridgeState();
1227
- };
1228
- // Clean up on exit
1229
- const cleanup = () => {
1230
- bridgeState.connected = false;
1231
- bridgeState.projects.forEach(p => {
1232
- p.connected = false;
1233
- if (p.lead)
1234
- p.lead.connected = false;
1235
- });
1236
- writeBridgeState();
1237
- };
1238
- // Keep running
1239
- process.on('SIGINT', () => {
1240
- console.log('\nDisconnecting...');
1241
- cleanup();
1242
- client.disconnect();
1243
- process.exit(0);
1244
- });
1245
- // Start a simple REPL for sending messages
1246
- const readline = await import('node:readline');
1247
- const rl = readline.createInterface({
1248
- input: process.stdin,
1249
- output: process.stdout,
1250
- });
1251
- console.log('Enter messages as: projectId:agent message');
1252
- console.log('Or: *:lead message (broadcast to all leads)');
1253
- console.log('Type "quit" to exit.\n');
1254
- const promptForInput = () => {
1255
- rl.question('> ', (input) => {
1256
- if (input.toLowerCase() === 'quit') {
1257
- client.disconnect();
1258
- rl.close();
1259
- process.exit(0);
1260
- }
1261
- // Parse input: projectId:agent message
1262
- const match = input.match(/^(\S+):(\S+)\s+(.+)$/);
1263
- if (match) {
1264
- const [, projectId, agent, message] = match;
1265
- if (projectId === '*' && agent === 'lead') {
1266
- client.broadcastToLeads(message);
1267
- console.log('→ Broadcast to all leads');
1268
- }
1269
- else if (projectId === '*') {
1270
- client.broadcastAll(message);
1271
- console.log('→ Broadcast to all');
1272
- }
1273
- else {
1274
- const sent = client.sendToProject(projectId, agent, message);
1275
- if (sent) {
1276
- console.log(`→ ${projectId}:${agent}`);
1277
- }
1278
- }
1279
- }
1280
- else {
1281
- console.log('Format: projectId:agent message');
1282
- }
1283
- promptForInput();
1284
- });
1285
- };
1286
- promptForInput();
1287
- });
1288
- // gc - Clean up orphaned tmux sessions (hidden - for agent use)
1289
- program
1290
- .command('gc', { hidden: true })
1291
- .description('Clean up orphaned tmux sessions (sessions with no connected agent)')
1292
- .option('--dry-run', 'Show what would be cleaned without actually doing it')
1293
- .option('--force', 'Kill all relay sessions regardless of connection status')
1294
- .action(async (options) => {
1295
- const { getProjectPaths } = await import('../utils/project-namespace.js');
1296
- const paths = getProjectPaths();
1297
- const agentsPath = path.join(paths.teamDir, 'agents.json');
1298
- // Get all relay tmux sessions
1299
- const sessions = await discoverRelaySessions();
1300
- if (!sessions.length) {
1301
- console.log('No relay tmux sessions found.');
1302
- return;
1303
- }
1304
- // Get connected agents
1305
- const connectedAgents = new Set();
1306
- if (!options.force) {
1307
- const agents = loadAgents(agentsPath);
1308
- // Consider an agent "connected" if last seen within 30 seconds
1309
- const staleThresholdMs = 30_000;
1310
- const now = Date.now();
1311
- agents.forEach(a => {
1312
- if (a.name && a.lastSeen) {
1313
- const lastSeenTs = Date.parse(a.lastSeen);
1314
- if (!Number.isNaN(lastSeenTs) && now - lastSeenTs < staleThresholdMs) {
1315
- connectedAgents.add(a.name);
1316
- }
1317
- }
1318
- });
1319
- }
1320
- // Find orphaned sessions
1321
- const orphaned = sessions.filter(s => options.force || (s.agentName && !connectedAgents.has(s.agentName)));
1322
- if (!orphaned.length) {
1323
- console.log(`All ${sessions.length} session(s) have active agents.`);
1324
- return;
1325
- }
1326
- console.log(`Found ${orphaned.length} orphaned session(s):`);
1327
- for (const session of orphaned) {
1328
- console.log(` - ${session.sessionName} (agent: ${session.agentName ?? 'unknown'})`);
1329
- }
1330
- if (options.dryRun) {
1331
- console.log('\nDry run - no sessions killed.');
1332
- return;
1333
- }
1334
- // Kill orphaned sessions
1335
- let killed = 0;
1336
- const tmuxPath = getTmuxPath();
1337
- for (const session of orphaned) {
1338
- try {
1339
- await execAsync(`"${tmuxPath}" kill-session -t ${session.sessionName}`);
1340
- killed++;
1341
- console.log(`Killed: ${session.sessionName}`);
1342
- }
1343
- catch (err) {
1344
- console.error(`Failed to kill ${session.sessionName}: ${err.message}`);
1345
- }
1346
- }
1347
- console.log(`\nCleaned up ${killed}/${orphaned.length} session(s).`);
1348
- });
1349
- async function discoverRelaySessions() {
1350
- try {
1351
- const tmuxPath = getTmuxPath();
1352
- const { stdout } = await execAsync(`"${tmuxPath}" list-sessions -F "#{session_name}"`);
1353
- const sessionNames = stdout
1354
- .split('\n')
1355
- .map(s => s.trim())
1356
- .filter(Boolean);
1357
- const relaySessions = sessionNames
1358
- .map(name => {
1359
- const match = name.match(/^relay-(.+)$/);
1360
- if (!match)
1361
- return undefined;
1362
- return { sessionName: name, agentName: match[1] };
1363
- })
1364
- .filter((s) => Boolean(s));
1365
- return await Promise.all(relaySessions.map(async (session) => {
1366
- let cwd;
1367
- try {
1368
- const { stdout: cwdOut } = await execAsync(`"${tmuxPath}" display-message -t ${session.sessionName} -p '#{pane_current_path}'`);
1369
- cwd = cwdOut.trim() || undefined;
1370
- }
1371
- catch {
1372
- cwd = undefined;
1373
- }
1374
- return { ...session, cwd };
1375
- }));
1376
- }
1377
- catch {
1378
- return [];
1379
- }
1380
- }
1381
- function logRelaySessions(sessions) {
1382
- if (!sessions.length) {
1383
- console.log('Relay tmux sessions: none detected');
1384
- return;
1385
- }
1386
- console.log('Relay tmux sessions:');
1387
- sessions.forEach((session) => {
1388
- const parts = [
1389
- `agent: ${session.agentName ?? 'unknown'}`,
1390
- session.cwd ? `cwd: ${session.cwd}` : undefined,
1391
- ].filter(Boolean);
1392
- console.log(`- ${session.sessionName}${parts.length ? ` (${parts.join(', ')})` : ''}`);
1393
- });
1394
- }
1395
- function loadAgents(agentsPath) {
1396
- if (!fs.existsSync(agentsPath)) {
1397
- return [];
1398
- }
1399
- try {
1400
- const raw = JSON.parse(fs.readFileSync(agentsPath, 'utf-8'));
1401
- const agentsArray = Array.isArray(raw?.agents)
1402
- ? raw.agents
1403
- : raw?.agents
1404
- ? Object.values(raw.agents)
1405
- : [];
1406
- return agentsArray
1407
- .filter((a) => a?.name)
1408
- .map((a) => ({
1409
- id: a.id,
1410
- name: a.name,
1411
- cli: a.cli,
1412
- workingDirectory: a.workingDirectory,
1413
- firstSeen: a.firstSeen,
1414
- lastSeen: a.lastSeen,
1415
- messagesSent: typeof a.messagesSent === 'number' ? a.messagesSent : 0,
1416
- messagesReceived: typeof a.messagesReceived === 'number' ? a.messagesReceived : 0,
1417
- }));
1418
- }
1419
- catch (err) {
1420
- console.error('Failed to read agents.json:', err.message);
1421
- return [];
1422
- }
1423
- }
1424
- const STALE_THRESHOLD_MS = 30_000;
1425
- // Internal agents that should be hidden from `agents` and `who` by default
1426
- const INTERNAL_AGENTS = new Set(['cli', 'Dashboard']);
1427
- function isInternalAgent(name) {
1428
- if (!name)
1429
- return true;
1430
- if (name.startsWith('__'))
1431
- return true;
1432
- return INTERNAL_AGENTS.has(name);
1433
- }
1434
- function getAgentStatus(agent) {
1435
- if (!agent.lastSeen)
1436
- return 'UNKNOWN';
1437
- const ts = Date.parse(agent.lastSeen);
1438
- if (Number.isNaN(ts))
1439
- return 'UNKNOWN';
1440
- return Date.now() - ts < STALE_THRESHOLD_MS ? 'ONLINE' : 'STALE';
1441
- }
1442
- function isAgentOnline(agent) {
1443
- return getAgentStatus(agent) === 'ONLINE';
1444
- }
1445
- // Visible agents: not internal and not stale (used by `agents` command)
1446
- function isVisibleAgent(agent) {
1447
- if (isInternalAgent(agent.name))
1448
- return false;
1449
- if (getAgentStatus(agent) === 'STALE')
1450
- return false;
1451
- return true;
1452
- }
1453
- function formatRelativeTime(iso) {
1454
- if (!iso)
1455
- return 'unknown';
1456
- const ts = Date.parse(iso);
1457
- if (Number.isNaN(ts))
1458
- return 'unknown';
1459
- const diffMs = Date.now() - ts;
1460
- const diffSec = Math.floor(diffMs / 1000);
1461
- if (diffSec < 60)
1462
- return `${diffSec}s ago`;
1463
- const diffMin = Math.floor(diffSec / 60);
1464
- if (diffMin < 60)
1465
- return `${diffMin}m ago`;
1466
- const diffHours = Math.floor(diffMin / 60);
1467
- if (diffHours < 48)
1468
- return `${diffHours}h ago`;
1469
- const diffDays = Math.floor(diffHours / 24);
1470
- return `${diffDays}d ago`;
1471
- }
1472
- function parseSince(input) {
1473
- if (!input)
1474
- return undefined;
1475
- const trimmed = String(input).trim();
1476
- if (!trimmed)
1477
- return undefined;
1478
- const durationMatch = trimmed.match(/^(-?\d+)([smhd])$/i);
1479
- if (durationMatch) {
1480
- const value = Number(durationMatch[1]);
1481
- const unit = durationMatch[2].toLowerCase();
1482
- const multipliers = {
1483
- s: 1000,
1484
- m: 60_000,
1485
- h: 3_600_000,
1486
- d: 86_400_000,
1487
- };
1488
- return Date.now() - value * multipliers[unit];
1489
- }
1490
- const parsed = Date.parse(trimmed);
1491
- if (Number.isNaN(parsed))
1492
- return undefined;
1493
- return parsed;
1494
- }
1495
- // ============================================
1496
- // Spawned agent debugging commands
1497
- // ============================================
1498
- // agents:logs - Show log file output for a spawned agent
1499
- program
1500
- .command('agents:logs')
1501
- .description('Show recent output from a spawned agent')
1502
- .argument('<name>', 'Agent name')
1503
- .option('-n, --lines <n>', 'Number of lines to show', '50')
1504
- .option('-f, --follow', 'Follow output (like tail -f)')
1505
- .action(async (name, options) => {
1506
- const { getProjectPaths } = await import('../utils/project-namespace.js');
1507
- const paths = getProjectPaths();
1508
- const logsDir = getWorkerLogsDir(paths.projectRoot);
1509
- const logFile = path.join(logsDir, `${name}.log`);
1510
- if (!fs.existsSync(logFile)) {
1511
- console.error(`No logs found for agent "${name}"`);
1512
- console.log(`Log file not found: ${logFile}`);
1513
- console.log(`Run 'agent-relay agents' to see available agents`);
1514
- process.exit(1);
1515
- }
1516
- if (options.follow) {
1517
- console.log(`Following logs for ${name} (Ctrl+C to stop)...`);
1518
- console.log('─'.repeat(50));
1519
- // Use tail -f approach
1520
- const { spawn } = await import('child_process');
1521
- const child = spawn('tail', ['-f', logFile], {
1522
- stdio: ['ignore', 'inherit', 'inherit'],
1523
- });
1524
- process.on('SIGINT', () => {
1525
- child.kill();
1526
- console.log('\nStopped following');
1527
- process.exit(0);
1528
- });
1529
- child.on('exit', () => {
1530
- process.exit(0);
1531
- });
1532
- }
1533
- else {
1534
- try {
1535
- const lines = parseInt(options.lines || '50', 10);
1536
- const { stdout } = await execAsync(`tail -n ${lines} "${logFile}"`);
1537
- console.log(`Logs for ${name} (last ${lines} lines):`);
1538
- console.log('─'.repeat(50));
1539
- console.log(stdout || '(empty)');
1540
- }
1541
- catch (err) {
1542
- console.error('Failed to read logs:', err.message);
1543
- }
1544
- }
1545
- });
1546
- // spawn - Spawn an agent via API (works from any context, no tmux required)
1547
- program
1548
- .command('spawn', { hidden: true })
1549
- .description('Spawn an agent via dashboard API (no tmux required, works in containers)')
1550
- .argument('<name>', 'Agent name')
1551
- .argument('<cli>', 'CLI to use (claude, codex, gemini, etc.)')
1552
- .argument('[task]', 'Task description (can also be piped via stdin)')
1553
- .option('--port <port>', 'Dashboard port', DEFAULT_DASHBOARD_PORT)
1554
- .option('--team <team>', 'Team name for the agent')
1555
- .option('--spawner <name>', 'Name of the agent requesting the spawn (for policy enforcement)')
1556
- .option('--interactive', 'Disable auto-accept of permission prompts (for auth setup flows)')
1557
- .option('--cwd <path>', 'Working directory for the agent')
1558
- .option('--shadow-mode <mode>', 'Shadow execution mode: subagent or process')
1559
- .option('--shadow-of <name>', 'Primary agent to shadow (if this agent is a shadow)')
1560
- .option('--shadow-agent <profile>', 'Shadow agent profile to use')
1561
- .option('--shadow-triggers <triggers>', 'When to trigger shadow (comma-separated: SESSION_END,CODE_WRITTEN,REVIEW_REQUEST,EXPLICIT_ASK,ALL_MESSAGES)')
1562
- .option('--shadow-speak-on <triggers>', 'When shadow should speak (comma-separated, same values as --shadow-triggers)')
1563
- .action(async (name, cli, task, options) => {
1564
- const port = options.port || DEFAULT_DASHBOARD_PORT;
1565
- // Read task from stdin if not provided as argument
1566
- let finalTask = task;
1567
- if (!finalTask && !process.stdin.isTTY) {
1568
- const chunks = [];
1569
- for await (const chunk of process.stdin) {
1570
- chunks.push(chunk);
1571
- }
1572
- finalTask = Buffer.concat(chunks).toString('utf-8').trim();
1573
- }
1574
- if (!finalTask) {
1575
- console.error('Error: Task description required (as argument or via stdin)');
1576
- process.exit(1);
1577
- }
1578
- // Validate shadow mode if provided
1579
- if (options.shadowMode && !['subagent', 'process'].includes(options.shadowMode)) {
1580
- console.error('Error: --shadow-mode must be "subagent" or "process"');
1581
- process.exit(1);
1582
- }
1583
- // Parse comma-separated trigger lists
1584
- const parseTriggers = (value) => {
1585
- if (!value)
1586
- return undefined;
1587
- const validTriggers = ['SESSION_END', 'CODE_WRITTEN', 'REVIEW_REQUEST', 'EXPLICIT_ASK', 'ALL_MESSAGES'];
1588
- const triggers = value.split(',').map(t => t.trim().toUpperCase());
1589
- const invalid = triggers.filter(t => !validTriggers.includes(t));
1590
- if (invalid.length > 0) {
1591
- console.error(`Error: Invalid triggers: ${invalid.join(', ')}`);
1592
- console.error(`Valid triggers: ${validTriggers.join(', ')}`);
1593
- process.exit(1);
1594
- }
1595
- return triggers;
1596
- };
1597
- try {
1598
- // Build spawn request using the SpawnRequest type for consistency
1599
- const spawnRequest = {
1600
- name,
1601
- cli,
1602
- task: finalTask,
1603
- team: options.team,
1604
- spawnerName: options.spawner,
1605
- interactive: options.interactive,
1606
- cwd: options.cwd,
1607
- shadowMode: options.shadowMode,
1608
- shadowOf: options.shadowOf,
1609
- shadowAgent: options.shadowAgent,
1610
- shadowTriggers: parseTriggers(options.shadowTriggers),
1611
- shadowSpeakOn: parseTriggers(options.shadowSpeakOn),
1612
- };
1613
- const response = await fetch(`http://localhost:${port}/api/spawn`, {
1614
- method: 'POST',
1615
- headers: { 'Content-Type': 'application/json' },
1616
- body: JSON.stringify(spawnRequest),
1617
- });
1618
- const result = await response.json();
1619
- if (result.success) {
1620
- console.log(`Spawned agent: ${name} (pid: ${result.pid})`);
1621
- process.exit(0);
1622
- }
1623
- else {
1624
- if (result.policyDecision) {
1625
- console.error(`Policy denied spawn: ${result.policyDecision.reason}`);
1626
- console.error(`Policy source: ${result.policyDecision.policySource}`);
1627
- }
1628
- else {
1629
- console.error(`Failed to spawn ${name}: ${result.error || 'Unknown error'}`);
1630
- }
1631
- process.exit(1);
1632
- }
1633
- }
1634
- catch (err) {
1635
- if (err.code === 'ECONNREFUSED') {
1636
- console.error(`Cannot connect to dashboard at port ${port}. Is the daemon running?`);
1637
- console.log(`Run 'agent-relay up' to start the daemon.`);
1638
- }
1639
- else {
1640
- console.error(`Failed to spawn ${name}: ${err.message}`);
1641
- }
1642
- process.exit(1);
1643
- }
1644
- });
1645
- // release - Release a spawned agent via API (works from any context, no terminal required)
1646
- program
1647
- .command('release')
1648
- .description('Release a spawned agent via API (no terminal required)')
1649
- .argument('<name>', 'Agent name to release')
1650
- .option('--port <port>', 'Dashboard port', DEFAULT_DASHBOARD_PORT)
1651
- .action(async (name, options) => {
1652
- const port = options.port || DEFAULT_DASHBOARD_PORT;
1653
- try {
1654
- const response = await fetch(`http://localhost:${port}/api/spawned/${encodeURIComponent(name)}`, {
1655
- method: 'DELETE',
1656
- });
1657
- const result = await response.json();
1658
- if (result.success) {
1659
- console.log(`Released agent: ${name}`);
1660
- process.exit(0);
1661
- }
1662
- else {
1663
- console.error(`Failed to release ${name}: ${result.error || 'Unknown error'}`);
1664
- process.exit(1);
1665
- }
1666
- }
1667
- catch (err) {
1668
- // If API call fails, try to provide helpful error message
1669
- if (err.code === 'ECONNREFUSED') {
1670
- console.error(`Cannot connect to dashboard at port ${port}. Is the daemon running?`);
1671
- console.log(`Run 'agent-relay up' to start the daemon.`);
1672
- }
1673
- else {
1674
- console.error(`Failed to release ${name}: ${err.message}`);
1675
- }
1676
- process.exit(1);
1677
- }
1678
- });
1679
- // agents:kill - Kill a spawned agent by PID
1680
- program
1681
- .command('agents:kill')
1682
- .description('Kill a spawned agent')
1683
- .argument('<name>', 'Agent name')
1684
- .option('--force', 'Skip graceful shutdown, kill immediately')
1685
- .action(async (name, options) => {
1686
- const { getProjectPaths } = await import('../utils/project-namespace.js');
1687
- const paths = getProjectPaths();
1688
- const workers = readWorkersMetadata(paths.projectRoot);
1689
- const worker = workers.find(w => w.name === name);
1690
- if (!worker) {
1691
- console.error(`Spawned agent "${name}" not found`);
1692
- console.log(`Run 'agent-relay agents' to see available agents`);
1693
- process.exit(1);
1694
- }
1695
- if (!worker.pid) {
1696
- console.error(`Agent "${name}" has no PID recorded`);
1697
- process.exit(1);
1698
- }
1699
- try {
1700
- if (!options.force) {
1701
- // Try graceful shutdown first (SIGTERM)
1702
- console.log(`Sending SIGTERM to ${name} (pid: ${worker.pid})...`);
1703
- process.kill(worker.pid, 'SIGTERM');
1704
- // Wait for graceful shutdown
1705
- await new Promise(r => setTimeout(r, 2000));
1706
- // Check if still running
1707
- try {
1708
- process.kill(worker.pid, 0); // Check if process exists
1709
- console.log(`Agent still running, sending SIGKILL...`);
1710
- process.kill(worker.pid, 'SIGKILL');
1711
- }
1712
- catch {
1713
- // Process no longer exists, graceful shutdown worked
1714
- }
1715
- }
1716
- else {
1717
- // Force kill immediately
1718
- console.log(`Force killing ${name} (pid: ${worker.pid})...`);
1719
- process.kill(worker.pid, 'SIGKILL');
1720
- }
1721
- console.log(`Killed agent: ${name}`);
1722
- }
1723
- catch (err) {
1724
- if (err.code === 'ESRCH') {
1725
- console.log(`Agent ${name} is no longer running (pid: ${worker.pid})`);
1726
- }
1727
- else {
1728
- console.error(`Failed to kill ${name}:`, err.message);
1729
- process.exit(1);
1730
- }
1731
- }
1732
- });
1733
- // ============================================================================
1734
- // Cloud commands
1735
- // ============================================================================
1736
- const cloudCommand = program
1737
- .command('cloud')
1738
- .description('Cloud account and sync commands');
1739
- cloudCommand
1740
- .command('link')
1741
- .description('Link this machine to your Agent Relay Cloud account')
1742
- .option('--name <name>', 'Name for this machine')
1743
- .option('--cloud-url <url>', 'Cloud API URL', process.env.AGENT_RELAY_CLOUD_URL || 'https://agent-relay.com')
1744
- .action(async (options) => {
1745
- const os = await import('node:os');
1746
- const crypto = await import('node:crypto');
1747
- const readline = await import('node:readline');
1748
- const cloudUrl = options.cloudUrl;
1749
- const machineName = options.name || os.hostname();
1750
- // Generate machine ID
1751
- const dataDir = process.env.AGENT_RELAY_DATA_DIR ||
1752
- path.join(os.homedir(), '.local', 'share', 'agent-relay');
1753
- const machineIdPath = path.join(dataDir, 'machine-id');
1754
- const configPath = path.join(dataDir, 'cloud-config.json');
1755
- let machineId;
1756
- if (fs.existsSync(machineIdPath)) {
1757
- machineId = fs.readFileSync(machineIdPath, 'utf-8').trim();
1758
- }
1759
- else {
1760
- machineId = `${os.hostname()}-${crypto.randomBytes(8).toString('hex')}`;
1761
- fs.mkdirSync(dataDir, { recursive: true });
1762
- fs.writeFileSync(machineIdPath, machineId);
1763
- }
1764
- console.log('');
1765
- console.log('🔗 Agent Relay Cloud - Link Machine');
1766
- console.log('');
1767
- console.log(`Machine: ${machineName}`);
1768
- console.log(`ID: ${machineId}`);
1769
- console.log('');
1770
- // Generate a temporary code for the browser auth flow
1771
- const tempCode = crypto.randomBytes(16).toString('hex');
1772
- // Store temp code for callback
1773
- const tempCodePath = path.join(dataDir, '.link-code');
1774
- fs.writeFileSync(tempCodePath, tempCode);
1775
- const authUrl = `${cloudUrl.replace('/api', '')}/cloud/link?code=${tempCode}&machine=${encodeURIComponent(machineId)}&name=${encodeURIComponent(machineName)}`;
1776
- console.log('Open this URL in your browser to authenticate:');
1777
- console.log('');
1778
- console.log(` ${authUrl}`);
1779
- console.log('');
1780
- // Try to open browser automatically
1781
- try {
1782
- const openCommand = process.platform === 'darwin' ? 'open' :
1783
- process.platform === 'win32' ? 'start' : 'xdg-open';
1784
- await execAsync(`${openCommand} "${authUrl}"`);
1785
- console.log('(Browser opened automatically)');
1786
- }
1787
- catch {
1788
- console.log('(Copy the URL above and paste it in your browser)');
1789
- }
1790
- console.log('');
1791
- console.log('After authenticating, paste your API key here:');
1792
- const rl = readline.createInterface({
1793
- input: process.stdin,
1794
- output: process.stdout,
1795
- });
1796
- const apiKey = await new Promise((resolve) => {
1797
- rl.question('API Key: ', (answer) => {
1798
- rl.close();
1799
- resolve(answer.trim());
1800
- });
1801
- });
1802
- if (!apiKey || !apiKey.startsWith('ar_live_')) {
1803
- console.error('');
1804
- console.error('Invalid API key format. Expected ar_live_...');
1805
- process.exit(1);
1806
- }
1807
- // Verify the API key works
1808
- console.log('');
1809
- console.log('Verifying API key...');
1810
- try {
1811
- const response = await fetch(`${cloudUrl}/api/daemons/heartbeat`, {
1812
- method: 'POST',
1813
- headers: {
1814
- 'Authorization': `Bearer ${apiKey}`,
1815
- 'Content-Type': 'application/json',
1816
- },
1817
- body: JSON.stringify({
1818
- agents: [],
1819
- metrics: { linkedAt: new Date().toISOString() },
1820
- }),
1821
- });
1822
- if (!response.ok) {
1823
- const error = await response.text();
1824
- console.error(`Failed to verify API key: ${error}`);
1825
- process.exit(1);
1826
- }
1827
- // Save config
1828
- const config = {
1829
- apiKey,
1830
- cloudUrl,
1831
- machineId,
1832
- machineName,
1833
- linkedAt: new Date().toISOString(),
1834
- };
1835
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
1836
- fs.chmodSync(configPath, 0o600); // Secure the file
1837
- // Clean up temp code
1838
- if (fs.existsSync(tempCodePath)) {
1839
- fs.unlinkSync(tempCodePath);
1840
- }
1841
- console.log('');
1842
- console.log('✓ Machine linked successfully!');
1843
- console.log('');
1844
- console.log('Your daemon will now sync with Agent Relay Cloud.');
1845
- console.log('Run `agent-relay up` to start with cloud sync enabled.');
1846
- console.log('');
1847
- }
1848
- catch (err) {
1849
- console.error(`Failed to connect to cloud: ${err.message}`);
1850
- process.exit(1);
1851
- }
1852
- });
1853
- cloudCommand
1854
- .command('unlink')
1855
- .description('Unlink this machine from Agent Relay Cloud')
1856
- .action(async () => {
1857
- const os = await import('node:os');
1858
- const dataDir = process.env.AGENT_RELAY_DATA_DIR ||
1859
- path.join(os.homedir(), '.local', 'share', 'agent-relay');
1860
- const configPath = path.join(dataDir, 'cloud-config.json');
1861
- if (!fs.existsSync(configPath)) {
1862
- console.log('This machine is not linked to Agent Relay Cloud.');
1863
- return;
1864
- }
1865
- // Read current config
1866
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
1867
- // Delete config file
1868
- fs.unlinkSync(configPath);
1869
- console.log('');
1870
- console.log('✓ Machine unlinked from Agent Relay Cloud');
1871
- console.log('');
1872
- console.log(`Machine ID: ${config.machineId}`);
1873
- console.log(`Was linked since: ${config.linkedAt}`);
1874
- console.log('');
1875
- console.log('Note: The API key has been removed locally. To fully revoke access,');
1876
- console.log('visit your Agent Relay Cloud dashboard and remove this machine.');
1877
- console.log('');
1878
- });
1879
- cloudCommand
1880
- .command('status')
1881
- .description('Show cloud sync status')
1882
- .action(async () => {
1883
- const os = await import('node:os');
1884
- const dataDir = process.env.AGENT_RELAY_DATA_DIR ||
1885
- path.join(os.homedir(), '.local', 'share', 'agent-relay');
1886
- const configPath = path.join(dataDir, 'cloud-config.json');
1887
- if (!fs.existsSync(configPath)) {
1888
- console.log('');
1889
- console.log('Cloud sync: Not configured');
1890
- console.log('');
1891
- console.log('Run `agent-relay cloud link` to connect to Agent Relay Cloud.');
1892
- console.log('');
1893
- return;
1894
- }
1895
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
1896
- console.log('');
1897
- console.log('Cloud sync: Enabled');
1898
- console.log('');
1899
- console.log(` Machine: ${config.machineName}`);
1900
- console.log(` ID: ${config.machineId}`);
1901
- console.log(` Cloud URL: ${config.cloudUrl}`);
1902
- console.log(` Linked: ${new Date(config.linkedAt).toLocaleString()}`);
1903
- console.log('');
1904
- // Check if daemon is running and connected
1905
- const { getProjectPaths } = await import('../utils/project-namespace.js');
1906
- const paths = getProjectPaths();
1907
- if (fs.existsSync(paths.socketPath)) {
1908
- console.log(' Daemon: Running');
1909
- // Try to get cloud sync status from daemon
1910
- try {
1911
- const response = await fetch(`${config.cloudUrl}/api/daemons/heartbeat`, {
1912
- method: 'POST',
1913
- headers: {
1914
- 'Authorization': `Bearer ${config.apiKey}`,
1915
- 'Content-Type': 'application/json',
1916
- },
1917
- body: JSON.stringify({ agents: [], metrics: {} }),
1918
- });
1919
- if (response.ok) {
1920
- console.log(' Cloud connection: Online');
1921
- }
1922
- else {
1923
- console.log(' Cloud connection: Error (API key may be invalid)');
1924
- }
1925
- }
1926
- catch (err) {
1927
- console.log(` Cloud connection: Offline (${err.message})`);
1928
- }
1929
- }
1930
- else {
1931
- console.log(' Daemon: Not running');
1932
- console.log(' Cloud connection: Offline (daemon not started)');
1933
- }
1934
- console.log('');
1935
- });
1936
- cloudCommand
1937
- .command('sync')
1938
- .description('Manually sync credentials from cloud')
1939
- .action(async () => {
1940
- const os = await import('node:os');
1941
- const dataDir = process.env.AGENT_RELAY_DATA_DIR ||
1942
- path.join(os.homedir(), '.local', 'share', 'agent-relay');
1943
- const configPath = path.join(dataDir, 'cloud-config.json');
1944
- if (!fs.existsSync(configPath)) {
1945
- console.error('Not linked to cloud. Run `agent-relay cloud link` first.');
1946
- process.exit(1);
1947
- }
1948
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
1949
- console.log('Syncing credentials from cloud...');
1950
- try {
1951
- const response = await fetch(`${config.cloudUrl}/api/daemons/credentials`, {
1952
- headers: {
1953
- 'Authorization': `Bearer ${config.apiKey}`,
1954
- },
1955
- });
1956
- if (!response.ok) {
1957
- const error = await response.text();
1958
- console.error(`Failed to sync: ${error}`);
1959
- process.exit(1);
1960
- }
1961
- const data = await response.json();
1962
- console.log('');
1963
- console.log(`Synced ${data.credentials.length} provider credentials:`);
1964
- for (const cred of data.credentials) {
1965
- console.log(` - ${cred.provider}`);
1966
- }
1967
- // Save credentials locally for daemon to use
1968
- const credentialsPath = path.join(dataDir, 'cloud-credentials.json');
1969
- fs.writeFileSync(credentialsPath, JSON.stringify(data.credentials, null, 2));
1970
- fs.chmodSync(credentialsPath, 0o600);
1971
- console.log('');
1972
- console.log('✓ Credentials synced successfully');
1973
- console.log('');
1974
- }
1975
- catch (err) {
1976
- console.error(`Failed to sync: ${err.message}`);
1977
- process.exit(1);
1978
- }
1979
- });
1980
- // ============================================================================
1981
- // TRAJECTORY COMMANDS (trail proxy)
1982
- // ============================================================================
1983
- // trail - Proxy to trail CLI for trajectory tracking
1984
- program
1985
- .command('trail')
1986
- .description('Trajectory tracking commands (proxies to trail CLI)')
1987
- .argument('[args...]', 'Arguments to pass to trail CLI')
1988
- .allowUnknownOption()
1989
- .action(async (args) => {
1990
- const { spawn } = await import('node:child_process');
1991
- const { getProjectPaths } = await import('../utils/project-namespace.js');
1992
- const { getPrimaryTrajectoriesDir, ensureTrajectoriesDir } = await import('../trajectory/config.js');
1993
- const paths = getProjectPaths();
1994
- // Check if trail is available
1995
- const trailCheck = spawn('which', ['trail'], { stdio: 'pipe' });
1996
- const trailExists = await new Promise((resolve) => {
1997
- trailCheck.on('close', (code) => resolve(code === 0));
1998
- trailCheck.on('error', () => resolve(false));
1999
- });
2000
- if (!trailExists) {
2001
- console.error('trail CLI not found. Install with: npm install -g agent-trajectories');
2002
- console.log('');
2003
- console.log('The trail CLI provides trajectory tracking for agent work:');
2004
- console.log(' trail start "<task>" Start tracking a new trajectory');
2005
- console.log(' trail status Show current trajectory status');
2006
- console.log(' trail phase <phase> Transition to PDERO phase');
2007
- console.log(' trail decision "<choice>" Record a decision');
2008
- console.log(' trail complete Complete the trajectory');
2009
- console.log(' trail list List all trajectories');
2010
- console.log('');
2011
- console.log('PDERO phases: plan, design, execute, review, observe');
2012
- process.exit(1);
2013
- }
2014
- // Get trajectory storage path based on config (respects opt-in/opt-out)
2015
- // Uses TRAJECTORIES_DATA_DIR env var which trail CLI reads
2016
- const trajectoriesDir = getPrimaryTrajectoriesDir(paths.projectRoot);
2017
- ensureTrajectoriesDir(paths.projectRoot);
2018
- // Spawn trail with the provided arguments
2019
- const trailProc = spawn('trail', args, {
2020
- cwd: paths.projectRoot,
2021
- stdio: 'inherit',
2022
- env: {
2023
- ...process.env,
2024
- // Trajectory env vars override parent shell settings
2025
- // This ensures config-based TRAJECTORIES_DATA_DIR takes precedence
2026
- TRAJECTORIES_PROJECT: paths.projectId,
2027
- TRAJECTORIES_DATA_DIR: trajectoriesDir,
2028
- },
2029
- });
2030
- trailProc.on('close', (code) => {
2031
- process.exit(code ?? 0);
2032
- });
2033
- trailProc.on('error', (err) => {
2034
- console.error(`Failed to run trail: ${err.message}`);
2035
- process.exit(1);
2036
- });
2037
- });
2038
- cloudCommand
2039
- .command('agents')
2040
- .description('List agents across all linked machines')
2041
- .option('--json', 'Output as JSON')
2042
- .action(async (options) => {
2043
- const os = await import('node:os');
2044
- const dataDir = process.env.AGENT_RELAY_DATA_DIR ||
2045
- path.join(os.homedir(), '.local', 'share', 'agent-relay');
2046
- const configPath = path.join(dataDir, 'cloud-config.json');
2047
- if (!fs.existsSync(configPath)) {
2048
- console.error('Not linked to cloud. Run `agent-relay cloud link` first.');
2049
- process.exit(1);
2050
- }
2051
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
2052
- try {
2053
- // Get agents from cloud
2054
- const response = await fetch(`${config.cloudUrl}/api/daemons/agents`, {
2055
- method: 'POST',
2056
- headers: {
2057
- 'Authorization': `Bearer ${config.apiKey}`,
2058
- 'Content-Type': 'application/json',
2059
- },
2060
- body: JSON.stringify({ agents: [] }), // Report no agents, just fetch list
2061
- });
2062
- if (!response.ok) {
2063
- const error = await response.text();
2064
- console.error(`Failed to fetch agents: ${error}`);
2065
- process.exit(1);
2066
- }
2067
- const data = await response.json();
2068
- if (options.json) {
2069
- console.log(JSON.stringify(data.allAgents, null, 2));
2070
- return;
2071
- }
2072
- if (!data.allAgents.length) {
2073
- console.log('No agents found across linked machines.');
2074
- console.log('Make sure daemons are running on linked machines.');
2075
- return;
2076
- }
2077
- console.log('');
2078
- console.log('Agents across all linked machines:');
2079
- console.log('');
2080
- console.log('NAME STATUS DAEMON MACHINE');
2081
- console.log('─'.repeat(65));
2082
- // Group by daemon
2083
- const byDaemon = new Map();
2084
- for (const agent of data.allAgents) {
2085
- const existing = byDaemon.get(agent.daemonName) || [];
2086
- existing.push(agent);
2087
- byDaemon.set(agent.daemonName, existing);
2088
- }
2089
- for (const [daemonName, agents] of byDaemon.entries()) {
2090
- for (const agent of agents) {
2091
- const name = agent.name.padEnd(15);
2092
- const status = agent.status.padEnd(8);
2093
- const daemon = daemonName.padEnd(18);
2094
- const machine = agent.machineId.substring(0, 20);
2095
- console.log(`${name} ${status} ${daemon} ${machine}`);
2096
- }
2097
- }
2098
- console.log('');
2099
- console.log(`Total: ${data.allAgents.length} agents on ${byDaemon.size} machines`);
2100
- console.log('');
2101
- }
2102
- catch (err) {
2103
- console.error(`Failed to fetch agents: ${err.message}`);
2104
- process.exit(1);
2105
- }
2106
- });
2107
- cloudCommand
2108
- .command('send')
2109
- .description('Send a message to an agent on any linked machine')
2110
- .argument('<agent>', 'Target agent name')
2111
- .argument('<message>', 'Message to send')
2112
- .option('--from <name>', 'Sender name', 'cli')
2113
- .action(async (agent, message, options) => {
2114
- const os = await import('node:os');
2115
- const dataDir = process.env.AGENT_RELAY_DATA_DIR ||
2116
- path.join(os.homedir(), '.local', 'share', 'agent-relay');
2117
- const configPath = path.join(dataDir, 'cloud-config.json');
2118
- if (!fs.existsSync(configPath)) {
2119
- console.error('Not linked to cloud. Run `agent-relay cloud link` first.');
2120
- process.exit(1);
2121
- }
2122
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
2123
- console.log(`Sending message to ${agent}...`);
2124
- try {
2125
- // First, find which daemon the agent is on
2126
- const agentsResponse = await fetch(`${config.cloudUrl}/api/daemons/agents`, {
2127
- method: 'POST',
2128
- headers: {
2129
- 'Authorization': `Bearer ${config.apiKey}`,
2130
- 'Content-Type': 'application/json',
2131
- },
2132
- body: JSON.stringify({ agents: [] }),
2133
- });
2134
- if (!agentsResponse.ok) {
2135
- const error = await agentsResponse.text();
2136
- console.error(`Failed to find agent: ${error}`);
2137
- process.exit(1);
2138
- }
2139
- const agentsData = await agentsResponse.json();
2140
- const targetAgent = agentsData.allAgents.find(a => a.name === agent);
2141
- if (!targetAgent) {
2142
- console.error(`Agent "${agent}" not found.`);
2143
- console.log('Available agents:');
2144
- for (const a of agentsData.allAgents) {
2145
- console.log(` - ${a.name} (on ${a.daemonName})`);
2146
- }
2147
- process.exit(1);
2148
- }
2149
- // Send the message
2150
- const sendResponse = await fetch(`${config.cloudUrl}/api/daemons/message`, {
2151
- method: 'POST',
2152
- headers: {
2153
- 'Authorization': `Bearer ${config.apiKey}`,
2154
- 'Content-Type': 'application/json',
2155
- },
2156
- body: JSON.stringify({
2157
- targetDaemonId: targetAgent.daemonId,
2158
- targetAgent: agent,
2159
- message: {
2160
- from: options.from,
2161
- content: message,
2162
- },
2163
- }),
2164
- });
2165
- if (!sendResponse.ok) {
2166
- const error = await sendResponse.text();
2167
- console.error(`Failed to send message: ${error}`);
2168
- process.exit(1);
2169
- }
2170
- console.log('');
2171
- console.log(`✓ Message sent to ${agent} on ${targetAgent.daemonName}`);
2172
- console.log('');
2173
- }
2174
- catch (err) {
2175
- console.error(`Failed to send message: ${err.message}`);
2176
- process.exit(1);
2177
- }
2178
- });
2179
- cloudCommand
2180
- .command('daemons')
2181
- .description('List all linked daemon instances')
2182
- .option('--json', 'Output as JSON')
2183
- .action(async (_options) => {
2184
- const os = await import('node:os');
2185
- const dataDir = process.env.AGENT_RELAY_DATA_DIR ||
2186
- path.join(os.homedir(), '.local', 'share', 'agent-relay');
2187
- const configPath = path.join(dataDir, 'cloud-config.json');
2188
- if (!fs.existsSync(configPath)) {
2189
- console.error('Not linked to cloud. Run `agent-relay cloud link` first.');
2190
- process.exit(1);
2191
- }
2192
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
2193
- try {
2194
- // Get daemons list (requires browser auth, so we use a workaround)
2195
- // For now, just show what we know about our own daemon
2196
- console.log('');
2197
- console.log('Linked Daemon:');
2198
- console.log('');
2199
- console.log(` Machine: ${config.machineName}`);
2200
- console.log(` ID: ${config.machineId}`);
2201
- console.log(` Cloud: ${config.cloudUrl}`);
2202
- console.log(` Linked: ${new Date(config.linkedAt).toLocaleString()}`);
2203
- console.log('');
2204
- console.log('Note: To see all linked daemons, visit your cloud dashboard.');
2205
- console.log('');
2206
- }
2207
- catch (err) {
2208
- console.error(`Failed: ${err.message}`);
2209
- process.exit(1);
2210
- }
2211
- });
2212
- // ============================================================================
2213
- // Monitoring commands (metrics, health, profiler)
2214
- // ============================================================================
2215
- // metrics - Show agent memory metrics
2216
- program
2217
- .command('metrics')
2218
- .description('Show agent memory metrics and resource usage')
2219
- .option('--agent <name>', 'Show metrics for specific agent')
2220
- .option('--port <port>', 'Dashboard port', DEFAULT_DASHBOARD_PORT)
2221
- .option('--json', 'Output as JSON')
2222
- .option('--watch', 'Continuously update metrics')
2223
- .option('--interval <ms>', 'Update interval for watch mode', '5000')
2224
- .action(async (options) => {
2225
- const port = options.port || DEFAULT_DASHBOARD_PORT;
2226
- const fetchMetrics = async () => {
2227
- try {
2228
- const response = await fetch(`http://localhost:${port}/api/metrics/agents`);
2229
- if (!response.ok) {
2230
- throw new Error(`HTTP ${response.status}`);
2231
- }
2232
- return await response.json();
2233
- }
2234
- catch (err) {
2235
- if (err.code === 'ECONNREFUSED') {
2236
- console.error(`Cannot connect to dashboard at port ${port}. Is the daemon running?`);
2237
- console.log(`Run 'agent-relay up' to start the daemon.`);
2238
- }
2239
- else {
2240
- console.error(`Failed to fetch metrics: ${err.message}`);
2241
- }
2242
- process.exit(1);
2243
- }
2244
- };
2245
- const formatBytes = (bytes) => {
2246
- if (bytes === 0)
2247
- return '0 B';
2248
- const k = 1024;
2249
- const sizes = ['B', 'KB', 'MB', 'GB'];
2250
- const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k));
2251
- return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`;
2252
- };
2253
- const formatUptime = (ms) => {
2254
- if (ms < 60000)
2255
- return `${Math.floor(ms / 1000)}s`;
2256
- if (ms < 3600000)
2257
- return `${Math.floor(ms / 60000)}m`;
2258
- return `${Math.floor(ms / 3600000)}h ${Math.floor((ms % 3600000) / 60000)}m`;
2259
- };
2260
- const displayMetrics = (data) => {
2261
- let agents = data.agents;
2262
- if (options.agent) {
2263
- agents = agents.filter(a => a.name === options.agent);
2264
- if (agents.length === 0) {
2265
- console.error(`Agent "${options.agent}" not found`);
2266
- return;
2267
- }
2268
- }
2269
- if (options.json) {
2270
- console.log(JSON.stringify({ agents, system: data.system }, null, 2));
2271
- return;
2272
- }
2273
- if (options.watch) {
2274
- // Clear screen for watch mode
2275
- console.clear();
2276
- console.log(`Agent Metrics (updating every ${options.interval}ms) [Ctrl+C to stop]`);
2277
- console.log(`System: ${formatBytes(data.system.heapUsed)} heap / ${formatBytes(data.system.freeMemory)} free`);
2278
- console.log('');
2279
- }
2280
- if (agents.length === 0) {
2281
- console.log('No agents with memory metrics.');
2282
- console.log('Ensure agents are running and memory monitoring is enabled.');
2283
- return;
2284
- }
2285
- console.log('AGENT PID MEMORY CPU TREND ALERT UPTIME');
2286
- console.log('─'.repeat(75));
2287
- for (const agent of agents) {
2288
- const name = agent.name.padEnd(15);
2289
- const pid = (agent.pid?.toString() || '-').padEnd(8);
2290
- const memory = formatBytes(agent.rssBytes || 0).padEnd(11);
2291
- const cpu = ((agent.cpuPercent?.toFixed(1) || '0') + '%').padEnd(6);
2292
- const trend = (agent.trend || 'unknown').padEnd(11);
2293
- const alertColors = {
2294
- normal: 'normal',
2295
- warning: '\x1b[33mwarning\x1b[0m',
2296
- critical: '\x1b[31mcritical\x1b[0m',
2297
- oom_imminent: '\x1b[31;1mOOM!\x1b[0m',
2298
- };
2299
- const alert = (alertColors[agent.alertLevel || 'normal'] || agent.alertLevel || '-').padEnd(9);
2300
- const uptime = formatUptime(agent.uptimeMs || 0);
2301
- console.log(`${name} ${pid} ${memory} ${cpu} ${trend} ${alert} ${uptime}`);
2302
- }
2303
- if (!options.watch) {
2304
- console.log('');
2305
- console.log(`Total: ${agents.length} agent(s)`);
2306
- if (agents.some(a => a.alertLevel && a.alertLevel !== 'normal')) {
2307
- console.log('');
2308
- console.log('⚠️ Some agents have elevated memory usage. Run `agent-relay health` for details.');
2309
- }
2310
- }
2311
- };
2312
- if (options.watch) {
2313
- const interval = parseInt(options.interval || '5000', 10);
2314
- const update = async () => {
2315
- try {
2316
- const data = await fetchMetrics();
2317
- displayMetrics(data);
2318
- }
2319
- catch {
2320
- // Error already logged in fetchMetrics
2321
- }
2322
- };
2323
- process.on('SIGINT', () => {
2324
- console.log('\nStopped watching metrics.');
2325
- process.exit(0);
2326
- });
2327
- await update();
2328
- setInterval(update, interval);
2329
- }
2330
- else {
2331
- const data = await fetchMetrics();
2332
- displayMetrics(data);
2333
- }
2334
- });
2335
- // health - Show crash insights and system health
2336
- program
2337
- .command('health')
2338
- .description('Show system health, crash insights, and recommendations')
2339
- .option('--port <port>', 'Dashboard port', DEFAULT_DASHBOARD_PORT)
2340
- .option('--json', 'Output as JSON')
2341
- .option('--crashes', 'Show recent crash history')
2342
- .option('--alerts', 'Show unacknowledged alerts')
2343
- .action(async (options) => {
2344
- const port = options.port || DEFAULT_DASHBOARD_PORT;
2345
- try {
2346
- const response = await fetch(`http://localhost:${port}/api/metrics/health`);
2347
- if (!response.ok) {
2348
- throw new Error(`HTTP ${response.status}`);
2349
- }
2350
- const data = await response.json();
2351
- if (options.json) {
2352
- console.log(JSON.stringify(data, null, 2));
2353
- return;
2354
- }
2355
- // Health score with color
2356
- const scoreColor = data.healthScore >= 80 ? '\x1b[32m' : // Green
2357
- data.healthScore >= 50 ? '\x1b[33m' : // Yellow
2358
- '\x1b[31m'; // Red
2359
- const resetColor = '\x1b[0m';
2360
- console.log('');
2361
- console.log('═══════════════════════════════════════════════════════════════');
2362
- console.log(` SYSTEM HEALTH: ${scoreColor}${data.healthScore}/100${resetColor}`);
2363
- console.log('═══════════════════════════════════════════════════════════════');
2364
- console.log('');
2365
- console.log(` ${data.summary}`);
2366
- console.log('');
2367
- // Show stats
2368
- console.log(` Agents: ${data.stats.agentCount}`);
2369
- console.log(` Crashes (24h): ${data.stats.totalCrashes24h}`);
2370
- console.log(` Alerts (24h): ${data.stats.totalAlerts24h}`);
2371
- console.log('');
2372
- // Show issues
2373
- if (data.issues.length > 0) {
2374
- console.log(' ISSUES:');
2375
- for (const issue of data.issues) {
2376
- const icon = issue.severity === 'critical' ? '🔴' :
2377
- issue.severity === 'high' ? '🟠' :
2378
- issue.severity === 'medium' ? '🟡' : '🔵';
2379
- console.log(` ${icon} ${issue.message}`);
2380
- }
2381
- console.log('');
2382
- }
2383
- // Show recommendations
2384
- if (data.recommendations.length > 0) {
2385
- console.log(' RECOMMENDATIONS:');
2386
- for (const rec of data.recommendations) {
2387
- console.log(` → ${rec}`);
2388
- }
2389
- console.log('');
2390
- }
2391
- // Show crashes if requested
2392
- if (options.crashes && data.crashes.length > 0) {
2393
- console.log(' RECENT CRASHES:');
2394
- console.log(' ─────────────────────────────────────────────────────────────');
2395
- for (const crash of data.crashes.slice(0, 10)) {
2396
- const time = new Date(crash.crashedAt).toLocaleString();
2397
- console.log(` ${crash.agentName} - ${time}`);
2398
- console.log(` Cause: ${crash.likelyCause} | ${crash.summary.slice(0, 60)}...`);
2399
- }
2400
- console.log('');
2401
- }
2402
- // Show alerts if requested
2403
- if (options.alerts && data.alerts.length > 0) {
2404
- console.log(' UNACKNOWLEDGED ALERTS:');
2405
- console.log(' ─────────────────────────────────────────────────────────────');
2406
- for (const alert of data.alerts.slice(0, 10)) {
2407
- const _time = new Date(alert.createdAt).toLocaleString();
2408
- const icon = alert.alertType === 'oom_imminent' ? '🔴' :
2409
- alert.alertType === 'critical' ? '🟠' : '🟡';
2410
- console.log(` ${icon} ${alert.agentName} - ${alert.alertType}`);
2411
- console.log(` ${alert.message}`);
2412
- }
2413
- console.log('');
2414
- }
2415
- console.log('═══════════════════════════════════════════════════════════════');
2416
- console.log('');
2417
- if (!options.crashes && data.stats.totalCrashes24h > 0) {
2418
- console.log(' Tip: Run `agent-relay health --crashes` to see crash details');
2419
- }
2420
- if (!options.alerts && data.stats.totalAlerts24h > 0) {
2421
- console.log(' Tip: Run `agent-relay health --alerts` to see alerts');
2422
- }
2423
- console.log('');
2424
- }
2425
- catch (err) {
2426
- if (err.code === 'ECONNREFUSED') {
2427
- console.error(`Cannot connect to dashboard at port ${port}. Is the daemon running?`);
2428
- console.log(`Run 'agent-relay up' to start the daemon.`);
2429
- }
2430
- else {
2431
- console.error(`Failed to fetch health data: ${err.message}`);
2432
- }
2433
- process.exit(1);
2434
- }
2435
- });
2436
- // profile - Run agent with profiling enabled
2437
- program
2438
- .command('profile')
2439
- .description('Run an agent with memory profiling enabled')
2440
- .argument('<command...>', 'Command to profile')
2441
- .option('-n, --name <name>', 'Agent name')
2442
- .option('--heap-snapshot-interval <ms>', 'Take heap snapshots at interval (ms)', '60000')
2443
- .option('--output-dir <dir>', 'Directory for profile output', './profiles')
2444
- .option('--expose-gc', 'Expose garbage collector for manual GC')
2445
- .action(async (commandParts, options) => {
2446
- const { getProjectPaths } = await import('../utils/project-namespace.js');
2447
- if (!commandParts || commandParts.length === 0) {
2448
- console.error('No command specified');
2449
- process.exit(1);
2450
- }
2451
- const [cmd, ...args] = commandParts;
2452
- const agentName = options.name ?? generateAgentName();
2453
- const outputDir = options.outputDir || './profiles';
2454
- const snapshotInterval = parseInt(options.heapSnapshotInterval || '60000', 10);
2455
- // Create output directory
2456
- if (!fs.existsSync(outputDir)) {
2457
- fs.mkdirSync(outputDir, { recursive: true });
2458
- }
2459
- console.log('');
2460
- console.log('🔬 Agent Relay Profiler');
2461
- console.log('');
2462
- console.log(` Agent: ${agentName}`);
2463
- console.log(` Command: ${cmd} ${args.join(' ')}`);
2464
- console.log(` Output: ${outputDir}`);
2465
- console.log(` Heap snapshots: every ${snapshotInterval}ms`);
2466
- console.log('');
2467
- // Build Node.js flags for profiling
2468
- const nodeFlags = [
2469
- '--inspect', // Enable inspector
2470
- '--inspect-brk=0', // Don't actually break, just enable
2471
- ];
2472
- if (options.exposeGc) {
2473
- nodeFlags.push('--expose-gc');
2474
- }
2475
- // Set environment variables for profiling
2476
- const profileEnv = {
2477
- ...process.env,
2478
- NODE_OPTIONS: `${process.env.NODE_OPTIONS || ''} ${nodeFlags.join(' ')}`.trim(),
2479
- AGENT_RELAY_PROFILE_ENABLED: '1',
2480
- AGENT_RELAY_PROFILE_OUTPUT: outputDir,
2481
- AGENT_RELAY_PROFILE_INTERVAL: snapshotInterval.toString(),
2482
- };
2483
- console.log('Starting profiled agent...');
2484
- console.log('');
2485
- // Use the regular wrapper but with profiling environment
2486
- const paths = getProjectPaths();
2487
- const wrapper = new RelayPtyOrchestrator({
2488
- name: agentName,
2489
- command: cmd,
2490
- args,
2491
- socketPath: paths.socketPath,
2492
- cwd: paths.projectRoot,
2493
- env: profileEnv,
2494
- streamLogs: true,
2495
- });
2496
- // Start memory sampling
2497
- const sampleInterval = setInterval(() => {
2498
- const memUsage = process.memoryUsage();
2499
- const timestamp = new Date().toISOString();
2500
- const sample = {
2501
- timestamp,
2502
- heapUsed: memUsage.heapUsed,
2503
- heapTotal: memUsage.heapTotal,
2504
- external: memUsage.external,
2505
- rss: memUsage.rss,
2506
- };
2507
- // Append to samples file
2508
- const samplesFile = path.join(outputDir, `${agentName}-memory.jsonl`);
2509
- fs.appendFileSync(samplesFile, JSON.stringify(sample) + '\n');
2510
- }, 5000);
2511
- process.on('SIGINT', async () => {
2512
- clearInterval(sampleInterval);
2513
- console.log('\n');
2514
- console.log('Profiling stopped.');
2515
- console.log('');
2516
- console.log(`Profile data saved to: ${outputDir}/`);
2517
- console.log(` - ${agentName}-memory.jsonl (memory samples)`);
2518
- console.log('');
2519
- console.log('To analyze:');
2520
- console.log(` 1. Open chrome://inspect in Chrome`);
2521
- console.log(` 2. Load CPU/heap profiles from ${outputDir}/`);
2522
- console.log('');
2523
- wrapper.stop();
2524
- process.exit(0);
2525
- });
2526
- await wrapper.start();
2527
- console.log(`Profiling ${agentName}... Press Ctrl+C to stop.`);
2528
- });
2529
- // ============================================================================
2530
- // codex-auth - SSH tunnel helper for Codex/OpenAI authentication
2531
- // ============================================================================
2532
- program
2533
- .command('codex-auth')
2534
- .description('Connect Codex via SSH tunnel to workspace (run this when connecting Codex in Agent Relay)')
2535
- .option('--workspace <id>', 'Workspace ID to connect to')
2536
- .option('--cloud-url <url>', 'Cloud API URL', process.env.AGENT_RELAY_CLOUD_URL || 'https://agent-relay.com')
2537
- .option('--token <token>', 'CLI authentication token (from dashboard)')
2538
- .option('--session-cookie <cookie>', 'Session cookie for authentication (deprecated, use --token)')
2539
- .option('--timeout <seconds>', 'Timeout in seconds (default: 300)', '300')
2540
- .action(async (options) => {
2541
- const TIMEOUT_MS = parseInt(options.timeout, 10) * 1000;
2542
- const CLOUD_URL = options.cloudUrl.replace(/\/$/, '');
2543
- const TUNNEL_PORT = 1455;
2544
- // Colors for terminal output
2545
- const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
2546
- const green = (s) => `\x1b[32m${s}\x1b[0m`;
2547
- const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
2548
- const red = (s) => `\x1b[31m${s}\x1b[0m`;
2549
- const dim = (s) => `\x1b[2m${s}\x1b[0m`;
2550
- console.log('');
2551
- console.log(cyan('═══════════════════════════════════════════════════'));
2552
- console.log(cyan(' Codex Authentication Helper'));
2553
- console.log(cyan('═══════════════════════════════════════════════════'));
2554
- console.log('');
2555
- if (!options.workspace) {
2556
- console.log(red('Missing --workspace parameter.'));
2557
- console.log('');
2558
- console.log('To connect Codex, follow these steps:');
2559
- console.log('');
2560
- console.log(' 1. Go to the Agent Relay dashboard');
2561
- console.log(' 2. Click "Connect with Codex" (Settings → AI Providers)');
2562
- console.log(' 3. Copy the command shown (it includes the workspace ID and token)');
2563
- console.log(' 4. Run the command in your terminal');
2564
- console.log('');
2565
- console.log('The command will look like:');
2566
- console.log(cyan(' npx agent-relay codex-auth --workspace=<ID> --token=<TOKEN>'));
2567
- console.log('');
2568
- process.exit(1);
2569
- }
2570
- const workspaceId = options.workspace;
2571
- console.log(`Workspace: ${workspaceId.slice(0, 8)}...`);
2572
- // Get tunnel info from cloud API
2573
- console.log('Getting workspace connection info...');
2574
- const headers = { 'Content-Type': 'application/json' };
2575
- if (options.sessionCookie) {
2576
- headers['Cookie'] = options.sessionCookie;
2577
- }
2578
- // Validate token is provided
2579
- if (!options.token && !options.sessionCookie) {
2580
- console.log(red('Missing --token parameter.'));
2581
- console.log('');
2582
- console.log('The token is provided by the dashboard when you click "Connect with Codex".');
2583
- console.log('Copy the complete command from the dashboard and paste it here.');
2584
- console.log('');
2585
- process.exit(1);
2586
- }
2587
- let tunnelInfo;
2588
- try {
2589
- // Build URL with token query parameter
2590
- const tunnelInfoUrl = new URL(`${CLOUD_URL}/api/auth/codex-helper/tunnel-info/${workspaceId}`);
2591
- if (options.token) {
2592
- tunnelInfoUrl.searchParams.set('token', options.token);
2593
- }
2594
- const response = await fetch(tunnelInfoUrl.toString(), {
2595
- method: 'GET',
2596
- headers,
2597
- credentials: 'include',
2598
- });
2599
- if (!response.ok) {
2600
- const errorData = await response.json();
2601
- console.log(red(`Failed to get tunnel info: ${errorData.error || response.statusText}`));
2602
- process.exit(1);
2603
- }
2604
- tunnelInfo = await response.json();
2605
- }
2606
- catch (err) {
2607
- console.log(red(`Failed to connect to cloud API: ${err instanceof Error ? err.message : String(err)}`));
2608
- process.exit(1);
2609
- }
2610
- console.log(`Workspace: ${cyan(tunnelInfo.workspaceName)}`);
2611
- console.log('');
2612
- // Establish SSH tunnel using ssh2 library (no external tools needed)
2613
- console.log(yellow('Establishing SSH tunnel...'));
2614
- console.log(dim(` SSH: ${tunnelInfo.host}:${tunnelInfo.port}`));
2615
- console.log(dim(` Tunnel: localhost:${TUNNEL_PORT} → workspace:${tunnelInfo.tunnelPort}`));
2616
- console.log('');
2617
- const { Client } = await import('ssh2');
2618
- const net = await import('node:net');
2619
- const sshClient = new Client();
2620
- // Use object to hold server reference (avoids TypeScript narrowing issues)
2621
- const tunnel = { server: null };
2622
- let tunnelReady = false;
2623
- let tunnelError = null;
2624
- // Create a promise that resolves when tunnel is ready or rejects on error
2625
- const tunnelPromise = new Promise((resolve, reject) => {
2626
- sshClient.on('ready', () => {
2627
- // Create local server that forwards connections through SSH
2628
- tunnel.server = net.createServer((localSocket) => {
2629
- sshClient.forwardOut('127.0.0.1', TUNNEL_PORT, 'localhost', tunnelInfo.tunnelPort, (err, stream) => {
2630
- if (err) {
2631
- localSocket.end();
2632
- return;
2633
- }
2634
- localSocket.pipe(stream).pipe(localSocket);
2635
- });
2636
- });
2637
- tunnel.server.on('error', (err) => {
2638
- if (err.code === 'EADDRINUSE') {
2639
- tunnelError = `Port ${TUNNEL_PORT} is already in use. Close any other applications using this port.`;
2640
- }
2641
- else {
2642
- tunnelError = err.message;
2643
- }
2644
- reject(new Error(tunnelError));
2645
- });
2646
- tunnel.server.listen(TUNNEL_PORT, '127.0.0.1', () => {
2647
- tunnelReady = true;
2648
- resolve();
2649
- });
2650
- });
2651
- sshClient.on('error', (err) => {
2652
- if (err.message.includes('Authentication')) {
2653
- tunnelError = 'SSH authentication failed. Check the password.';
2654
- }
2655
- else if (err.message.includes('ECONNREFUSED')) {
2656
- tunnelError = `Cannot connect to SSH server at ${tunnelInfo.host}:${tunnelInfo.port}. Is the workspace running and SSH enabled?`;
2657
- }
2658
- else if (err.message.includes('ENOTFOUND') || err.message.includes('getaddrinfo')) {
2659
- tunnelError = `Cannot resolve hostname: ${tunnelInfo.host}. Check network connectivity.`;
2660
- }
2661
- else if (err.message.includes('ETIMEDOUT')) {
2662
- tunnelError = `Connection timed out to ${tunnelInfo.host}:${tunnelInfo.port}. Is the workspace running?`;
2663
- }
2664
- else {
2665
- tunnelError = `SSH error: ${err.message}`;
2666
- }
2667
- reject(new Error(tunnelError));
2668
- });
2669
- sshClient.on('close', () => {
2670
- if (!tunnelReady) {
2671
- // Only set error if not already set by error handler
2672
- if (!tunnelError) {
2673
- tunnelError = `SSH connection to ${tunnelInfo.host}:${tunnelInfo.port} closed unexpectedly. The workspace may not have SSH enabled or the port may be blocked.`;
2674
- }
2675
- reject(new Error(tunnelError));
2676
- }
2677
- });
2678
- // Connect to SSH server
2679
- sshClient.connect({
2680
- host: tunnelInfo.host,
2681
- port: tunnelInfo.port,
2682
- username: tunnelInfo.user,
2683
- password: tunnelInfo.password,
2684
- readyTimeout: 10000,
2685
- // Disable host key checking for simplicity (workspace containers)
2686
- hostVerifier: () => true,
2687
- });
2688
- });
2689
- // Wait for tunnel to establish
2690
- try {
2691
- await Promise.race([
2692
- tunnelPromise,
2693
- new Promise((_, reject) => setTimeout(() => reject(new Error('SSH connection timeout')), 15000)),
2694
- ]);
2695
- }
2696
- catch (err) {
2697
- console.log(red(`Failed to establish tunnel: ${err instanceof Error ? err.message : String(err)}`));
2698
- sshClient.end();
2699
- process.exit(1);
2700
- }
2701
- console.log(green('✓ SSH tunnel established!'));
2702
- console.log('');
2703
- // Handle Ctrl+C gracefully
2704
- const cleanup = () => {
2705
- console.log('');
2706
- console.log(dim('Shutting down...'));
2707
- if (tunnel.server) {
2708
- tunnel.server.close();
2709
- }
2710
- sshClient.end();
2711
- process.exit(0);
2712
- };
2713
- process.on('SIGINT', cleanup);
2714
- process.on('SIGTERM', cleanup);
2715
- // Display the OAuth URL
2716
- if (tunnelInfo.authUrl) {
2717
- console.log('');
2718
- console.log(green('Ready! Open this URL in your browser to complete authentication:'));
2719
- console.log('');
2720
- console.log(cyan(tunnelInfo.authUrl));
2721
- console.log('');
2722
- console.log(dim('The browser will redirect to localhost:1455, which tunnels to the workspace.'));
2723
- console.log(dim('The Codex CLI in the workspace will receive the callback and complete auth.'));
2724
- console.log('');
2725
- }
2726
- else {
2727
- console.log('');
2728
- console.log(yellow('OAuth URL not available. Please start authentication from the dashboard.'));
2729
- console.log('');
2730
- }
2731
- // Poll for authentication completion
2732
- console.log(cyan(`Waiting for authentication... (timeout: ${options.timeout}s)`));
2733
- const startTime = Date.now();
2734
- let authenticated = false;
2735
- while (!authenticated && (Date.now() - startTime) < TIMEOUT_MS) {
2736
- await new Promise(resolve => setTimeout(resolve, 3000));
2737
- try {
2738
- // Build URL with token for authentication
2739
- const authStatusUrl = new URL(`${CLOUD_URL}/api/auth/codex-helper/auth-status/${workspaceId}`);
2740
- if (options.token) {
2741
- authStatusUrl.searchParams.set('token', options.token);
2742
- }
2743
- const statusResponse = await fetch(authStatusUrl.toString(), { method: 'GET', headers, credentials: 'include' });
2744
- if (statusResponse.ok) {
2745
- const statusData = await statusResponse.json();
2746
- if (statusData.authenticated) {
2747
- authenticated = true;
2748
- }
2749
- }
2750
- }
2751
- catch {
2752
- // Ignore polling errors
2753
- }
2754
- const elapsed = Math.floor((Date.now() - startTime) / 1000);
2755
- if (!authenticated && elapsed > 0 && elapsed % 30 === 0) {
2756
- console.log(` Still waiting... (${elapsed}s)`);
2757
- }
2758
- }
2759
- // Cleanup SSH tunnel
2760
- if (tunnel.server) {
2761
- tunnel.server.close();
2762
- }
2763
- sshClient.end();
2764
- if (authenticated) {
2765
- console.log('');
2766
- console.log(green('═══════════════════════════════════════════════════'));
2767
- console.log(green(' Authentication Complete!'));
2768
- console.log(green('═══════════════════════════════════════════════════'));
2769
- console.log('');
2770
- console.log('Your Codex account is now connected to the workspace.');
2771
- console.log('You can close this terminal and return to the dashboard.');
2772
- console.log('');
2773
- }
2774
- else {
2775
- console.log('');
2776
- console.log(red('Timeout waiting for authentication.'));
2777
- console.log('');
2778
- console.log('If you completed sign-in, the workspace may not have received');
2779
- console.log('the callback. Check if the SSH tunnel was working correctly.');
2780
- process.exit(1);
2781
- }
2782
- });
2783
- program.parse();
2784
- //# sourceMappingURL=index.js.map