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