agent-relay 1.6.0 → 2.0.0

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