agent-relay 1.3.2 → 1.5.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 (318) hide show
  1. package/README.md +130 -158
  2. package/bin/relay-pty +0 -0
  3. package/bin/relay-pty-darwin-arm64 +0 -0
  4. package/bin/relay-pty-darwin-x64 +0 -0
  5. package/bin/relay-pty-linux-x64 +0 -0
  6. package/deploy/workspace/entrypoint.sh +9 -0
  7. package/dist/bridge/spawner.d.ts +4 -4
  8. package/dist/bridge/spawner.js +58 -92
  9. package/dist/cli/index.d.ts +8 -6
  10. package/dist/cli/index.js +282 -47
  11. package/dist/cloud/api/daemons.js +13 -32
  12. package/dist/cloud/api/onboarding.js +2 -4
  13. package/dist/cloud/api/providers.js +6 -0
  14. package/dist/cloud/config.d.ts +1 -0
  15. package/dist/cloud/config.js +2 -0
  16. package/dist/cloud/db/bulk-ingest.d.ts +2 -1
  17. package/dist/cloud/db/drizzle.d.ts +21 -26
  18. package/dist/cloud/db/drizzle.js +87 -100
  19. package/dist/cloud/db/index.d.ts +6 -5
  20. package/dist/cloud/db/index.js +9 -8
  21. package/dist/cloud/db/schema.d.ts +1049 -1076
  22. package/dist/cloud/db/schema.js +59 -71
  23. package/dist/cloud/server.js +854 -18
  24. package/dist/cloud/services/persistence.d.ts +15 -15
  25. package/dist/cloud/services/persistence.js +14 -14
  26. package/dist/daemon/agent-manager.d.ts +6 -5
  27. package/dist/daemon/agent-manager.js +12 -8
  28. package/dist/daemon/channel-membership-store.d.ts +48 -0
  29. package/dist/daemon/channel-membership-store.js +149 -0
  30. package/dist/daemon/cloud-sync.d.ts +2 -0
  31. package/dist/daemon/cloud-sync.js +4 -0
  32. package/dist/daemon/connection.js +17 -9
  33. package/dist/daemon/router.d.ts +37 -0
  34. package/dist/daemon/router.js +318 -79
  35. package/dist/daemon/server.d.ts +15 -0
  36. package/dist/daemon/server.js +141 -3
  37. package/dist/dashboard/out/404.html +1 -0
  38. package/dist/dashboard/out/_next/static/IxxVRv94L1w3ReRGAiI-k/_buildManifest.js +1 -0
  39. package/dist/dashboard/out/_next/static/IxxVRv94L1w3ReRGAiI-k/_ssgManifest.js +1 -0
  40. package/dist/dashboard/out/_next/static/chunks/116-eacf84a131b80db9.js +1 -0
  41. package/dist/dashboard/out/_next/static/chunks/117-c8afed19e821a35d.js +2 -0
  42. package/dist/dashboard/out/_next/static/chunks/282-980c2eb8fff20123.js +1 -0
  43. package/dist/dashboard/out/_next/static/chunks/532-bace199897eeab37.js +9 -0
  44. package/dist/dashboard/out/_next/static/chunks/64-87ab9cd6bcf2f737.js +1 -0
  45. package/dist/dashboard/out/_next/static/chunks/648-acb2ff9f77cbfbd3.js +1 -0
  46. package/dist/dashboard/out/_next/static/chunks/766-aa7c8c9900ff5f53.js +1 -0
  47. package/dist/dashboard/out/_next/static/chunks/83-4f08122d4e7e79a6.js +1 -0
  48. package/dist/dashboard/out/_next/static/chunks/847-f1f467060f32afff.js +1 -0
  49. package/dist/dashboard/out/_next/static/chunks/891-a024fbe4b619cf6f.js +1 -0
  50. package/dist/dashboard/out/_next/static/chunks/app/_not-found/page-60501fddbafba9dc.js +1 -0
  51. package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-f746f29e01fffc43.js +1 -0
  52. package/dist/dashboard/out/_next/static/chunks/app/app/page-ffad986adfcc8b31.js +1 -0
  53. package/dist/dashboard/out/_next/static/chunks/app/cloud/link/page-cfeb437f08a12ed9.js +1 -0
  54. package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-03ac6f35a6654ea6.js +1 -0
  55. package/dist/dashboard/out/_next/static/chunks/app/history/page-240f91e8b06ba8ac.js +1 -0
  56. package/dist/dashboard/out/_next/static/chunks/app/layout-c0d118c0f92d969c.js +1 -0
  57. package/dist/dashboard/out/_next/static/chunks/app/login/page-6ec54eee75877971.js +1 -0
  58. package/dist/dashboard/out/_next/static/chunks/app/metrics/page-82938ab8fcf44694.js +1 -0
  59. package/dist/dashboard/out/_next/static/chunks/app/page-671037943b2f2e43.js +1 -0
  60. package/dist/dashboard/out/_next/static/chunks/app/pricing/page-0efa024c28ba4597.js +1 -0
  61. package/dist/dashboard/out/_next/static/chunks/app/providers/page-57cbd738c6a73859.js +1 -0
  62. package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-5ab0854472b402b0.js +1 -0
  63. package/dist/dashboard/out/_next/static/chunks/app/signup/page-18a4665665f6be11.js +1 -0
  64. package/dist/dashboard/out/_next/static/chunks/e868780c-48e5f147c90a3a41.js +18 -0
  65. package/dist/dashboard/out/_next/static/chunks/fd9d1056-609918ca7b6280bb.js +1 -0
  66. package/dist/dashboard/out/_next/static/chunks/framework-f66176bb897dc684.js +1 -0
  67. package/dist/dashboard/out/_next/static/chunks/main-5a40a5ae29646e1b.js +1 -0
  68. package/dist/dashboard/out/_next/static/chunks/main-app-6e8e8d3ef4e0192a.js +1 -0
  69. package/dist/dashboard/out/_next/static/chunks/pages/_app-72b849fbd24ac258.js +1 -0
  70. package/dist/dashboard/out/_next/static/chunks/pages/_error-7ba65e1336b92748.js +1 -0
  71. package/dist/dashboard/out/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  72. package/dist/dashboard/out/_next/static/chunks/webpack-1cdd8ed57114d5e1.js +1 -0
  73. package/dist/dashboard/out/_next/static/css/4034f236dd1a3178.css +1 -0
  74. package/dist/dashboard/out/_next/static/css/8f9ed310f454e5a5.css +1 -0
  75. package/dist/dashboard/out/alt-logos/agent-relay-logo-128.png +0 -0
  76. package/dist/dashboard/out/alt-logos/agent-relay-logo-256.png +0 -0
  77. package/dist/dashboard/out/alt-logos/agent-relay-logo-32.png +0 -0
  78. package/dist/dashboard/out/alt-logos/agent-relay-logo-512.png +0 -0
  79. package/dist/dashboard/out/alt-logos/agent-relay-logo-64.png +0 -0
  80. package/dist/dashboard/out/alt-logos/agent-relay-logo.svg +45 -0
  81. package/dist/dashboard/out/alt-logos/logo.svg +38 -0
  82. package/dist/dashboard/out/alt-logos/monogram-logo-128.png +0 -0
  83. package/dist/dashboard/out/alt-logos/monogram-logo-256.png +0 -0
  84. package/dist/dashboard/out/alt-logos/monogram-logo-32.png +0 -0
  85. package/dist/dashboard/out/alt-logos/monogram-logo-512.png +0 -0
  86. package/dist/dashboard/out/alt-logos/monogram-logo-64.png +0 -0
  87. package/dist/dashboard/out/alt-logos/monogram-logo.svg +38 -0
  88. package/dist/dashboard/out/app/onboarding.html +1 -0
  89. package/dist/dashboard/out/app/onboarding.txt +7 -0
  90. package/dist/dashboard/out/app.html +1 -0
  91. package/dist/dashboard/out/app.txt +7 -0
  92. package/dist/dashboard/out/apple-icon.png +0 -0
  93. package/dist/dashboard/out/cloud/link.html +1 -0
  94. package/dist/dashboard/out/cloud/link.txt +7 -0
  95. package/dist/dashboard/out/connect-repos.html +1 -0
  96. package/dist/dashboard/out/connect-repos.txt +7 -0
  97. package/dist/dashboard/out/history.html +1 -0
  98. package/dist/dashboard/out/history.txt +7 -0
  99. package/dist/dashboard/out/index.html +1 -0
  100. package/dist/dashboard/out/index.txt +7 -0
  101. package/dist/dashboard/out/login.html +5 -0
  102. package/dist/dashboard/out/login.txt +7 -0
  103. package/dist/dashboard/out/metrics.html +1 -0
  104. package/dist/dashboard/out/metrics.txt +7 -0
  105. package/dist/dashboard/out/pricing.html +13 -0
  106. package/dist/dashboard/out/pricing.txt +7 -0
  107. package/dist/dashboard/out/providers/setup/claude.html +1 -0
  108. package/dist/dashboard/out/providers/setup/claude.txt +8 -0
  109. package/dist/dashboard/out/providers/setup/codex.html +1 -0
  110. package/dist/dashboard/out/providers/setup/codex.txt +8 -0
  111. package/dist/dashboard/out/providers.html +1 -0
  112. package/dist/dashboard/out/providers.txt +7 -0
  113. package/dist/dashboard/out/signup.html +6 -0
  114. package/dist/dashboard/out/signup.txt +7 -0
  115. package/dist/dashboard-server/metrics.d.ts +105 -0
  116. package/dist/dashboard-server/metrics.js +193 -0
  117. package/dist/dashboard-server/needs-attention.d.ts +24 -0
  118. package/dist/dashboard-server/needs-attention.js +78 -0
  119. package/dist/dashboard-server/server.d.ts +15 -0
  120. package/dist/dashboard-server/server.js +4753 -0
  121. package/dist/dashboard-server/start.d.ts +6 -0
  122. package/dist/dashboard-server/start.js +13 -0
  123. package/dist/dashboard-server/user-bridge.d.ts +132 -0
  124. package/dist/dashboard-server/user-bridge.js +317 -0
  125. package/dist/protocol/channels.d.ts +14 -8
  126. package/dist/protocol/channels.js +1 -1
  127. package/dist/protocol/index.d.ts +1 -0
  128. package/dist/protocol/index.js +1 -0
  129. package/dist/protocol/relay-pty-schemas.d.ts +209 -0
  130. package/dist/protocol/relay-pty-schemas.js +60 -0
  131. package/dist/wrapper/auth-detection.js +8 -1
  132. package/dist/wrapper/base-wrapper.d.ts +11 -1
  133. package/dist/wrapper/base-wrapper.js +67 -6
  134. package/dist/wrapper/client.d.ts +49 -1
  135. package/dist/wrapper/client.js +167 -0
  136. package/dist/wrapper/parser.d.ts +0 -4
  137. package/dist/wrapper/parser.js +38 -10
  138. package/dist/wrapper/pty-wrapper.d.ts +12 -1
  139. package/dist/wrapper/pty-wrapper.js +104 -5
  140. package/dist/wrapper/relay-pty-orchestrator.d.ts +270 -0
  141. package/dist/wrapper/relay-pty-orchestrator.js +970 -0
  142. package/dist/wrapper/shared.d.ts +1 -1
  143. package/dist/wrapper/shared.js +14 -4
  144. package/dist/wrapper/tmux-wrapper.d.ts +13 -1
  145. package/dist/wrapper/tmux-wrapper.js +143 -29
  146. package/package.json +9 -4
  147. package/scripts/postinstall.js +101 -11
  148. package/.trajectories/active/traj_3yx9dy148mge.json +0 -42
  149. package/.trajectories/agent-relay-322-324.md +0 -17
  150. package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.json +0 -49
  151. package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.md +0 -31
  152. package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.json +0 -125
  153. package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.md +0 -62
  154. package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.json +0 -65
  155. package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.md +0 -37
  156. package/.trajectories/completed/2026-01/traj_1g7yx6qtg4ai.json +0 -49
  157. package/.trajectories/completed/2026-01/traj_1g7yx6qtg4ai.md +0 -31
  158. package/.trajectories/completed/2026-01/traj_1k5if5snst2e.json +0 -65
  159. package/.trajectories/completed/2026-01/traj_1k5if5snst2e.md +0 -37
  160. package/.trajectories/completed/2026-01/traj_1rp3rges5811.json +0 -49
  161. package/.trajectories/completed/2026-01/traj_1rp3rges5811.md +0 -31
  162. package/.trajectories/completed/2026-01/traj_22bhyulruouw.json +0 -113
  163. package/.trajectories/completed/2026-01/traj_22bhyulruouw.md +0 -57
  164. package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.json +0 -53
  165. package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.md +0 -32
  166. package/.trajectories/completed/2026-01/traj_33iuy72sezbk.json +0 -49
  167. package/.trajectories/completed/2026-01/traj_33iuy72sezbk.md +0 -31
  168. package/.trajectories/completed/2026-01/traj_3t0440mjeunc.json +0 -26
  169. package/.trajectories/completed/2026-01/traj_3t0440mjeunc.md +0 -6
  170. package/.trajectories/completed/2026-01/traj_45x9494d9xnr.json +0 -47
  171. package/.trajectories/completed/2026-01/traj_45x9494d9xnr.md +0 -32
  172. package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.json +0 -53
  173. package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.md +0 -32
  174. package/.trajectories/completed/2026-01/traj_4qwd4zmhfwp4.json +0 -49
  175. package/.trajectories/completed/2026-01/traj_4qwd4zmhfwp4.md +0 -31
  176. package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.json +0 -77
  177. package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.md +0 -42
  178. package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.json +0 -59
  179. package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.md +0 -33
  180. package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.json +0 -53
  181. package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.md +0 -32
  182. package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.json +0 -48
  183. package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.md +0 -24
  184. package/.trajectories/completed/2026-01/traj_6mieijqyvaag.json +0 -77
  185. package/.trajectories/completed/2026-01/traj_6mieijqyvaag.md +0 -42
  186. package/.trajectories/completed/2026-01/traj_6unwwmgyj5sq.json +0 -109
  187. package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.json +0 -77
  188. package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.md +0 -42
  189. package/.trajectories/completed/2026-01/traj_7ludwvz45veh.json +0 -209
  190. package/.trajectories/completed/2026-01/traj_7ludwvz45veh.md +0 -97
  191. package/.trajectories/completed/2026-01/traj_94gnp3k30goq.json +0 -66
  192. package/.trajectories/completed/2026-01/traj_94gnp3k30goq.md +0 -36
  193. package/.trajectories/completed/2026-01/traj_9921cuhel0pj.json +0 -48
  194. package/.trajectories/completed/2026-01/traj_9921cuhel0pj.md +0 -24
  195. package/.trajectories/completed/2026-01/traj_a0tqx8biw9c4.json +0 -49
  196. package/.trajectories/completed/2026-01/traj_a0tqx8biw9c4.md +0 -31
  197. package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.json +0 -49
  198. package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.md +0 -23
  199. package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.json +0 -40
  200. package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.md +0 -22
  201. package/.trajectories/completed/2026-01/traj_ax8uungxz2qh.json +0 -66
  202. package/.trajectories/completed/2026-01/traj_ax8uungxz2qh.md +0 -36
  203. package/.trajectories/completed/2026-01/traj_c9izbh2snpzf.json +0 -49
  204. package/.trajectories/completed/2026-01/traj_c9izbh2snpzf.md +0 -31
  205. package/.trajectories/completed/2026-01/traj_cpn70dw066nt.json +0 -65
  206. package/.trajectories/completed/2026-01/traj_cpn70dw066nt.md +0 -37
  207. package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json +0 -53
  208. package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.md +0 -32
  209. package/.trajectories/completed/2026-01/traj_cxofprm2m2en.json +0 -49
  210. package/.trajectories/completed/2026-01/traj_cxofprm2m2en.md +0 -31
  211. package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.json +0 -26
  212. package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.md +0 -6
  213. package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.json +0 -121
  214. package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.md +0 -29
  215. package/.trajectories/completed/2026-01/traj_dfuvww9pege5.json +0 -59
  216. package/.trajectories/completed/2026-01/traj_dfuvww9pege5.md +0 -37
  217. package/.trajectories/completed/2026-01/traj_erglv2f8t9eh.json +0 -36
  218. package/.trajectories/completed/2026-01/traj_erglv2f8t9eh.md +0 -21
  219. package/.trajectories/completed/2026-01/traj_fhx9irlckht6.json +0 -53
  220. package/.trajectories/completed/2026-01/traj_fhx9irlckht6.md +0 -32
  221. package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.json +0 -101
  222. package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.md +0 -52
  223. package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.json +0 -77
  224. package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.md +0 -42
  225. package/.trajectories/completed/2026-01/traj_gjdre5voouod.json +0 -53
  226. package/.trajectories/completed/2026-01/traj_gjdre5voouod.md +0 -32
  227. package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.json +0 -25
  228. package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.md +0 -15
  229. package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.json +0 -101
  230. package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.md +0 -44
  231. package/.trajectories/completed/2026-01/traj_he75f24d1xfm.json +0 -101
  232. package/.trajectories/completed/2026-01/traj_he75f24d1xfm.md +0 -52
  233. package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.json +0 -49
  234. package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.md +0 -31
  235. package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.json +0 -65
  236. package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.md +0 -37
  237. package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.json +0 -22
  238. package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.md +0 -5
  239. package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.json +0 -53
  240. package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.md +0 -32
  241. package/.trajectories/completed/2026-01/traj_lgtodco7dp1n.json +0 -61
  242. package/.trajectories/completed/2026-01/traj_lgtodco7dp1n.md +0 -36
  243. package/.trajectories/completed/2026-01/traj_lq450ly148uw.json +0 -49
  244. package/.trajectories/completed/2026-01/traj_lq450ly148uw.md +0 -31
  245. package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.json +0 -25
  246. package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.md +0 -15
  247. package/.trajectories/completed/2026-01/traj_multi_server_arch.md +0 -101
  248. package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.json +0 -53
  249. package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.md +0 -32
  250. package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.json +0 -53
  251. package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.md +0 -32
  252. package/.trajectories/completed/2026-01/traj_oszg9flv74pk.json +0 -73
  253. package/.trajectories/completed/2026-01/traj_oszg9flv74pk.md +0 -41
  254. package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.json +0 -48
  255. package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.md +0 -24
  256. package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.json +0 -53
  257. package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.md +0 -32
  258. package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.json +0 -27
  259. package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.md +0 -14
  260. package/.trajectories/completed/2026-01/traj_pulomd3y8cvj.json +0 -77
  261. package/.trajectories/completed/2026-01/traj_pulomd3y8cvj.md +0 -42
  262. package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.json +0 -77
  263. package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.md +0 -42
  264. package/.trajectories/completed/2026-01/traj_qft54mi7nfor.json +0 -53
  265. package/.trajectories/completed/2026-01/traj_qft54mi7nfor.md +0 -32
  266. package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.json +0 -83
  267. package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.md +0 -47
  268. package/.trajectories/completed/2026-01/traj_rd9toccj18a0.json +0 -59
  269. package/.trajectories/completed/2026-01/traj_rd9toccj18a0.md +0 -37
  270. package/.trajectories/completed/2026-01/traj_rsavt0jipi3c.json +0 -109
  271. package/.trajectories/completed/2026-01/traj_rsavt0jipi3c.md +0 -56
  272. package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.json +0 -48
  273. package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.md +0 -16
  274. package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json +0 -59
  275. package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.md +0 -37
  276. package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.json +0 -53
  277. package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.md +0 -32
  278. package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.json +0 -84
  279. package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.md +0 -109
  280. package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.json +0 -53
  281. package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.md +0 -32
  282. package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.json +0 -53
  283. package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.md +0 -32
  284. package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.json +0 -186
  285. package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.md +0 -86
  286. package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.json +0 -77
  287. package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.md +0 -42
  288. package/.trajectories/completed/2026-01/traj_v87hypnongqx.json +0 -71
  289. package/.trajectories/completed/2026-01/traj_v87hypnongqx.md +0 -42
  290. package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.json +0 -89
  291. package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.md +0 -47
  292. package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.json +0 -53
  293. package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.md +0 -32
  294. package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.json +0 -20
  295. package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.md +0 -6
  296. package/.trajectories/completed/2026-01/traj_x721m1j9rzup.json +0 -113
  297. package/.trajectories/completed/2026-01/traj_x721m1j9rzup.md +0 -57
  298. package/.trajectories/completed/2026-01/traj_xjqvmep5ed3h.json +0 -61
  299. package/.trajectories/completed/2026-01/traj_xjqvmep5ed3h.md +0 -36
  300. package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.json +0 -175
  301. package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.md +0 -82
  302. package/.trajectories/completed/2026-01/traj_xy9vifpqet80.json +0 -65
  303. package/.trajectories/completed/2026-01/traj_xy9vifpqet80.md +0 -37
  304. package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.json +0 -49
  305. package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.md +0 -31
  306. package/.trajectories/completed/2026-01/traj_y7n6hfbf7dmg.json +0 -49
  307. package/.trajectories/completed/2026-01/traj_y7n6hfbf7dmg.md +0 -31
  308. package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.json +0 -47
  309. package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.md +0 -32
  310. package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json +0 -59
  311. package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.md +0 -37
  312. package/.trajectories/completed/2026-01/traj_yvfkwnkdiso2.json +0 -49
  313. package/.trajectories/completed/2026-01/traj_yvfkwnkdiso2.md +0 -31
  314. package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.json +0 -53
  315. package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.md +0 -32
  316. package/.trajectories/consolidate-settings-panel.md +0 -24
  317. package/.trajectories/gh-cli-user-token.md +0 -26
  318. package/.trajectories/index.json +0 -607
@@ -53,7 +53,7 @@ export declare const INJECTION_CONSTANTS: {
53
53
  /** Timeout for injection verification (ms) */
54
54
  readonly VERIFICATION_TIMEOUT_MS: 2000;
55
55
  /** Delay between message and Enter key (ms) */
56
- readonly ENTER_DELAY_MS: 50;
56
+ readonly ENTER_DELAY_MS: 100;
57
57
  /** Backoff multiplier for retries (ms per attempt) */
58
58
  readonly RETRY_BACKOFF_MS: 300;
59
59
  /** Delay between processing queued messages (ms) */
@@ -19,7 +19,7 @@ export const INJECTION_CONSTANTS = {
19
19
  /** Timeout for injection verification (ms) */
20
20
  VERIFICATION_TIMEOUT_MS: 2000,
21
21
  /** Delay between message and Enter key (ms) */
22
- ENTER_DELAY_MS: 50,
22
+ ENTER_DELAY_MS: 100,
23
23
  /** Backoff multiplier for retries (ms per attempt) */
24
24
  RETRY_BACKOFF_MS: 300,
25
25
  /** Delay between processing queued messages (ms) */
@@ -58,6 +58,11 @@ export function sleep(ms) {
58
58
  */
59
59
  export function buildInjectionString(msg) {
60
60
  const shortId = msg.messageId.substring(0, 8);
61
+ // Use senderName from data if available (for dashboard messages sent via _DashboardUI)
62
+ // This allows showing the actual GitHub username instead of the system client name
63
+ const displayFrom = (msg.from === '_DashboardUI' && typeof msg.data?.senderName === 'string')
64
+ ? msg.data.senderName
65
+ : msg.from;
61
66
  // Strip ANSI and normalize whitespace
62
67
  const sanitizedBody = stripAnsi(msg.body).replace(/[\r\n]+/g, ' ').trim();
63
68
  // Thread hint
@@ -68,8 +73,13 @@ export function buildInjectionString(msg) {
68
73
  : msg.importance !== undefined && msg.importance > 50
69
74
  ? ' [!]'
70
75
  : '';
71
- // Channel indicator for broadcasts
72
- const channelHint = msg.originalTo === '*' ? ' [#general]' : '';
76
+ // Channel indicator for channel messages and broadcasts
77
+ // originalTo will be '*' for broadcasts or the channel name (e.g., '#general') for channel messages
78
+ const channelHint = msg.originalTo === '*'
79
+ ? ' [#general]'
80
+ : msg.originalTo?.startsWith('#')
81
+ ? ` [${msg.originalTo}]`
82
+ : '';
73
83
  // Extract attachment file paths if present
74
84
  let attachmentHint = '';
75
85
  if (msg.data?.attachments && Array.isArray(msg.data.attachments)) {
@@ -80,7 +90,7 @@ export function buildInjectionString(msg) {
80
90
  attachmentHint = ` [Attachments: ${filePaths.join(', ')}]`;
81
91
  }
82
92
  }
83
- return `Relay message from ${msg.from} [${shortId}]${threadHint}${importanceHint}${channelHint}${attachmentHint}: ${sanitizedBody}`;
93
+ return `Relay message from ${displayFrom} [${shortId}]${threadHint}${importanceHint}${channelHint}${attachmentHint}: ${sanitizedBody}`;
84
94
  }
85
95
  /**
86
96
  * Calculate injection success rate from metrics
@@ -232,9 +232,16 @@ export declare class TmuxWrapper extends BaseWrapper {
232
232
  */
233
233
  private parseSessionEndAndClose;
234
234
  /**
235
- * Execute spawn via API (if dashboardPort set) or callback
235
+ * Execute spawn via API (if dashboardPort set) or callback.
236
+ * After spawning, waits for the agent to come online and sends the task via relay.
236
237
  */
237
238
  protected executeSpawn(name: string, cli: string, task: string): Promise<void>;
239
+ /**
240
+ * Wait for a spawned agent to come online, then send the task via relay.
241
+ * Uses the wrapper's own relay client so the message comes "from" this agent,
242
+ * not from the dashboard's relay client.
243
+ */
244
+ private waitAndSendTask;
238
245
  /**
239
246
  * Execute release via API (if dashboardPort set) or callback
240
247
  */
@@ -255,6 +262,11 @@ export declare class TmuxWrapper extends BaseWrapper {
255
262
  * Agents should reply to originalTo to maintain channel routing (e.g., respond to #general, not DM).
256
263
  */
257
264
  protected handleIncomingMessage(from: string, payload: SendPayload, messageId: string, meta?: SendMeta, originalTo?: string): void;
265
+ /**
266
+ * Handle incoming channel message from relay.
267
+ * Channel messages include a channel indicator so the agent knows to reply to the channel.
268
+ */
269
+ protected handleIncomingChannelMessage(from: string, channel: string, body: string, envelope: import('../protocol/types.js').Envelope<import('../protocol/channels.js').ChannelMessagePayload>): void;
258
270
  /**
259
271
  * Check if we should inject a message.
260
272
  * Uses UniversalIdleDetector (from BaseWrapper) for robust cross-CLI idle detection.
@@ -218,11 +218,18 @@ export class TmuxWrapper extends BaseWrapper {
218
218
  if (!this.config.args || this.config.args.length === 0) {
219
219
  return this.config.command;
220
220
  }
221
- // Quote any argument that contains spaces, quotes, or special chars
221
+ // Quote any argument that contains spaces, quotes, or shell special chars
222
+ // Must handle: spaces, quotes, $, <, >, |, &, ;, (, ), `, etc.
222
223
  const quotedArgs = this.config.args.map(arg => {
223
- if (arg.includes(' ') || arg.includes('"') || arg.includes("'") || arg.includes('$')) {
224
- // Use double quotes and escape internal quotes
225
- return `"${arg.replace(/"/g, '\\"')}"`;
224
+ if (/[\s"'$<>|&;()`,!\\]/.test(arg)) {
225
+ // Use double quotes and escape internal quotes and special chars
226
+ const escaped = arg
227
+ .replace(/\\/g, '\\\\')
228
+ .replace(/"/g, '\\"')
229
+ .replace(/\$/g, '\\$')
230
+ .replace(/`/g, '\\`')
231
+ .replace(/!/g, '\\!');
232
+ return `"${escaped}"`;
226
233
  }
227
234
  return arg;
228
235
  });
@@ -251,9 +258,14 @@ export class TmuxWrapper extends BaseWrapper {
251
258
  this.inbox.init();
252
259
  }
253
260
  // Connect to relay daemon (in background, don't block)
254
- this.client.connect().catch((err) => {
261
+ this.client.connect()
262
+ .then(() => {
263
+ this.logStderr(`Relay connected (state: ${this.client.state})`, true);
264
+ })
265
+ .catch((err) => {
255
266
  // Connection failures will retry via client backoff; surface once to stderr.
256
267
  this.logStderr(`Relay connect failed: ${err.message}. Will retry if enabled.`, true);
268
+ this.logStderr(`Relay client state: ${this.client.state}`, true);
257
269
  });
258
270
  // Kill any existing session with this name
259
271
  try {
@@ -330,9 +342,13 @@ export class TmuxWrapper extends BaseWrapper {
330
342
  // Wait for shell to be ready (look for prompt)
331
343
  await this.waitForShellReady();
332
344
  // Send the command to run
345
+ this.logStderr('Sending command to tmux...');
333
346
  await this.sendKeysLiteral(fullCommand);
334
- await sleep(100);
347
+ await sleep(300); // Give shell time to process the command literal
348
+ this.logStderr('Sending Enter...');
335
349
  await this.sendKeys('Enter');
350
+ await sleep(500); // Ensure Enter is processed and command starts before we continue
351
+ this.logStderr('Command sent');
336
352
  }
337
353
  catch (err) {
338
354
  throw new Error(`Failed to create tmux session: ${err.message}`);
@@ -452,6 +468,8 @@ export class TmuxWrapper extends BaseWrapper {
452
468
  async injectInstructions() {
453
469
  if (!this.running)
454
470
  return;
471
+ if (this.config.skipInstructions)
472
+ return;
455
473
  // Use escaped prefix (\->relay:) in examples to prevent parser from treating them as real commands
456
474
  const escapedPrefix = '\\' + this.relayPrefix;
457
475
  // Build instructions including relay and trail
@@ -991,20 +1009,23 @@ export class TmuxWrapper extends BaseWrapper {
991
1009
  });
992
1010
  }
993
1011
  /**
994
- * Execute spawn via API (if dashboardPort set) or callback
1012
+ * Execute spawn via API (if dashboardPort set) or callback.
1013
+ * After spawning, waits for the agent to come online and sends the task via relay.
995
1014
  */
996
1015
  async executeSpawn(name, cli, task) {
1016
+ let spawned = false;
997
1017
  if (this.config.dashboardPort) {
998
1018
  // Use dashboard API for spawning (works from any context, no terminal required)
999
1019
  try {
1000
1020
  const response = await fetch(`http://localhost:${this.config.dashboardPort}/api/spawn`, {
1001
1021
  method: 'POST',
1002
1022
  headers: { 'Content-Type': 'application/json' },
1003
- body: JSON.stringify({ name, cli, task }),
1023
+ body: JSON.stringify({ name, cli }), // No task - we send it after agent is online
1004
1024
  });
1005
1025
  const result = await response.json();
1006
1026
  if (result.success) {
1007
1027
  this.logStderr(`Spawned ${name} via API`);
1028
+ spawned = true;
1008
1029
  }
1009
1030
  else {
1010
1031
  this.logStderr(`Spawn failed: ${result.error}`, true);
@@ -1018,11 +1039,57 @@ export class TmuxWrapper extends BaseWrapper {
1018
1039
  // Fall back to callback
1019
1040
  try {
1020
1041
  await this.config.onSpawn(name, cli, task);
1042
+ spawned = true;
1021
1043
  }
1022
1044
  catch (err) {
1023
1045
  this.logStderr(`Spawn failed: ${err.message}`, true);
1024
1046
  }
1025
1047
  }
1048
+ // If spawn succeeded and we have a task, wait for agent to come online and send it
1049
+ if (spawned && task && task.trim() && this.config.dashboardPort) {
1050
+ await this.waitAndSendTask(name, task);
1051
+ }
1052
+ }
1053
+ /**
1054
+ * Wait for a spawned agent to come online, then send the task via relay.
1055
+ * Uses the wrapper's own relay client so the message comes "from" this agent,
1056
+ * not from the dashboard's relay client.
1057
+ */
1058
+ async waitAndSendTask(agentName, task) {
1059
+ const maxWaitMs = 30000;
1060
+ const pollIntervalMs = 500;
1061
+ const startTime = Date.now();
1062
+ this.logStderr(`Waiting for ${agentName} to come online...`);
1063
+ // Poll for agent to be online using dedicated status endpoint
1064
+ while (Date.now() - startTime < maxWaitMs) {
1065
+ try {
1066
+ const response = await fetch(`http://localhost:${this.config.dashboardPort}/api/agents/${encodeURIComponent(agentName)}/online`);
1067
+ const data = await response.json();
1068
+ if (data.online) {
1069
+ this.logStderr(`${agentName} is online, sending task...`);
1070
+ // Send task directly via our relay client (not dashboard API)
1071
+ // This ensures the message comes "from" this agent, not from _DashboardUI
1072
+ if (this.client.state === 'READY') {
1073
+ const sent = this.client.sendMessage(agentName, task, 'message');
1074
+ if (sent) {
1075
+ this.logStderr(`Task sent to ${agentName}`);
1076
+ }
1077
+ else {
1078
+ this.logStderr(`Failed to send task to ${agentName}: sendMessage returned false`, true);
1079
+ }
1080
+ }
1081
+ else {
1082
+ this.logStderr(`Failed to send task to ${agentName}: relay client not ready (state: ${this.client.state})`, true);
1083
+ }
1084
+ return;
1085
+ }
1086
+ }
1087
+ catch (err) {
1088
+ // Ignore poll errors, keep trying
1089
+ }
1090
+ await sleep(pollIntervalMs);
1091
+ }
1092
+ this.logStderr(`Timeout waiting for ${agentName} to come online`, true);
1026
1093
  }
1027
1094
  /**
1028
1095
  * Execute release via API (if dashboardPort set) or callback
@@ -1069,6 +1136,10 @@ export class TmuxWrapper extends BaseWrapper {
1069
1136
  // Only process if we have API or callbacks configured
1070
1137
  const canSpawn = this.config.dashboardPort || this.config.onSpawn;
1071
1138
  const canRelease = this.config.dashboardPort || this.config.onRelease;
1139
+ // Debug: Log spawn capability status
1140
+ if (content.includes('->relay:spawn')) {
1141
+ this.logStderr(`[spawn-debug] canSpawn=${!!canSpawn} dashboardPort=${this.config.dashboardPort} hasOnSpawn=${!!this.config.onSpawn}`);
1142
+ }
1072
1143
  if (!canSpawn && !canRelease)
1073
1144
  return;
1074
1145
  const lines = content.split('\n');
@@ -1079,6 +1150,12 @@ export class TmuxWrapper extends BaseWrapper {
1079
1150
  let trimmed = line.trim();
1080
1151
  // Strip common line prefixes (bullets, prompts) before checking for commands
1081
1152
  trimmed = trimmed.replace(linePrefixPattern, '');
1153
+ // Fix for over-stripping: the linePrefixPattern includes - and > characters,
1154
+ // which can accidentally strip the -> from ->relay:spawn, leaving just relay:spawn.
1155
+ // If we detect this happened, restore the -> prefix.
1156
+ if (/^(relay|thinking|continuity):/.test(trimmed)) {
1157
+ trimmed = '->' + trimmed;
1158
+ }
1082
1159
  // If we're in fenced spawn mode, accumulate lines until we see >>>
1083
1160
  if (this.pendingFencedSpawn) {
1084
1161
  // Check for fence close (>>> at end of line or on its own line)
@@ -1217,6 +1294,40 @@ export class TmuxWrapper extends BaseWrapper {
1217
1294
  // Try to inject
1218
1295
  this.checkForInjectionOpportunity();
1219
1296
  }
1297
+ /**
1298
+ * Handle incoming channel message from relay.
1299
+ * Channel messages include a channel indicator so the agent knows to reply to the channel.
1300
+ */
1301
+ handleIncomingChannelMessage(from, channel, body, envelope) {
1302
+ const messageId = envelope.id;
1303
+ if (this.hasSeenIncoming(messageId)) {
1304
+ this.logStderr(`← ${from} [${channel}]: duplicate delivery (${messageId.substring(0, 8)})`);
1305
+ return;
1306
+ }
1307
+ const truncatedBody = body.substring(0, Math.min(DEBUG_LOG_TRUNCATE_LENGTH, body.length));
1308
+ this.logStderr(`← ${from} [${channel}]: ${truncatedBody}...`);
1309
+ // Record in trajectory via trail
1310
+ this.trajectory?.message('received', from, this.config.name, body);
1311
+ // Queue for injection - include channel as originalTo so we can inform the agent how to route responses
1312
+ this.messageQueue.push({
1313
+ from,
1314
+ body,
1315
+ messageId,
1316
+ thread: envelope.payload.thread,
1317
+ data: {
1318
+ _isChannelMessage: true,
1319
+ _channel: channel,
1320
+ _mentions: envelope.payload.mentions,
1321
+ },
1322
+ originalTo: channel, // Set channel as the reply target
1323
+ });
1324
+ // Write to inbox if enabled
1325
+ if (this.inbox) {
1326
+ this.inbox.addMessage(from, body);
1327
+ }
1328
+ // Try to inject
1329
+ this.checkForInjectionOpportunity();
1330
+ }
1220
1331
  /**
1221
1332
  * Check if we should inject a message.
1222
1333
  * Uses UniversalIdleDetector (from BaseWrapper) for robust cross-CLI idle detection.
@@ -1236,11 +1347,6 @@ export class TmuxWrapper extends BaseWrapper {
1236
1347
  setTimeout(() => this.checkForInjectionOpportunity(), retryMs);
1237
1348
  return;
1238
1349
  }
1239
- // Log detection method in debug mode
1240
- if (this.config.debug && idleResult.signals.length > 0) {
1241
- const signalInfo = idleResult.signals.map(s => `${s.source}:${(s.confidence * 100).toFixed(0)}%`).join(', ');
1242
- this.logStderr(`Idle detected (${signalInfo})`);
1243
- }
1244
1350
  this.injectNextMessage();
1245
1351
  }
1246
1352
  /**
@@ -1252,19 +1358,16 @@ export class TmuxWrapper extends BaseWrapper {
1252
1358
  if (!msg)
1253
1359
  return;
1254
1360
  this.isInjecting = true;
1255
- this.logStderr(`Injecting message from ${msg.from} (cli: ${this.cliType})`);
1256
1361
  try {
1257
1362
  const shortId = msg.messageId.substring(0, 8);
1258
1363
  // Wait for input to be clear before injecting
1259
1364
  // If input is not clear (human typing), re-queue and try later - never clear forcefully!
1260
- // Fix for agent-relay-j9z: forceful clearing destroys human input in progress
1261
1365
  const waitTimeoutMs = this.config.inputWaitTimeoutMs ?? 5000;
1262
1366
  const waitPollMs = this.config.inputWaitPollMs ?? 200;
1263
1367
  const inputClear = await this.waitForClearInput(waitTimeoutMs, waitPollMs);
1264
1368
  if (!inputClear) {
1265
1369
  // Input still has text after timeout - DON'T clear forcefully, re-queue instead
1266
- // This preserves any human input in progress
1267
- this.logStderr('Input not clear after waiting, re-queuing injection to preserve human input');
1370
+ this.logStderr('Input not clear, re-queuing injection');
1268
1371
  this.messageQueue.unshift(msg);
1269
1372
  this.isInjecting = false;
1270
1373
  setTimeout(() => this.checkForInjectionOpportunity(), this.config.injectRetryMs ?? 1000);
@@ -1316,7 +1419,9 @@ export class TmuxWrapper extends BaseWrapper {
1316
1419
  }
1317
1420
  },
1318
1421
  performInjection: async (inj) => {
1319
- await this.pasteLiteral(inj);
1422
+ // Use send-keys -l (literal) instead of paste-buffer
1423
+ // paste-buffer causes issues where Claude shows "[Pasted text]" but content doesn't appear
1424
+ await this.sendKeysLiteral(inj);
1320
1425
  await sleep(INJECTION_CONSTANTS.ENTER_DELAY_MS);
1321
1426
  await this.sendKeys('Enter');
1322
1427
  },
@@ -1367,7 +1472,15 @@ export class TmuxWrapper extends BaseWrapper {
1367
1472
  * Send special keys to tmux
1368
1473
  */
1369
1474
  async sendKeys(keys) {
1370
- await execAsync(`"${this.tmuxPath}" send-keys -t ${this.sessionName} ${keys}`);
1475
+ const cmd = `"${this.tmuxPath}" send-keys -t ${this.sessionName} ${keys}`;
1476
+ try {
1477
+ await execAsync(cmd);
1478
+ this.logStderr(`[sendKeys] Sent: ${keys}`);
1479
+ }
1480
+ catch (err) {
1481
+ this.logStderr(`[sendKeys] Failed to send ${keys}: ${err.message}`, true);
1482
+ throw err;
1483
+ }
1371
1484
  }
1372
1485
  /**
1373
1486
  * Send literal text to tmux
@@ -1382,7 +1495,14 @@ export class TmuxWrapper extends BaseWrapper {
1382
1495
  .replace(/\$/g, '\\$')
1383
1496
  .replace(/`/g, '\\`')
1384
1497
  .replace(/!/g, '\\!');
1385
- await execAsync(`"${this.tmuxPath}" send-keys -t ${this.sessionName} -l "${escaped}"`);
1498
+ try {
1499
+ await execAsync(`"${this.tmuxPath}" send-keys -t ${this.sessionName} -l "${escaped}"`);
1500
+ this.logStderr(`[sendKeysLiteral] Sent ${text.length} chars`);
1501
+ }
1502
+ catch (err) {
1503
+ this.logStderr(`[sendKeysLiteral] Failed: ${err.message}`, true);
1504
+ throw err;
1505
+ }
1386
1506
  }
1387
1507
  /**
1388
1508
  * Paste text using tmux buffer with optional bracketed paste to avoid interleaving with ongoing output.
@@ -1398,15 +1518,9 @@ export class TmuxWrapper extends BaseWrapper {
1398
1518
  .replace(/`/g, '\\`')
1399
1519
  .replace(/!/g, '\\!');
1400
1520
  // Set tmux buffer then paste
1401
- // Skip bracketed paste (-p) for CLIs that don't handle it properly (droid, other)
1402
- await execAsync(`"${this.tmuxPath}" set-buffer -- "${escaped}"`);
1403
- const useBracketedPaste = this.cliType === 'claude' || this.cliType === 'codex' || this.cliType === 'gemini' || this.cliType === 'opencode';
1404
- if (useBracketedPaste) {
1405
- await execAsync(`"${this.tmuxPath}" paste-buffer -t ${this.sessionName} -p`);
1406
- }
1407
- else {
1408
- await execAsync(`"${this.tmuxPath}" paste-buffer -t ${this.sessionName}`);
1409
- }
1521
+ const setBufferCmd = `"${this.tmuxPath}" set-buffer -- "${escaped}"`;
1522
+ await execAsync(setBufferCmd);
1523
+ await execAsync(`"${this.tmuxPath}" paste-buffer -t ${this.sessionName}`);
1410
1524
  }
1411
1525
  /**
1412
1526
  * Reset session-specific state for wrapper reuse.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay",
3
- "version": "1.3.2",
3
+ "version": "1.5.0",
4
4
  "description": "Real-time agent-to-agent communication system",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -13,8 +13,9 @@
13
13
  },
14
14
  "scripts": {
15
15
  "postinstall": "npm rebuild better-sqlite3 && node scripts/postinstall.js",
16
- "build": "npm run clean && tsc",
17
- "postbuild": "chmod +x dist/cli/index.js",
16
+ "build": "npm run clean && tsc && npm run build:dashboard",
17
+ "build:dashboard": "cd src/dashboard && npm run build",
18
+ "postbuild": "chmod +x dist/cli/index.js && mkdir -p dist/dashboard && cp -r src/dashboard/out dist/dashboard/",
18
19
  "dev:watch": "tsc -w",
19
20
  "predev": "npm run clean && tsc && chmod +x dist/cli/index.js",
20
21
  "dev": "concurrently -n daemon,next -c blue,magenta \"npm run dev:daemon\" \"npm run dev:next\"",
@@ -26,6 +27,7 @@
26
27
  "dev:rebuild": "npm run build && echo '✓ Rebuilt (linked version updated)'",
27
28
  "start": "node dist/cli/index.js",
28
29
  "daemon": "node dist/daemon/server.js",
30
+ "dashboard": "node dist/dashboard-server/start.js",
29
31
  "pretest": "npm run build",
30
32
  "test": "vitest run",
31
33
  "test:integration": "vitest run test/cloud/*.integration.test.ts",
@@ -97,6 +99,9 @@
97
99
  "ws": "^8.18.3"
98
100
  },
99
101
  "devDependencies": {
102
+ "@testing-library/dom": "^10.4.1",
103
+ "@testing-library/jest-dom": "^6.9.1",
104
+ "@testing-library/react": "^14.3.1",
100
105
  "@types/better-sqlite3": "^7.6.13",
101
106
  "@types/cors": "^2.8.19",
102
107
  "@types/express": "^5.0.6",
@@ -116,7 +121,7 @@
116
121
  "eslint": "^8.57.1",
117
122
  "jsdom": "^25.0.1",
118
123
  "typescript": "^5.9.3",
119
- "vitest": "^2.1.8"
124
+ "vitest": "^2.1.9"
120
125
  },
121
126
  "engines": {
122
127
  "node": ">=18.0.0"
@@ -3,14 +3,16 @@
3
3
  * Postinstall Script for agent-relay
4
4
  *
5
5
  * This script runs after npm install to:
6
- * 1. Install dashboard dependencies
7
- * 2. Patch agent-trajectories CLI
8
- * 3. Check for tmux availability
6
+ * 1. Install relay-pty binary for current platform
7
+ * 2. Install dashboard dependencies
8
+ * 3. Patch agent-trajectories CLI
9
+ * 4. Check for tmux availability (fallback)
9
10
  */
10
11
 
11
12
  import { execSync } from 'node:child_process';
12
13
  import path from 'node:path';
13
14
  import fs from 'node:fs';
15
+ import os from 'node:os';
14
16
  import { fileURLToPath } from 'node:url';
15
17
 
16
18
  const __filename = fileURLToPath(import.meta.url);
@@ -41,6 +43,86 @@ function warn(msg) {
41
43
  console.log(`${colors.yellow}[warn]${colors.reset} ${msg}`);
42
44
  }
43
45
 
46
+ /**
47
+ * Get the platform-specific binary name for relay-pty
48
+ * Returns null if platform is not supported
49
+ */
50
+ function getRelayPtyBinaryName() {
51
+ const platform = os.platform();
52
+ const arch = os.arch();
53
+
54
+ // Map Node.js arch to Rust target arch
55
+ const archMap = {
56
+ 'arm64': 'arm64',
57
+ 'x64': 'x64',
58
+ };
59
+
60
+ // Map Node.js platform to Rust target platform
61
+ const platformMap = {
62
+ 'darwin': 'darwin',
63
+ 'linux': 'linux',
64
+ };
65
+
66
+ const targetPlatform = platformMap[platform];
67
+ const targetArch = archMap[arch];
68
+
69
+ if (!targetPlatform || !targetArch) {
70
+ return null;
71
+ }
72
+
73
+ return `relay-pty-${targetPlatform}-${targetArch}`;
74
+ }
75
+
76
+ /**
77
+ * Install the relay-pty binary for the current platform
78
+ */
79
+ function installRelayPtyBinary() {
80
+ const pkgRoot = getPackageRoot();
81
+ const binaryName = getRelayPtyBinaryName();
82
+
83
+ if (!binaryName) {
84
+ warn(`Unsupported platform: ${os.platform()}-${os.arch()}`);
85
+ warn('relay-pty binary not available, will fall back to tmux mode');
86
+ return false;
87
+ }
88
+
89
+ const sourcePath = path.join(pkgRoot, 'bin', binaryName);
90
+ const targetPath = path.join(pkgRoot, 'bin', 'relay-pty');
91
+
92
+ // Check if platform-specific binary exists
93
+ if (!fs.existsSync(sourcePath)) {
94
+ warn(`relay-pty binary not found for ${os.platform()}-${os.arch()}`);
95
+ warn('Will fall back to tmux mode');
96
+ return false;
97
+ }
98
+
99
+ // Check if already installed (and is a symlink or copy of correct binary)
100
+ if (fs.existsSync(targetPath)) {
101
+ try {
102
+ // Check if it's already the right binary by comparing size
103
+ const sourceStats = fs.statSync(sourcePath);
104
+ const targetStats = fs.statSync(targetPath);
105
+ if (sourceStats.size === targetStats.size) {
106
+ info('relay-pty binary already installed');
107
+ return true;
108
+ }
109
+ } catch {
110
+ // Continue to reinstall
111
+ }
112
+ }
113
+
114
+ // Copy the binary (symlinks don't work well across npm install)
115
+ try {
116
+ fs.copyFileSync(sourcePath, targetPath);
117
+ fs.chmodSync(targetPath, 0o755);
118
+ success(`Installed relay-pty binary for ${os.platform()}-${os.arch()}`);
119
+ return true;
120
+ } catch (err) {
121
+ warn(`Failed to install relay-pty binary: ${err.message}`);
122
+ return false;
123
+ }
124
+ }
125
+
44
126
  /**
45
127
  * Check if tmux is available on the system
46
128
  */
@@ -140,6 +222,9 @@ function patchAgentTrajectories() {
140
222
  * Main postinstall routine
141
223
  */
142
224
  async function main() {
225
+ // Install relay-pty binary for current platform (primary mode)
226
+ const hasRelayPty = installRelayPtyBinary();
227
+
143
228
  // Ensure trail CLI captures agent info on start
144
229
  patchAgentTrajectories();
145
230
 
@@ -151,18 +236,23 @@ async function main() {
151
236
  return;
152
237
  }
153
238
 
154
- // Check if system tmux is available
239
+ // If relay-pty is installed, we're good
240
+ if (hasRelayPty) {
241
+ info('Using relay-pty for agent communication (fast mode)');
242
+ return;
243
+ }
244
+
245
+ // Fall back to tmux check
155
246
  if (hasSystemTmux()) {
156
- info('System tmux found');
247
+ info('System tmux found (fallback mode)');
157
248
  return;
158
249
  }
159
250
 
160
- // Recommend user installs tmux manually
161
- warn('tmux not found on system');
162
- info('To use tmux mode, install tmux:');
163
- info(' macOS: brew install tmux');
164
- info(' Ubuntu: sudo apt install tmux');
165
- info(' Or use PTY mode via the dashboard (no tmux required)');
251
+ // Neither relay-pty nor tmux available
252
+ warn('Neither relay-pty nor tmux available');
253
+ info('Agent spawning will not work without one of:');
254
+ info(' 1. relay-pty binary (included for darwin-arm64, darwin-x64, linux-x64)');
255
+ info(' 2. tmux: brew install tmux (macOS) or apt install tmux (Linux)');
166
256
  }
167
257
 
168
258
  main().catch((err) => {
@@ -1,42 +0,0 @@
1
- {
2
- "id": "traj_3yx9dy148mge",
3
- "version": 1,
4
- "task": {
5
- "title": "Investigate agent-relay codex-auth tunnel failure"
6
- },
7
- "status": "active",
8
- "startedAt": "2026-01-10T04:02:25.981Z",
9
- "agents": [
10
- {
11
- "name": "khaliqgant",
12
- "role": "lead",
13
- "joinedAt": "2026-01-10T04:02:25.985Z"
14
- }
15
- ],
16
- "chapters": [
17
- {
18
- "id": "chap_18hrx02drpjk",
19
- "title": "Work",
20
- "agentName": "default",
21
- "startedAt": "2026-01-10T04:20:27.656Z",
22
- "events": [
23
- {
24
- "ts": 1768018827657,
25
- "type": "decision",
26
- "content": "Switched workspace SSH tunnel port to 3022: Switched workspace SSH tunnel port to 3022",
27
- "raw": {
28
- "question": "Switched workspace SSH tunnel port to 3022",
29
- "chosen": "Switched workspace SSH tunnel port to 3022",
30
- "alternatives": [],
31
- "reasoning": "sshd failed to bind 2222 in workspace; moving default tunneling port avoids conflicts"
32
- },
33
- "significance": "high"
34
- }
35
- ]
36
- }
37
- ],
38
- "commits": [],
39
- "filesChanged": [],
40
- "projectId": "/Users/khaliqgant/Projects/agent-workforce/relay",
41
- "tags": []
42
- }
@@ -1,17 +0,0 @@
1
- # Trajectory: Fix agent-relay-322 and agent-relay-324
2
-
3
- > **Status:** 🔄 Active
4
- > **Task:** agent-relay-322,agent-relay-324
5
- > **Started:** January 6, 2026 at 01:36 PM
6
-
7
- ---
8
-
9
- ## Chapters
10
-
11
- ### 1. Initial work
12
- *Agent: Fullstack*
13
-
14
- - Added buildClaudeArgs call to spawner.ts spawn() method to apply model and --agent flags from agent profiles: Added buildClaudeArgs call to spawner.ts spawn() method to apply model and --agent flags from agent profiles
15
- - Created PR #80 for agent-relay-322. Now working on agent-relay-324 - replacing ps command with /proc parsing: Created PR #80 for agent-relay-322. Now working on agent-relay-324 - replacing ps command with /proc parsing
16
- - Replaced ps command with /proc/[pid]/status parsing. VmRSS line provides resident set size in kB. CPU% left at 0 since it requires time-based sampling.: Replaced ps command with /proc/[pid]/status parsing. VmRSS line provides resident set size in kB. CPU% left at 0 since it requires time-based sampling.
17
-