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
@@ -82,6 +82,14 @@ export class RelayClient {
82
82
  * @param originalTo - Original 'to' field from sender (e.g., '*' for broadcasts)
83
83
  */
84
84
  onMessage;
85
+ /**
86
+ * Callback for channel messages.
87
+ * @param from - Sender name
88
+ * @param channel - Channel name
89
+ * @param body - Message content
90
+ * @param envelope - Full envelope for additional data
91
+ */
92
+ onChannelMessage;
85
93
  onStateChange;
86
94
  onError;
87
95
  constructor(config = {}) {
@@ -217,6 +225,120 @@ export class RelayClient {
217
225
  broadcast(body, kind = 'message', data) {
218
226
  return this.sendMessage('*', body, kind, data);
219
227
  }
228
+ // =============================================================================
229
+ // Channel Operations
230
+ // =============================================================================
231
+ /**
232
+ * Join a channel.
233
+ * @param channel - Channel name (e.g., '#general', 'dm:alice:bob')
234
+ * @param displayName - Optional display name for this member
235
+ */
236
+ joinChannel(channel, displayName) {
237
+ if (this._state !== 'READY') {
238
+ return false;
239
+ }
240
+ const envelope = {
241
+ v: PROTOCOL_VERSION,
242
+ type: 'CHANNEL_JOIN',
243
+ id: generateId(),
244
+ ts: Date.now(),
245
+ payload: {
246
+ channel,
247
+ displayName,
248
+ },
249
+ };
250
+ return this.send(envelope);
251
+ }
252
+ /**
253
+ * Admin join: Add any member to a channel (does not require member to be connected).
254
+ * Used by dashboard to sync channel memberships for agents.
255
+ * @param channel - Channel name (e.g., '#general')
256
+ * @param member - Name of the member to add
257
+ */
258
+ adminJoinChannel(channel, member) {
259
+ if (this._state !== 'READY') {
260
+ return false;
261
+ }
262
+ const envelope = {
263
+ v: PROTOCOL_VERSION,
264
+ type: 'CHANNEL_JOIN',
265
+ id: generateId(),
266
+ ts: Date.now(),
267
+ payload: {
268
+ channel,
269
+ member, // Admin mode: specify member to add
270
+ },
271
+ };
272
+ return this.send(envelope);
273
+ }
274
+ /**
275
+ * Leave a channel.
276
+ * @param channel - Channel name to leave
277
+ * @param reason - Optional reason for leaving
278
+ */
279
+ leaveChannel(channel, reason) {
280
+ if (this._state !== 'READY')
281
+ return false;
282
+ const envelope = {
283
+ v: PROTOCOL_VERSION,
284
+ type: 'CHANNEL_LEAVE',
285
+ id: generateId(),
286
+ ts: Date.now(),
287
+ payload: {
288
+ channel,
289
+ reason,
290
+ },
291
+ };
292
+ return this.send(envelope);
293
+ }
294
+ /**
295
+ * Admin remove: Remove any member from a channel (does not require member to be connected).
296
+ * Used by dashboard to remove channel members.
297
+ * @param channel - Channel name (e.g., '#general')
298
+ * @param member - Name of the member to remove
299
+ */
300
+ adminRemoveMember(channel, member) {
301
+ if (this._state !== 'READY') {
302
+ return false;
303
+ }
304
+ const envelope = {
305
+ v: PROTOCOL_VERSION,
306
+ type: 'CHANNEL_LEAVE',
307
+ id: generateId(),
308
+ ts: Date.now(),
309
+ payload: {
310
+ channel,
311
+ member, // Admin mode: specify member to remove
312
+ },
313
+ };
314
+ return this.send(envelope);
315
+ }
316
+ /**
317
+ * Send a message to a channel.
318
+ * @param channel - Channel name
319
+ * @param body - Message content
320
+ * @param options - Optional thread, mentions, attachments
321
+ */
322
+ sendChannelMessage(channel, body, options) {
323
+ if (this._state !== 'READY') {
324
+ return false;
325
+ }
326
+ const envelope = {
327
+ v: PROTOCOL_VERSION,
328
+ type: 'CHANNEL_MESSAGE',
329
+ id: generateId(),
330
+ ts: Date.now(),
331
+ payload: {
332
+ channel,
333
+ body,
334
+ thread: options?.thread,
335
+ mentions: options?.mentions,
336
+ attachments: options?.attachments,
337
+ data: options?.data,
338
+ },
339
+ };
340
+ return this.send(envelope);
341
+ }
220
342
  /**
221
343
  * Subscribe to a topic.
222
344
  */
@@ -395,6 +517,9 @@ export class RelayClient {
395
517
  case 'DELIVER':
396
518
  this.handleDeliver(envelope);
397
519
  break;
520
+ case 'CHANNEL_MESSAGE':
521
+ this.handleChannelMessage(envelope);
522
+ break;
398
523
  case 'PING':
399
524
  this.handlePing(envelope);
400
525
  break;
@@ -417,6 +542,7 @@ export class RelayClient {
417
542
  }
418
543
  }
419
544
  handleDeliver(envelope) {
545
+ console.log(`[relay-client:${this.config.agentName}] Received DELIVER from ${envelope.from}: "${envelope.payload.body?.substring(0, 40)}..."`);
420
546
  // Send ACK
421
547
  this.send({
422
548
  v: PROTOCOL_VERSION,
@@ -430,6 +556,7 @@ export class RelayClient {
430
556
  });
431
557
  const duplicate = this.markDelivered(envelope.id);
432
558
  if (duplicate) {
559
+ console.log(`[relay-client:${this.config.agentName}] Duplicate delivery, skipping`);
433
560
  return;
434
561
  }
435
562
  // Notify handler
@@ -437,6 +564,46 @@ export class RelayClient {
437
564
  if (this.onMessage && envelope.from) {
438
565
  this.onMessage(envelope.from, envelope.payload, envelope.id, envelope.payload_meta, envelope.delivery.originalTo);
439
566
  }
567
+ else {
568
+ console.log(`[relay-client:${this.config.agentName}] No onMessage handler or no from field`);
569
+ }
570
+ }
571
+ handleChannelMessage(envelope) {
572
+ if (!this.config.quiet) {
573
+ console.log(`[client] handleChannelMessage: from=${envelope.from}, channel=${envelope.payload.channel}`);
574
+ }
575
+ const duplicate = this.markDelivered(envelope.id);
576
+ if (duplicate) {
577
+ if (!this.config.quiet) {
578
+ console.log(`[client] handleChannelMessage: duplicate message ${envelope.id}, skipping`);
579
+ }
580
+ return;
581
+ }
582
+ // Notify channel message handler
583
+ if (this.onChannelMessage && envelope.from) {
584
+ if (!this.config.quiet) {
585
+ console.log(`[client] Calling onChannelMessage callback`);
586
+ }
587
+ this.onChannelMessage(envelope.from, envelope.payload.channel, envelope.payload.body, envelope);
588
+ }
589
+ else if (!this.config.quiet) {
590
+ console.log(`[client] No onChannelMessage handler set (handler=${!!this.onChannelMessage}, from=${envelope.from})`);
591
+ }
592
+ // Also call onMessage for backwards compatibility
593
+ // Convert to SendPayload format (channel is passed as 5th argument, not in payload)
594
+ if (this.onMessage && envelope.from) {
595
+ const sendPayload = {
596
+ kind: 'message',
597
+ body: envelope.payload.body,
598
+ data: {
599
+ _isChannelMessage: true,
600
+ _channel: envelope.payload.channel,
601
+ _mentions: envelope.payload.mentions,
602
+ },
603
+ thread: envelope.payload.thread,
604
+ };
605
+ this.onMessage(envelope.from, sendPayload, envelope.id, undefined, envelope.payload.channel);
606
+ }
440
607
  }
441
608
  handlePing(envelope) {
442
609
  this.send({
@@ -137,10 +137,6 @@ export declare class OutputParser {
137
137
  */
138
138
  reset(): void;
139
139
  }
140
- /**
141
- * Format a relay command for injection into agent input.
142
- */
143
- export declare function formatIncomingMessage(from: string, body: string, kind?: PayloadKind): string;
144
140
  /**
145
141
  * Parsed message metadata block from agent output.
146
142
  */
@@ -49,6 +49,9 @@ const MAX_INLINE_CONTINUATION_LINES = 30;
49
49
  // They are handled separately by the wrappers (pty-wrapper.ts, tmux-wrapper.ts)
50
50
  const SPAWN_COMMAND_PATTERN = /->relay:spawn\s+\S+/i;
51
51
  const RELEASE_COMMAND_PATTERN = /->relay:release\s+\S+/i;
52
+ // JSON relay format: ->relay.json:{...}
53
+ // Simple single-line format that's resilient and won't interfere with normal conversation
54
+ const JSON_RELAY_PATTERN = /->relay\.json:(\{[^\n]+\})/;
52
55
  /**
53
56
  * Check if a line is a spawn or release command that should be handled
54
57
  * by the wrapper's spawn subsystem, not parsed as a relay message.
@@ -653,9 +656,41 @@ export class OutputParser {
653
656
  const thinkingBase = this.options.thinkingPrefix.replace(/:$/, '');
654
657
  const hasRelayPattern = line.includes(relayBase) || line.includes(thinkingBase);
655
658
  const hasBlockPattern = line.includes('[[') || line.includes('```');
656
- if (!hasRelayPattern && !hasBlockPattern) {
659
+ const hasJsonRelay = line.includes('->relay.json:');
660
+ if (!hasRelayPattern && !hasBlockPattern && !hasJsonRelay) {
657
661
  return { command: null, output: line };
658
662
  }
663
+ // Check for JSON relay format first (preferred): ->relay.json:{...}
664
+ if (hasJsonRelay) {
665
+ const stripped = stripAnsi(line);
666
+ const jsonMatch = stripped.match(JSON_RELAY_PATTERN);
667
+ if (jsonMatch) {
668
+ try {
669
+ const parsed = JSON.parse(jsonMatch[1]);
670
+ const kind = parsed.kind || 'message';
671
+ // Handle different command kinds
672
+ if (kind === 'message' && parsed.to) {
673
+ return {
674
+ command: {
675
+ to: parsed.to,
676
+ kind: 'message',
677
+ body: parsed.body || '',
678
+ thread: parsed.thread,
679
+ raw: jsonMatch[0],
680
+ },
681
+ output: null,
682
+ };
683
+ }
684
+ // spawn/release are handled by the wrapper, not here
685
+ // But we still strip the line from output
686
+ return { command: null, output: null };
687
+ }
688
+ catch {
689
+ // Invalid JSON, pass through
690
+ console.error('[parser] Invalid JSON in ->relay.json:', jsonMatch[1]);
691
+ }
692
+ }
693
+ }
659
694
  // Strip ANSI codes for pattern matching (only when potentially needed)
660
695
  const stripped = stripAnsi(line);
661
696
  // Handle code fences
@@ -811,12 +846,12 @@ export class OutputParser {
811
846
  shouldFilterFencedInline(target, body) {
812
847
  // Check for placeholder target names
813
848
  if (isPlaceholderTarget(target)) {
814
- console.error(`[parser] Filtered message - placeholder target: ${target}`);
849
+ // Silently filter placeholder targets (common in documentation)
815
850
  return true;
816
851
  }
817
852
  // Check for instructional body content
818
853
  if (isInstructionalText(body)) {
819
- console.error(`[parser] Filtered message to ${target} - instructional text detected. Body preview: ${body.substring(0, 100)}`);
854
+ // Silently filter instructional text (common in system prompts)
820
855
  return true;
821
856
  }
822
857
  return false;
@@ -1049,13 +1084,6 @@ export class OutputParser {
1049
1084
  this.fencedInlineKind = 'message';
1050
1085
  }
1051
1086
  }
1052
- /**
1053
- * Format a relay command for injection into agent input.
1054
- */
1055
- export function formatIncomingMessage(from, body, kind = 'message') {
1056
- const prefix = kind === 'thinking' ? '[THINKING]' : '[MSG]';
1057
- return `\n${prefix} from ${from}: ${body}\n`;
1058
- }
1059
1087
  /**
1060
1088
  * Parse [[RELAY_METADATA]]...[[/RELAY_METADATA]] blocks from agent output.
1061
1089
  * Agents can output metadata to enhance messages.
@@ -230,9 +230,15 @@ export declare class PtyWrapper extends BaseWrapper {
230
230
  protected parseSpawnReleaseCommands(content: string): void;
231
231
  /**
232
232
  * Execute spawn via API or callback.
233
- * Overrides BaseWrapper to add PTY-specific logging and API path.
233
+ * After spawning, waits for the agent to come online and sends the task via relay.
234
234
  */
235
235
  protected executeSpawn(name: string, cli: string, task: string): Promise<void>;
236
+ /**
237
+ * Wait for a spawned agent to come online, then send the task via relay.
238
+ * Uses the wrapper's own relay client so the message comes "from" this agent,
239
+ * not from the dashboard's relay client.
240
+ */
241
+ private waitAndSendTask;
236
242
  /**
237
243
  * Execute release via API or callback.
238
244
  * Overrides BaseWrapper to add PTY-specific logging and API path.
@@ -243,6 +249,11 @@ export declare class PtyWrapper extends BaseWrapper {
243
249
  * Extends BaseWrapper to add PTY-specific behavior.
244
250
  */
245
251
  protected handleIncomingMessage(from: string, payload: SendPayload, messageId: string, meta?: SendMeta, originalTo?: string): void;
252
+ /**
253
+ * Handle incoming channel message from relay.
254
+ * Extends BaseWrapper to add PTY-specific queue processing.
255
+ */
256
+ protected handleIncomingChannelMessage(from: string, channel: string, body: string, envelope: import('../protocol/types.js').Envelope<import('../protocol/channels.js').ChannelMessagePayload>): void;
246
257
  /**
247
258
  * Wait for output to stabilize before injection.
248
259
  * Uses UniversalIdleDetector (from BaseWrapper) for robust cross-CLI idle detection.
@@ -134,8 +134,11 @@ export class PtyWrapper extends BaseWrapper {
134
134
  }
135
135
  }
136
136
  // Connect to relay daemon
137
+ const socketPath = this.config.socketPath ?? 'DEFAULT';
138
+ console.log(`[pty:${this.config.name}] Connecting to relay daemon at: ${socketPath}`);
137
139
  try {
138
140
  await this.client.connect();
141
+ console.log(`[pty:${this.config.name}] Relay connected (state: ${this.client.state})`);
139
142
  // If this is a shadow agent, bind to the primary after connecting
140
143
  if (this.config.shadowOf) {
141
144
  const speakOn = this.config.shadowSpeakOn ?? ['EXPLICIT_ASK'];
@@ -150,6 +153,7 @@ export class PtyWrapper extends BaseWrapper {
150
153
  }
151
154
  catch (err) {
152
155
  console.error(`[pty:${this.config.name}] Relay connect failed: ${err.message}`);
156
+ console.error(`[pty:${this.config.name}] Relay client state: ${this.client.state}`);
153
157
  }
154
158
  // Build command args
155
159
  const args = this.config.args ?? [];
@@ -220,6 +224,7 @@ export class PtyWrapper extends BaseWrapper {
220
224
  this.injectInstructions();
221
225
  }
222
226
  this.readyForMessages = true;
227
+ console.log(`[pty:${this.config.name}] Agent ready for messages (queueLen=${this.messageQueue.length}, interactive=${this.config.interactive})`);
223
228
  // Process any messages that arrived while waiting (skip in interactive mode)
224
229
  if (!this.config.interactive) {
225
230
  this.processMessageQueue();
@@ -228,6 +233,7 @@ export class PtyWrapper extends BaseWrapper {
228
233
  console.error(`[pty:${this.config.name}] Failed to wait for agent ready:`, err);
229
234
  // Fall back to marking ready anyway to avoid blocking forever
230
235
  this.readyForMessages = true;
236
+ console.log(`[pty:${this.config.name}] Agent ready for messages (fallback, queueLen=${this.messageQueue.length})`);
231
237
  });
232
238
  }
233
239
  /**
@@ -608,6 +614,14 @@ export class PtyWrapper extends BaseWrapper {
608
614
  // 500 chars is enough to capture most relay message headers
609
615
  const lookbackStart = Math.max(0, this.lastParsedLength - 500);
610
616
  const contentToParse = cleanContent.substring(lookbackStart);
617
+ // Debug: Check if content contains relay pattern
618
+ if (contentToParse.includes('->relay:')) {
619
+ const relayLines = contentToParse.split('\n').filter(l => l.includes('->relay:'));
620
+ console.log(`[pty:${this.config.name}] [RELAY-DEBUG] Found ${relayLines.length} lines with ->relay: pattern`);
621
+ relayLines.slice(0, 3).forEach((line, i) => {
622
+ console.log(`[pty:${this.config.name}] [RELAY-DEBUG] Line ${i}: "${line.substring(0, 80)}..."`);
623
+ });
624
+ }
611
625
  // First, try to find fenced multi-line messages: ->relay:Target <<<\n...\n>>>
612
626
  this.parseFencedMessages(contentToParse);
613
627
  // Then parse single-line messages
@@ -625,9 +639,14 @@ export class PtyWrapper extends BaseWrapper {
625
639
  // Thread is optional, can be [thread:id] or [thread:project:id] for cross-project
626
640
  const escapedPrefix = this.relayPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
627
641
  const fenceStartPattern = new RegExp(`${escapedPrefix}(\\S+)(?:\\s+\\[thread:(?:([\\w-]+):)?([\\w-]+)\\])?\\s*<<<`, 'g');
642
+ // Debug: Log if content contains relay prefix with fenced syntax
643
+ if (content.includes(this.relayPrefix) && content.includes('<<<')) {
644
+ console.error(`[pty:${this.config.name}] parseFencedMessages: Found relay+<<< in content`);
645
+ }
628
646
  let match;
629
647
  while ((match = fenceStartPattern.exec(content)) !== null) {
630
648
  const target = match[1];
649
+ console.error(`[pty:${this.config.name}] parseFencedMessages: MATCHED target=${target}`);
631
650
  const threadProject = match[2]; // Optional: project part of thread
632
651
  const threadId = match[3]; // Thread ID
633
652
  const startIdx = match.index + match[0].length;
@@ -985,22 +1004,24 @@ export class PtyWrapper extends BaseWrapper {
985
1004
  }
986
1005
  /**
987
1006
  * Execute spawn via API or callback.
988
- * Overrides BaseWrapper to add PTY-specific logging and API path.
1007
+ * After spawning, waits for the agent to come online and sends the task via relay.
989
1008
  */
990
1009
  async executeSpawn(name, cli, task) {
991
1010
  console.log(`[pty:${this.config.name}] [SPAWN-DEBUG] executeSpawn called: name=${name}, cli=${cli}, task="${task.substring(0, 50)}..."`);
992
1011
  console.log(`[pty:${this.config.name}] [SPAWN-DEBUG] dashboardPort=${this.config.dashboardPort}, hasOnSpawn=${!!this.config.onSpawn}`);
1012
+ let spawned = false;
993
1013
  if (this.config.dashboardPort) {
994
1014
  // Use dashboard API for spawning (works from spawned agents)
995
1015
  try {
996
1016
  const response = await fetch(`http://localhost:${this.config.dashboardPort}/api/spawn`, {
997
1017
  method: 'POST',
998
1018
  headers: { 'Content-Type': 'application/json' },
999
- body: JSON.stringify({ name, cli, task }),
1019
+ body: JSON.stringify({ name, cli }), // No task - we send it after agent is online
1000
1020
  });
1001
1021
  const result = await response.json();
1002
1022
  if (result.success) {
1003
1023
  console.log(`[pty:${this.config.name}] Spawned ${name} via API`);
1024
+ spawned = true;
1004
1025
  }
1005
1026
  else {
1006
1027
  console.error(`[pty:${this.config.name}] Spawn failed: ${result.error}`);
@@ -1014,11 +1035,57 @@ export class PtyWrapper extends BaseWrapper {
1014
1035
  // Fall back to callback
1015
1036
  try {
1016
1037
  await this.config.onSpawn(name, cli, task);
1038
+ spawned = true;
1017
1039
  }
1018
1040
  catch (err) {
1019
1041
  console.error(`[pty:${this.config.name}] Spawn failed: ${err.message}`);
1020
1042
  }
1021
1043
  }
1044
+ // If spawn succeeded and we have a task, wait for agent to come online and send it
1045
+ if (spawned && task && task.trim() && this.config.dashboardPort) {
1046
+ await this.waitAndSendTask(name, task);
1047
+ }
1048
+ }
1049
+ /**
1050
+ * Wait for a spawned agent to come online, then send the task via relay.
1051
+ * Uses the wrapper's own relay client so the message comes "from" this agent,
1052
+ * not from the dashboard's relay client.
1053
+ */
1054
+ async waitAndSendTask(agentName, task) {
1055
+ const maxWaitMs = 30000;
1056
+ const pollIntervalMs = 500;
1057
+ const startTime = Date.now();
1058
+ console.log(`[pty:${this.config.name}] Waiting for ${agentName} to come online...`);
1059
+ // Poll for agent to be online using dedicated status endpoint
1060
+ while (Date.now() - startTime < maxWaitMs) {
1061
+ try {
1062
+ const response = await fetch(`http://localhost:${this.config.dashboardPort}/api/agents/${encodeURIComponent(agentName)}/online`);
1063
+ const data = await response.json();
1064
+ if (data.online) {
1065
+ console.log(`[pty:${this.config.name}] ${agentName} is online, sending task...`);
1066
+ // Send task directly via our relay client (not dashboard API)
1067
+ // This ensures the message comes "from" this agent, not from _DashboardUI
1068
+ if (this.client.state === 'READY') {
1069
+ const sent = this.client.sendMessage(agentName, task, 'message');
1070
+ if (sent) {
1071
+ console.log(`[pty:${this.config.name}] Task sent to ${agentName}`);
1072
+ }
1073
+ else {
1074
+ console.error(`[pty:${this.config.name}] Failed to send task to ${agentName}: sendMessage returned false`);
1075
+ }
1076
+ }
1077
+ else {
1078
+ console.error(`[pty:${this.config.name}] Failed to send task to ${agentName}: relay client not ready (state: ${this.client.state})`);
1079
+ }
1080
+ return;
1081
+ }
1082
+ }
1083
+ catch (err) {
1084
+ // Ignore poll errors, keep trying
1085
+ }
1086
+ await sleep(pollIntervalMs);
1087
+ }
1088
+ console.error(`[pty:${this.config.name}] Timeout waiting for ${agentName} to come online`);
1022
1089
  }
1023
1090
  /**
1024
1091
  * Execute release via API or callback.
@@ -1058,6 +1125,8 @@ export class PtyWrapper extends BaseWrapper {
1058
1125
  * Extends BaseWrapper to add PTY-specific behavior.
1059
1126
  */
1060
1127
  handleIncomingMessage(from, payload, messageId, meta, originalTo) {
1128
+ const bodyPreview = payload.body.substring(0, 50).replace(/\n/g, '\\n');
1129
+ console.log(`[pty:${this.config.name}] Message received from ${from}: "${bodyPreview}..." (readyForMessages=${this.readyForMessages}, queueLen=${this.messageQueue.length})`);
1061
1130
  // Call base class to handle deduplication and queuing
1062
1131
  super.handleIncomingMessage(from, payload, messageId, meta, originalTo);
1063
1132
  // PTY-specific: Process the message queue immediately
@@ -1067,6 +1136,20 @@ export class PtyWrapper extends BaseWrapper {
1067
1136
  console.error(`[pty:${this.config.name}] Message received hook error:`, err);
1068
1137
  });
1069
1138
  }
1139
+ /**
1140
+ * Handle incoming channel message from relay.
1141
+ * Extends BaseWrapper to add PTY-specific queue processing.
1142
+ */
1143
+ handleIncomingChannelMessage(from, channel, body, envelope) {
1144
+ // Call base class to handle deduplication and queuing
1145
+ super.handleIncomingChannelMessage(from, channel, body, envelope);
1146
+ // PTY-specific: Process the message queue immediately
1147
+ this.processMessageQueue();
1148
+ // PTY-specific: Dispatch message received hook with channel info
1149
+ this.hookRegistry.dispatchMessageReceived(from, body, envelope.id).catch(err => {
1150
+ console.error(`[pty:${this.config.name}] Channel message received hook error:`, err);
1151
+ });
1152
+ }
1070
1153
  /**
1071
1154
  * Wait for output to stabilize before injection.
1072
1155
  * Uses UniversalIdleDetector (from BaseWrapper) for robust cross-CLI idle detection.
@@ -1114,6 +1197,8 @@ export class PtyWrapper extends BaseWrapper {
1114
1197
  this.isInjecting = false;
1115
1198
  return;
1116
1199
  }
1200
+ const bodyPreview = msg.body.substring(0, 50).replace(/\n/g, '\\n');
1201
+ console.log(`[pty:${this.config.name}] Processing message from ${msg.from}: "${bodyPreview}..." (remaining=${this.messageQueue.length})`);
1117
1202
  try {
1118
1203
  // Wait for output to stabilize before injecting
1119
1204
  await this.waitForOutputStable();
@@ -1152,9 +1237,21 @@ export class PtyWrapper extends BaseWrapper {
1152
1237
  if (!this.ptyProcess || !this.running) {
1153
1238
  throw new Error('PTY process not running');
1154
1239
  }
1155
- // Write message to PTY, then send Enter separately after a small delay
1156
- this.ptyProcess.write(inj);
1157
- await sleep(INJECTION_CONSTANTS.ENTER_DELAY_MS);
1240
+ // Use bracketed paste mode for CLIs that support it (claude, codex, gemini)
1241
+ // This prevents interleaving with CLI output and ensures clean input
1242
+ const useBracketedPaste = this.cliType === 'claude' || this.cliType === 'codex' || this.cliType === 'gemini';
1243
+ if (useBracketedPaste) {
1244
+ // Bracketed paste: \x1b[200~ starts paste, \x1b[201~ ends paste
1245
+ this.ptyProcess.write('\x1b[200~' + inj + '\x1b[201~');
1246
+ }
1247
+ else {
1248
+ this.ptyProcess.write(inj);
1249
+ }
1250
+ // Wait longer for CLI to process the pasted content before sending Enter.
1251
+ // The standard 50ms delay is too short for CLIs like Claude that need time
1252
+ // to process bracketed paste content before accepting Enter.
1253
+ await sleep(200);
1254
+ // Send Enter key - use \r for PTY (carriage return)
1158
1255
  this.ptyProcess.write('\r');
1159
1256
  },
1160
1257
  log: (message) => console.log(`[pty:${this.config.name}] ${message}`),
@@ -1199,6 +1296,8 @@ export class PtyWrapper extends BaseWrapper {
1199
1296
  injectInstructions() {
1200
1297
  if (!this.running)
1201
1298
  return;
1299
+ if (this.config.skipInstructions)
1300
+ return;
1202
1301
  // Guard: Only inject once per session
1203
1302
  if (this.instructionsInjected) {
1204
1303
  console.log(`[pty:${this.config.name}] Init instructions already injected, skipping`);