agent-relay 2.3.13 → 2.4.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 (1421) hide show
  1. package/README.md +42 -176
  2. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  3. package/bin/agent-relay-broker-darwin-x64 +0 -0
  4. package/bin/agent-relay-broker-linux-arm64 +0 -0
  5. package/bin/agent-relay-broker-linux-x64 +0 -0
  6. package/dist/index.cjs +50288 -63371
  7. package/dist/src/cli/bootstrap.d.ts +6 -0
  8. package/dist/src/cli/bootstrap.d.ts.map +1 -0
  9. package/dist/src/cli/bootstrap.js +109 -0
  10. package/dist/src/cli/bootstrap.js.map +1 -0
  11. package/dist/src/cli/commands/agent-management.d.ts +51 -0
  12. package/dist/src/cli/commands/agent-management.d.ts.map +1 -0
  13. package/dist/src/cli/commands/agent-management.js +290 -0
  14. package/dist/src/cli/commands/agent-management.js.map +1 -0
  15. package/dist/src/cli/commands/auth.d.ts +9 -0
  16. package/dist/src/cli/commands/auth.d.ts.map +1 -0
  17. package/dist/src/cli/commands/auth.js +33 -0
  18. package/dist/src/cli/commands/auth.js.map +1 -0
  19. package/dist/src/cli/commands/cloud.d.ts +18 -0
  20. package/dist/src/cli/commands/cloud.d.ts.map +1 -0
  21. package/dist/src/cli/commands/cloud.js +392 -0
  22. package/dist/src/cli/commands/cloud.js.map +1 -0
  23. package/dist/src/cli/commands/core.d.ts +107 -0
  24. package/dist/src/cli/commands/core.d.ts.map +1 -0
  25. package/dist/src/cli/commands/core.js +299 -0
  26. package/dist/src/cli/commands/core.js.map +1 -0
  27. package/dist/src/cli/commands/doctor.d.ts +1 -1
  28. package/dist/src/cli/commands/doctor.d.ts.map +1 -1
  29. package/dist/src/cli/commands/doctor.js +1 -485
  30. package/dist/src/cli/commands/doctor.js.map +1 -1
  31. package/dist/src/cli/commands/messaging.d.ts +61 -0
  32. package/dist/src/cli/commands/messaging.d.ts.map +1 -0
  33. package/dist/src/cli/commands/messaging.js +213 -0
  34. package/dist/src/cli/commands/messaging.js.map +1 -0
  35. package/dist/src/cli/commands/monitoring.d.ts +57 -0
  36. package/dist/src/cli/commands/monitoring.d.ts.map +1 -0
  37. package/dist/src/cli/commands/monitoring.js +350 -0
  38. package/dist/src/cli/commands/monitoring.js.map +1 -0
  39. package/dist/src/cli/commands/setup.d.ts +29 -0
  40. package/dist/src/cli/commands/setup.d.ts.map +1 -0
  41. package/dist/src/cli/commands/setup.js +324 -0
  42. package/dist/src/cli/commands/setup.js.map +1 -0
  43. package/dist/src/cli/commands/swarm.d.ts +3 -0
  44. package/dist/src/cli/commands/swarm.d.ts.map +1 -0
  45. package/dist/src/cli/commands/swarm.js +108 -0
  46. package/dist/src/cli/commands/swarm.js.map +1 -0
  47. package/dist/src/cli/index.d.ts +1 -28
  48. package/dist/src/cli/index.d.ts.map +1 -1
  49. package/dist/src/cli/index.js +4 -4936
  50. package/dist/src/cli/index.js.map +1 -1
  51. package/dist/src/cli/lib/agent-management-listing.d.ts +39 -0
  52. package/dist/src/cli/lib/agent-management-listing.d.ts.map +1 -0
  53. package/dist/src/cli/lib/agent-management-listing.js +253 -0
  54. package/dist/src/cli/lib/agent-management-listing.js.map +1 -0
  55. package/dist/src/cli/lib/auth-ssh.d.ts +48 -0
  56. package/dist/src/cli/lib/auth-ssh.d.ts.map +1 -0
  57. package/dist/src/cli/lib/auth-ssh.js +572 -0
  58. package/dist/src/cli/lib/auth-ssh.js.map +1 -0
  59. package/dist/src/cli/lib/bridge.d.ts +8 -0
  60. package/dist/src/cli/lib/bridge.d.ts.map +1 -0
  61. package/dist/src/cli/lib/bridge.js +100 -0
  62. package/dist/src/cli/lib/bridge.js.map +1 -0
  63. package/dist/src/cli/lib/broker-lifecycle.d.ts +20 -0
  64. package/dist/src/cli/lib/broker-lifecycle.d.ts.map +1 -0
  65. package/dist/src/cli/lib/broker-lifecycle.js +843 -0
  66. package/dist/src/cli/lib/broker-lifecycle.js.map +1 -0
  67. package/dist/src/cli/lib/client-factory.d.ts +24 -0
  68. package/dist/src/cli/lib/client-factory.d.ts.map +1 -0
  69. package/dist/src/cli/lib/client-factory.js +20 -0
  70. package/dist/src/cli/lib/client-factory.js.map +1 -0
  71. package/dist/src/cli/lib/cloud-client.d.ts +39 -0
  72. package/dist/src/cli/lib/cloud-client.d.ts.map +1 -0
  73. package/dist/src/cli/lib/cloud-client.js +120 -0
  74. package/dist/src/cli/lib/cloud-client.js.map +1 -0
  75. package/dist/src/cli/lib/core-maintenance.d.ts +13 -0
  76. package/dist/src/cli/lib/core-maintenance.d.ts.map +1 -0
  77. package/dist/src/cli/lib/core-maintenance.js +250 -0
  78. package/dist/src/cli/lib/core-maintenance.js.map +1 -0
  79. package/dist/src/cli/lib/doctor.d.ts +2 -0
  80. package/dist/src/cli/lib/doctor.d.ts.map +1 -0
  81. package/dist/src/cli/lib/doctor.js +484 -0
  82. package/dist/src/cli/lib/doctor.js.map +1 -0
  83. package/dist/src/cli/lib/formatting.d.ts +8 -0
  84. package/dist/src/cli/lib/formatting.d.ts.map +1 -0
  85. package/dist/src/cli/lib/formatting.js +48 -0
  86. package/dist/src/cli/lib/formatting.js.map +1 -0
  87. package/dist/src/cli/lib/index.d.ts +5 -0
  88. package/dist/src/cli/lib/index.d.ts.map +1 -0
  89. package/dist/src/cli/lib/index.js +5 -0
  90. package/dist/src/cli/lib/index.js.map +1 -0
  91. package/dist/src/cli/lib/jsonc.d.ts +8 -0
  92. package/dist/src/cli/lib/jsonc.d.ts.map +1 -0
  93. package/dist/src/cli/lib/jsonc.js +88 -0
  94. package/dist/src/cli/lib/jsonc.js.map +1 -0
  95. package/dist/src/cli/lib/monitoring-health.d.ts +32 -0
  96. package/dist/src/cli/lib/monitoring-health.d.ts.map +1 -0
  97. package/dist/src/cli/lib/monitoring-health.js +2 -0
  98. package/dist/src/cli/lib/monitoring-health.js.map +1 -0
  99. package/dist/src/cli/lib/paths.d.ts +2 -0
  100. package/dist/src/cli/lib/paths.d.ts.map +1 -0
  101. package/dist/src/cli/lib/paths.js +5 -0
  102. package/dist/src/cli/lib/paths.js.map +1 -0
  103. package/dist/src/index.d.ts +1 -5
  104. package/dist/src/index.d.ts.map +1 -1
  105. package/dist/src/index.js +1 -5
  106. package/dist/src/index.js.map +1 -1
  107. package/install.sh +0 -30
  108. package/package.json +84 -98
  109. package/packages/acp-bridge/README.md +8 -8
  110. package/packages/acp-bridge/dist/acp-agent.d.ts +8 -7
  111. package/packages/acp-bridge/dist/acp-agent.d.ts.map +1 -1
  112. package/packages/acp-bridge/dist/acp-agent.js +118 -143
  113. package/packages/acp-bridge/dist/acp-agent.js.map +1 -1
  114. package/packages/acp-bridge/dist/cli.d.ts +1 -1
  115. package/packages/acp-bridge/dist/cli.js +3 -3
  116. package/packages/acp-bridge/dist/index.d.ts +2 -2
  117. package/packages/acp-bridge/dist/index.d.ts.map +1 -1
  118. package/packages/acp-bridge/dist/index.js +1 -1
  119. package/packages/acp-bridge/dist/index.js.map +1 -1
  120. package/packages/acp-bridge/dist/types.d.ts +3 -3
  121. package/packages/acp-bridge/package.json +3 -3
  122. package/packages/acp-bridge/src/acp-agent.ts +123 -160
  123. package/packages/acp-bridge/src/cli.ts +3 -3
  124. package/packages/acp-bridge/src/index.ts +2 -2
  125. package/packages/acp-bridge/src/types.ts +3 -3
  126. package/packages/config/dist/bridge-config.d.ts +5 -5
  127. package/packages/config/dist/bridge-config.d.ts.map +1 -1
  128. package/packages/config/dist/bridge-config.js +16 -9
  129. package/packages/config/dist/bridge-config.js.map +1 -1
  130. package/packages/config/dist/cli-auth-config.d.ts +1 -1
  131. package/packages/config/dist/cli-auth-config.js +1 -1
  132. package/packages/config/dist/cli-registry.generated.d.ts +340 -0
  133. package/packages/config/dist/cli-registry.generated.d.ts.map +1 -0
  134. package/packages/config/dist/cli-registry.generated.js +297 -0
  135. package/packages/config/dist/cli-registry.generated.js.map +1 -0
  136. package/packages/config/dist/index.d.ts +1 -0
  137. package/packages/config/dist/index.d.ts.map +1 -1
  138. package/packages/config/dist/index.js +1 -0
  139. package/packages/config/dist/index.js.map +1 -1
  140. package/packages/config/dist/project-namespace.d.ts +9 -9
  141. package/packages/config/dist/project-namespace.js +3 -3
  142. package/packages/config/dist/relay-config.d.ts +1 -1
  143. package/packages/config/dist/relay-config.js +1 -1
  144. package/packages/config/dist/schemas.js +1 -1
  145. package/packages/config/dist/shadow-config.d.ts +2 -1
  146. package/packages/config/dist/shadow-config.d.ts.map +1 -1
  147. package/packages/config/dist/shadow-config.js.map +1 -1
  148. package/packages/config/package.json +2 -3
  149. package/packages/config/src/bridge-config.test.ts +20 -6
  150. package/packages/config/src/bridge-config.ts +20 -10
  151. package/packages/config/src/cli-auth-config.ts +1 -1
  152. package/packages/config/src/cli-registry.generated.ts +328 -0
  153. package/packages/config/src/index.ts +1 -0
  154. package/packages/config/src/project-namespace.ts +9 -9
  155. package/packages/config/src/relay-config.ts +1 -1
  156. package/packages/config/src/schemas.ts +1 -1
  157. package/packages/config/src/shadow-config.ts +8 -1
  158. package/packages/contracts/fixtures/error-fixtures.json +42 -0
  159. package/packages/contracts/fixtures/event-fixtures.json +161 -0
  160. package/packages/contracts/fixtures/health-fixtures.json +35 -0
  161. package/packages/contracts/fixtures/identity-fixtures.json +58 -0
  162. package/packages/contracts/fixtures/replay-fixtures.json +33 -0
  163. package/packages/hooks/dist/inbox-check/types.d.ts +2 -2
  164. package/packages/hooks/dist/types.d.ts +9 -3
  165. package/packages/hooks/dist/types.d.ts.map +1 -1
  166. package/packages/hooks/dist/types.js +1 -1
  167. package/packages/hooks/dist/types.js.map +1 -1
  168. package/packages/hooks/package.json +5 -5
  169. package/packages/hooks/src/inbox-check/types.ts +2 -2
  170. package/packages/hooks/src/types.ts +11 -3
  171. package/packages/memory/package.json +2 -2
  172. package/packages/policy/package.json +2 -2
  173. package/packages/sdk/.mcp.json +14 -0
  174. package/packages/sdk/.trajectories/active/traj_1771875803391_84ca57b2.json +50 -0
  175. package/packages/sdk/.trajectories/active/traj_1771891934534_06504121.json +50 -0
  176. package/packages/sdk/.trajectories/active/traj_1771891957929_211afc4e.json +50 -0
  177. package/packages/sdk/.trajectories/active/traj_1771891982509_38c84638.json +50 -0
  178. package/packages/sdk/.trajectories/completed/traj_1771875803188_cd6d181c.json +80 -0
  179. package/packages/sdk/.trajectories/completed/traj_1771875803204_f2aeb8c8.json +80 -0
  180. package/packages/sdk/.trajectories/completed/traj_1771875803210_d65f3f1a.json +80 -0
  181. package/packages/sdk/.trajectories/completed/traj_1771875803218_e454a25d.json +80 -0
  182. package/packages/sdk/.trajectories/completed/traj_1771875803223_d7a64815.json +80 -0
  183. package/packages/sdk/.trajectories/completed/traj_1771875803227_7e56da5b.json +80 -0
  184. package/packages/sdk/.trajectories/completed/traj_1771875803235_4fbf93b4.json +80 -0
  185. package/packages/sdk/.trajectories/completed/traj_1771875803243_47931c71.json +80 -0
  186. package/packages/sdk/.trajectories/completed/traj_1771875803258_3816f3fe.json +80 -0
  187. package/packages/sdk/.trajectories/completed/traj_1771875803268_8061140e.json +80 -0
  188. package/packages/sdk/.trajectories/completed/traj_1771875803326_ae6f9c78.json +80 -0
  189. package/packages/sdk/.trajectories/completed/traj_1771875808396_cbde0a6c.json +91 -0
  190. package/packages/sdk/.trajectories/completed/traj_1771875812026_aa2442bb.json +91 -0
  191. package/packages/sdk/.trajectories/completed/traj_1771875815431_c2c656c5.json +91 -0
  192. package/packages/sdk/.trajectories/completed/traj_1771875818645_3a4dbf02.json +91 -0
  193. package/packages/sdk/.trajectories/completed/traj_1771891934403_24923c03.json +80 -0
  194. package/packages/sdk/.trajectories/completed/traj_1771891934421_dca16e24.json +80 -0
  195. package/packages/sdk/.trajectories/completed/traj_1771891934430_057706f7.json +80 -0
  196. package/packages/sdk/.trajectories/completed/traj_1771891934442_faf97382.json +80 -0
  197. package/packages/sdk/.trajectories/completed/traj_1771891934454_5542ecd5.json +80 -0
  198. package/packages/sdk/.trajectories/completed/traj_1771891934464_12202a08.json +80 -0
  199. package/packages/sdk/.trajectories/completed/traj_1771891934487_94378275.json +80 -0
  200. package/packages/sdk/.trajectories/completed/traj_1771891934503_ca728c13.json +80 -0
  201. package/packages/sdk/.trajectories/completed/traj_1771891934519_100af69a.json +80 -0
  202. package/packages/sdk/.trajectories/completed/traj_1771891934536_62ad39d9.json +80 -0
  203. package/packages/sdk/.trajectories/completed/traj_1771891934553_d6798a52.json +80 -0
  204. package/packages/sdk/.trajectories/completed/traj_1771891939537_541c8096.json +91 -0
  205. package/packages/sdk/.trajectories/completed/traj_1771891942985_36ab9a4d.json +91 -0
  206. package/packages/sdk/.trajectories/completed/traj_1771891946453_e8a6e05f.json +91 -0
  207. package/packages/sdk/.trajectories/completed/traj_1771891949838_5de0de84.json +91 -0
  208. package/packages/sdk/.trajectories/completed/traj_1771891957807_0ecfb4f4.json +80 -0
  209. package/packages/sdk/.trajectories/completed/traj_1771891957827_c4539239.json +80 -0
  210. package/packages/sdk/.trajectories/completed/traj_1771891957836_91168b48.json +80 -0
  211. package/packages/sdk/.trajectories/completed/traj_1771891957848_8c5cad0b.json +80 -0
  212. package/packages/sdk/.trajectories/completed/traj_1771891957857_0986b293.json +80 -0
  213. package/packages/sdk/.trajectories/completed/traj_1771891957872_8a3113af.json +80 -0
  214. package/packages/sdk/.trajectories/completed/traj_1771891957884_0bb85208.json +80 -0
  215. package/packages/sdk/.trajectories/completed/traj_1771891957892_86c75e2e.json +80 -0
  216. package/packages/sdk/.trajectories/completed/traj_1771891957907_98ca0e6f.json +80 -0
  217. package/packages/sdk/.trajectories/completed/traj_1771891957918_d9091231.json +80 -0
  218. package/packages/sdk/.trajectories/completed/traj_1771891957931_dcaf77ed.json +80 -0
  219. package/packages/sdk/.trajectories/completed/traj_1771891962931_eb1fdee2.json +91 -0
  220. package/packages/sdk/.trajectories/completed/traj_1771891966262_9061a93f.json +91 -0
  221. package/packages/sdk/.trajectories/completed/traj_1771891969915_1adaba19.json +91 -0
  222. package/packages/sdk/.trajectories/completed/traj_1771891973588_f08b79e9.json +91 -0
  223. package/packages/sdk/.trajectories/completed/traj_1771891982421_f1985bce.json +80 -0
  224. package/packages/sdk/.trajectories/completed/traj_1771891982432_e7a84163.json +80 -0
  225. package/packages/sdk/.trajectories/completed/traj_1771891982447_369b842a.json +80 -0
  226. package/packages/sdk/.trajectories/completed/traj_1771891982469_5fc45199.json +80 -0
  227. package/packages/sdk/.trajectories/completed/traj_1771891982495_454c7cb3.json +80 -0
  228. package/packages/sdk/.trajectories/completed/traj_1771891982514_08098e03.json +80 -0
  229. package/packages/sdk/.trajectories/completed/traj_1771891982526_b351d778.json +80 -0
  230. package/packages/sdk/.trajectories/completed/traj_1771891982533_fa542d83.json +80 -0
  231. package/packages/sdk/.trajectories/completed/traj_1771891982540_18ab24dc.json +80 -0
  232. package/packages/sdk/.trajectories/completed/traj_1771891982544_5b4fa163.json +80 -0
  233. package/packages/sdk/.trajectories/completed/traj_1771891982548_c13f089a.json +80 -0
  234. package/packages/sdk/.trajectories/completed/traj_1771891987510_23f6da1f.json +91 -0
  235. package/packages/sdk/.trajectories/completed/traj_1771891991466_912c2e04.json +91 -0
  236. package/packages/sdk/.trajectories/completed/traj_1771891994891_60604be2.json +91 -0
  237. package/packages/sdk/.trajectories/completed/traj_1771891998370_cfaf9b8b.json +91 -0
  238. package/packages/sdk/README.md +68 -838
  239. package/packages/sdk/bin/agent-relay-broker +0 -0
  240. package/packages/sdk/dist/__tests__/contract-fixtures.test.d.ts +2 -0
  241. package/packages/sdk/dist/__tests__/contract-fixtures.test.d.ts.map +1 -0
  242. package/packages/sdk/dist/__tests__/contract-fixtures.test.js +85 -0
  243. package/packages/sdk/dist/__tests__/contract-fixtures.test.js.map +1 -0
  244. package/packages/sdk/dist/__tests__/facade.test.js +305 -0
  245. package/packages/sdk/dist/__tests__/facade.test.js.map +1 -0
  246. package/packages/sdk/dist/__tests__/integration.test.js +169 -0
  247. package/packages/sdk/dist/__tests__/integration.test.js.map +1 -0
  248. package/packages/sdk/dist/__tests__/pty.test.d.ts +2 -0
  249. package/packages/sdk/dist/__tests__/pty.test.d.ts.map +1 -0
  250. package/packages/sdk/dist/__tests__/pty.test.js +20 -0
  251. package/packages/sdk/dist/__tests__/pty.test.js.map +1 -0
  252. package/packages/sdk/dist/__tests__/quickstart.test.js +176 -0
  253. package/packages/sdk/dist/__tests__/quickstart.test.js.map +1 -0
  254. package/packages/sdk/dist/__tests__/spawn-from-env.test.d.ts +2 -0
  255. package/packages/sdk/dist/__tests__/spawn-from-env.test.d.ts.map +1 -0
  256. package/packages/sdk/dist/__tests__/spawn-from-env.test.js +206 -0
  257. package/packages/sdk/dist/__tests__/spawn-from-env.test.js.map +1 -0
  258. package/packages/sdk/dist/__tests__/unit.test.js +347 -0
  259. package/packages/sdk/dist/__tests__/unit.test.js.map +1 -0
  260. package/packages/sdk/dist/client.d.ts +140 -526
  261. package/packages/sdk/dist/client.d.ts.map +1 -1
  262. package/packages/sdk/dist/client.js +416 -1509
  263. package/packages/sdk/dist/client.js.map +1 -1
  264. package/packages/sdk/dist/examples/workflow-superiority.d.ts +32 -0
  265. package/packages/sdk/dist/examples/workflow-superiority.d.ts.map +1 -0
  266. package/packages/sdk/dist/examples/workflow-superiority.js +1421 -0
  267. package/packages/sdk/dist/examples/workflow-superiority.js.map +1 -0
  268. package/packages/sdk/dist/index.d.ts +13 -20
  269. package/packages/sdk/dist/index.d.ts.map +1 -1
  270. package/packages/sdk/dist/index.js +12 -26
  271. package/packages/sdk/dist/index.js.map +1 -1
  272. package/packages/sdk/dist/logs.d.ts +70 -25
  273. package/packages/sdk/dist/logs.d.ts.map +1 -1
  274. package/packages/sdk/dist/logs.js +238 -42
  275. package/packages/sdk/dist/logs.js.map +1 -1
  276. package/packages/sdk/dist/models.d.ts +9 -0
  277. package/packages/sdk/dist/models.d.ts.map +1 -0
  278. package/packages/sdk/dist/models.js +17 -0
  279. package/packages/sdk/dist/models.js.map +1 -0
  280. package/packages/sdk/dist/protocol.d.ts +366 -0
  281. package/packages/sdk/dist/protocol.d.ts.map +1 -0
  282. package/packages/sdk/dist/pty.d.ts.map +1 -0
  283. package/packages/sdk/dist/pty.js +26 -0
  284. package/packages/sdk/dist/pty.js.map +1 -0
  285. package/packages/sdk/dist/relay-adapter.d.ts +139 -0
  286. package/packages/sdk/dist/relay-adapter.d.ts.map +1 -0
  287. package/packages/sdk/dist/relay-adapter.js +210 -0
  288. package/packages/sdk/dist/relay-adapter.js.map +1 -0
  289. package/packages/sdk/dist/relay.d.ts +304 -0
  290. package/packages/sdk/dist/relay.d.ts.map +1 -0
  291. package/packages/sdk/dist/relay.js +910 -0
  292. package/packages/sdk/dist/relay.js.map +1 -0
  293. package/packages/sdk/dist/shadow.d.ts +101 -0
  294. package/packages/sdk/dist/shadow.d.ts.map +1 -0
  295. package/packages/sdk/dist/shadow.js.map +1 -0
  296. package/packages/sdk/dist/spawn-from-env.d.ts +77 -0
  297. package/packages/sdk/dist/spawn-from-env.d.ts.map +1 -0
  298. package/packages/sdk/dist/spawn-from-env.js +172 -0
  299. package/packages/sdk/dist/spawn-from-env.js.map +1 -0
  300. package/packages/sdk/dist/workflows/builder.d.ts +114 -0
  301. package/packages/sdk/dist/workflows/builder.d.ts.map +1 -0
  302. package/packages/sdk/dist/workflows/builder.js +201 -0
  303. package/packages/sdk/dist/workflows/builder.js.map +1 -0
  304. package/packages/sdk/dist/workflows/cli.d.ts +11 -0
  305. package/packages/sdk/dist/workflows/cli.d.ts.map +1 -0
  306. package/packages/sdk/dist/workflows/cli.js +144 -0
  307. package/packages/sdk/dist/workflows/cli.js.map +1 -0
  308. package/packages/sdk/dist/workflows/coordinator.d.ts +73 -0
  309. package/packages/sdk/dist/workflows/coordinator.d.ts.map +1 -0
  310. package/packages/sdk/dist/workflows/coordinator.js +647 -0
  311. package/packages/sdk/dist/workflows/coordinator.js.map +1 -0
  312. package/packages/sdk/dist/workflows/custom-steps.d.ts +73 -0
  313. package/packages/sdk/dist/workflows/custom-steps.d.ts.map +1 -0
  314. package/packages/sdk/dist/workflows/custom-steps.js +321 -0
  315. package/packages/sdk/dist/workflows/custom-steps.js.map +1 -0
  316. package/packages/sdk/dist/workflows/dry-run-format.d.ts +6 -0
  317. package/packages/sdk/dist/workflows/dry-run-format.d.ts.map +1 -0
  318. package/packages/sdk/dist/workflows/dry-run-format.js +68 -0
  319. package/packages/sdk/dist/workflows/dry-run-format.js.map +1 -0
  320. package/packages/sdk/dist/workflows/file-db.d.ts +33 -0
  321. package/packages/sdk/dist/workflows/file-db.d.ts.map +1 -0
  322. package/packages/sdk/dist/workflows/file-db.js +108 -0
  323. package/packages/sdk/dist/workflows/file-db.js.map +1 -0
  324. package/packages/sdk/dist/workflows/index.d.ts +15 -0
  325. package/packages/sdk/dist/workflows/index.d.ts.map +1 -0
  326. package/packages/sdk/dist/workflows/index.js +15 -0
  327. package/packages/sdk/dist/workflows/index.js.map +1 -0
  328. package/packages/sdk/dist/workflows/run.d.ts +38 -0
  329. package/packages/sdk/dist/workflows/run.d.ts.map +1 -0
  330. package/packages/sdk/dist/workflows/run.js +25 -0
  331. package/packages/sdk/dist/workflows/run.js.map +1 -0
  332. package/packages/sdk/dist/workflows/runner.d.ts +320 -0
  333. package/packages/sdk/dist/workflows/runner.d.ts.map +1 -0
  334. package/packages/sdk/dist/workflows/runner.js +2821 -0
  335. package/packages/sdk/dist/workflows/runner.js.map +1 -0
  336. package/packages/sdk/dist/workflows/templates.d.ts +47 -0
  337. package/packages/sdk/dist/workflows/templates.d.ts.map +1 -0
  338. package/packages/sdk/dist/workflows/templates.js +405 -0
  339. package/packages/sdk/dist/workflows/templates.js.map +1 -0
  340. package/packages/sdk/dist/workflows/trajectory.d.ts +87 -0
  341. package/packages/sdk/dist/workflows/trajectory.d.ts.map +1 -0
  342. package/packages/sdk/dist/workflows/trajectory.js +441 -0
  343. package/packages/sdk/dist/workflows/trajectory.js.map +1 -0
  344. package/packages/sdk/dist/workflows/types.d.ts +306 -0
  345. package/packages/sdk/dist/workflows/types.d.ts.map +1 -0
  346. package/packages/sdk/dist/workflows/types.js +23 -0
  347. package/packages/sdk/dist/workflows/types.js.map +1 -0
  348. package/packages/sdk/dist/workflows/validator.d.ts +11 -0
  349. package/packages/sdk/dist/workflows/validator.d.ts.map +1 -0
  350. package/packages/sdk/dist/workflows/validator.js +128 -0
  351. package/packages/sdk/dist/workflows/validator.js.map +1 -0
  352. package/packages/sdk/package.json +59 -53
  353. package/packages/sdk/scripts/bundle-agent-relay.mjs +53 -0
  354. package/packages/sdk/src/__tests__/contract-fixtures.test.ts +122 -0
  355. package/packages/sdk/src/__tests__/error-scenarios.test.ts +682 -0
  356. package/packages/sdk/src/__tests__/facade.test.ts +364 -0
  357. package/packages/sdk/src/__tests__/idle-nudge.test.ts +438 -0
  358. package/packages/sdk/src/__tests__/integration.test.ts +204 -0
  359. package/packages/sdk/src/__tests__/orchestration-upgrades.test.ts +797 -0
  360. package/packages/sdk/src/__tests__/pty.test.ts +24 -0
  361. package/packages/sdk/src/__tests__/quickstart.test.ts +198 -0
  362. package/packages/sdk/src/__tests__/spawn-from-env.test.ts +282 -0
  363. package/packages/sdk/src/__tests__/swarm-coordinator.test.ts +909 -0
  364. package/packages/sdk/src/__tests__/unit.test.ts +435 -0
  365. package/packages/sdk/src/__tests__/workflow-runner.test.ts +489 -0
  366. package/packages/sdk/src/__tests__/yaml-validation.test.ts +890 -0
  367. package/packages/sdk/src/client.ts +514 -1912
  368. package/packages/sdk/src/examples/workflow-superiority.ts +1485 -0
  369. package/packages/sdk/src/examples/workflows/README.md +156 -0
  370. package/packages/sdk/src/examples/workflows/ralph-overnight.yaml +421 -0
  371. package/packages/sdk/src/examples/workflows/ralph-swarm.yaml +411 -0
  372. package/packages/sdk/src/examples/workflows/ralph-tdd.yaml +259 -0
  373. package/packages/sdk/src/index.ts +13 -116
  374. package/packages/sdk/src/logs.ts +282 -54
  375. package/packages/sdk/src/models.ts +36 -0
  376. package/packages/sdk/src/protocol.ts +385 -0
  377. package/packages/sdk/src/pty.ts +35 -0
  378. package/packages/sdk/src/relay-adapter.ts +316 -0
  379. package/packages/sdk/src/relay.ts +1147 -0
  380. package/packages/sdk/src/shadow.ts +228 -0
  381. package/packages/sdk/src/spawn-from-env.ts +245 -0
  382. package/packages/sdk/src/workflows/README.md +656 -0
  383. package/packages/sdk/src/workflows/builder.ts +278 -0
  384. package/packages/sdk/src/workflows/builtin-templates/bug-fix.yaml +135 -0
  385. package/packages/sdk/src/workflows/builtin-templates/code-review.yaml +133 -0
  386. package/packages/sdk/src/workflows/builtin-templates/competitive.yaml +103 -0
  387. package/packages/sdk/src/workflows/builtin-templates/documentation.yaml +120 -0
  388. package/packages/sdk/src/workflows/builtin-templates/feature-dev.yaml +142 -0
  389. package/packages/sdk/src/workflows/builtin-templates/refactor.yaml +141 -0
  390. package/packages/sdk/src/workflows/builtin-templates/review-loop.yaml +223 -0
  391. package/packages/sdk/src/workflows/builtin-templates/security-audit.yaml +129 -0
  392. package/packages/sdk/src/workflows/cli.ts +162 -0
  393. package/packages/sdk/src/workflows/coordinator.ts +842 -0
  394. package/packages/sdk/src/workflows/custom-steps.ts +450 -0
  395. package/packages/sdk/src/workflows/dry-run-format.ts +75 -0
  396. package/packages/sdk/src/workflows/file-db.ts +117 -0
  397. package/packages/sdk/src/workflows/index.ts +24 -0
  398. package/packages/sdk/src/workflows/run.ts +72 -0
  399. package/packages/sdk/src/workflows/runner.ts +3409 -0
  400. package/packages/sdk/src/workflows/schema.json +651 -0
  401. package/packages/sdk/src/workflows/templates.ts +552 -0
  402. package/packages/sdk/src/workflows/trajectory.ts +631 -0
  403. package/packages/sdk/src/workflows/types.ts +389 -0
  404. package/packages/sdk/src/workflows/validator.ts +151 -0
  405. package/packages/sdk/tsconfig.build.json +25 -0
  406. package/packages/sdk/tsconfig.json +17 -18
  407. package/packages/sdk/vitest.config.ts +1 -1
  408. package/packages/sdk-py/README.md +106 -21
  409. package/packages/sdk-py/agent_relay/__init__.py +21 -0
  410. package/packages/sdk-py/agent_relay/models.py +206 -0
  411. package/packages/sdk-py/pyproject.toml +2 -2
  412. package/packages/sdk-py/src/agent_relay/__init__.py +76 -0
  413. package/packages/sdk-py/src/agent_relay/builder.py +430 -109
  414. package/packages/sdk-py/src/agent_relay/templates.py +197 -0
  415. package/packages/sdk-py/src/agent_relay/types.py +489 -15
  416. package/packages/sdk-py/tests/test_builder.py +115 -1
  417. package/packages/sdk-py/tests/test_workflow_templates.py +450 -0
  418. package/packages/shared/cli-registry.yaml +193 -0
  419. package/packages/shared/codegen-py.mjs +215 -0
  420. package/packages/shared/codegen-ts.mjs +227 -0
  421. package/packages/telemetry/dist/events.d.ts +8 -8
  422. package/packages/telemetry/dist/index.d.ts +1 -1
  423. package/packages/telemetry/package.json +2 -2
  424. package/packages/telemetry/src/events.ts +9 -9
  425. package/packages/telemetry/src/index.ts +2 -2
  426. package/packages/trajectory/package.json +2 -2
  427. package/packages/user-directory/dist/user-directory.js +1 -1
  428. package/packages/user-directory/dist/user-directory.js.map +1 -1
  429. package/packages/user-directory/package.json +2 -2
  430. package/packages/user-directory/src/user-directory.ts +1 -1
  431. package/packages/utils/dist/cjs/client-helpers.js +4 -4
  432. package/packages/utils/dist/cjs/discovery.js +9 -6
  433. package/packages/utils/dist/cjs/errors.js +5 -5
  434. package/packages/utils/dist/cjs/legacy-protocol.js +70 -0
  435. package/packages/utils/dist/cjs/logger.js +3 -3
  436. package/packages/utils/dist/cjs/precompiled-patterns.js +33 -2
  437. package/packages/utils/dist/cjs/relay-pty-path.js +0 -6
  438. package/packages/utils/dist/client-helpers.d.ts +1 -1
  439. package/packages/utils/dist/client-helpers.d.ts.map +1 -1
  440. package/packages/utils/dist/client-helpers.js +1 -1
  441. package/packages/utils/dist/client-helpers.js.map +1 -1
  442. package/packages/utils/dist/discovery.d.ts +7 -7
  443. package/packages/utils/dist/discovery.d.ts.map +1 -1
  444. package/packages/utils/dist/discovery.js +20 -17
  445. package/packages/utils/dist/discovery.js.map +1 -1
  446. package/packages/utils/dist/errors.d.ts +1 -1
  447. package/packages/utils/dist/errors.js +3 -3
  448. package/packages/utils/dist/legacy-protocol.d.ts +46 -0
  449. package/packages/utils/dist/legacy-protocol.d.ts.map +1 -0
  450. package/packages/utils/dist/legacy-protocol.js +47 -0
  451. package/packages/utils/dist/legacy-protocol.js.map +1 -0
  452. package/packages/utils/dist/logger.d.ts +2 -2
  453. package/packages/utils/dist/logger.js +2 -2
  454. package/packages/utils/dist/precompiled-patterns.d.ts.map +1 -1
  455. package/packages/utils/dist/precompiled-patterns.js +28 -2
  456. package/packages/utils/dist/precompiled-patterns.js.map +1 -1
  457. package/packages/utils/dist/relay-pty-path.d.ts.map +1 -1
  458. package/packages/utils/dist/relay-pty-path.js +1 -10
  459. package/packages/utils/dist/relay-pty-path.js.map +1 -1
  460. package/packages/utils/package.json +2 -3
  461. package/packages/utils/src/client-helpers.ts +1 -1
  462. package/packages/utils/src/consolidation.test.ts +3 -3
  463. package/packages/utils/src/discovery.test.ts +3 -3
  464. package/packages/utils/src/discovery.ts +21 -18
  465. package/packages/utils/src/errors.test.ts +6 -11
  466. package/packages/utils/src/errors.ts +3 -3
  467. package/packages/utils/src/legacy-protocol.ts +151 -0
  468. package/packages/utils/src/logger.ts +2 -2
  469. package/packages/utils/src/precompiled-patterns.test.ts +8 -0
  470. package/packages/utils/src/precompiled-patterns.ts +40 -2
  471. package/packages/utils/src/relay-pty-path.test.ts +23 -34
  472. package/packages/utils/src/relay-pty-path.ts +1 -11
  473. package/relay-snippets/agent-relay-protocol.md +6 -43
  474. package/relay-snippets/agent-relay-snippet.md +59 -203
  475. package/scripts/postinstall.js +44 -171
  476. package/bin/relay-pty-darwin-arm64 +0 -0
  477. package/bin/relay-pty-darwin-x64 +0 -0
  478. package/bin/relay-pty-linux-arm64 +0 -0
  479. package/bin/relay-pty-linux-x64 +0 -0
  480. package/dist/src/bridge/index.d.ts +0 -8
  481. package/dist/src/bridge/index.d.ts.map +0 -1
  482. package/dist/src/bridge/index.js +0 -8
  483. package/dist/src/bridge/index.js.map +0 -1
  484. package/dist/src/continuity/index.d.ts +0 -5
  485. package/dist/src/continuity/index.d.ts.map +0 -1
  486. package/dist/src/continuity/index.js +0 -5
  487. package/dist/src/continuity/index.js.map +0 -1
  488. package/dist/src/daemon/index.d.ts +0 -8
  489. package/dist/src/daemon/index.d.ts.map +0 -1
  490. package/dist/src/daemon/index.js +0 -9
  491. package/dist/src/daemon/index.js.map +0 -1
  492. package/dist/src/protocol/index.d.ts +0 -8
  493. package/dist/src/protocol/index.d.ts.map +0 -1
  494. package/dist/src/protocol/index.js +0 -8
  495. package/dist/src/protocol/index.js.map +0 -1
  496. package/dist/src/resiliency/index.d.ts +0 -5
  497. package/dist/src/resiliency/index.d.ts.map +0 -1
  498. package/dist/src/resiliency/index.js +0 -5
  499. package/dist/src/resiliency/index.js.map +0 -1
  500. package/dist/src/state/index.d.ts +0 -5
  501. package/dist/src/state/index.d.ts.map +0 -1
  502. package/dist/src/state/index.js +0 -5
  503. package/dist/src/state/index.js.map +0 -1
  504. package/dist/src/storage/index.d.ts +0 -8
  505. package/dist/src/storage/index.d.ts.map +0 -1
  506. package/dist/src/storage/index.js +0 -8
  507. package/dist/src/storage/index.js.map +0 -1
  508. package/dist/src/wrapper/index.d.ts +0 -8
  509. package/dist/src/wrapper/index.d.ts.map +0 -1
  510. package/dist/src/wrapper/index.js +0 -11
  511. package/dist/src/wrapper/index.js.map +0 -1
  512. package/packages/bridge/dist/cli-resolution.d.ts +0 -32
  513. package/packages/bridge/dist/cli-resolution.d.ts.map +0 -1
  514. package/packages/bridge/dist/cli-resolution.js +0 -88
  515. package/packages/bridge/dist/cli-resolution.js.map +0 -1
  516. package/packages/bridge/dist/index.d.ts +0 -9
  517. package/packages/bridge/dist/index.d.ts.map +0 -1
  518. package/packages/bridge/dist/index.js +0 -11
  519. package/packages/bridge/dist/index.js.map +0 -1
  520. package/packages/bridge/dist/multi-project-client.d.ts +0 -99
  521. package/packages/bridge/dist/multi-project-client.d.ts.map +0 -1
  522. package/packages/bridge/dist/multi-project-client.js +0 -389
  523. package/packages/bridge/dist/multi-project-client.js.map +0 -1
  524. package/packages/bridge/dist/shadow-cli.d.ts +0 -17
  525. package/packages/bridge/dist/shadow-cli.d.ts.map +0 -1
  526. package/packages/bridge/dist/shadow-cli.js +0 -75
  527. package/packages/bridge/dist/shadow-cli.js.map +0 -1
  528. package/packages/bridge/dist/spawner.d.ts +0 -263
  529. package/packages/bridge/dist/spawner.d.ts.map +0 -1
  530. package/packages/bridge/dist/spawner.js +0 -1758
  531. package/packages/bridge/dist/spawner.js.map +0 -1
  532. package/packages/bridge/dist/types.d.ts +0 -141
  533. package/packages/bridge/dist/types.d.ts.map +0 -1
  534. package/packages/bridge/dist/types.js +0 -6
  535. package/packages/bridge/dist/types.js.map +0 -1
  536. package/packages/bridge/dist/utils.d.ts +0 -39
  537. package/packages/bridge/dist/utils.d.ts.map +0 -1
  538. package/packages/bridge/dist/utils.js +0 -98
  539. package/packages/bridge/dist/utils.js.map +0 -1
  540. package/packages/bridge/package.json +0 -45
  541. package/packages/bridge/src/cli-resolution.test.ts +0 -225
  542. package/packages/bridge/src/cli-resolution.ts +0 -100
  543. package/packages/bridge/src/index.ts +0 -34
  544. package/packages/bridge/src/multi-project-client.test.ts +0 -340
  545. package/packages/bridge/src/multi-project-client.ts +0 -469
  546. package/packages/bridge/src/shadow-cli.ts +0 -95
  547. package/packages/bridge/src/spawner-mcp.test.ts +0 -505
  548. package/packages/bridge/src/spawner.ts +0 -2067
  549. package/packages/bridge/src/types.ts +0 -153
  550. package/packages/bridge/src/utils.test.ts +0 -235
  551. package/packages/bridge/src/utils.ts +0 -113
  552. package/packages/bridge/tsconfig.json +0 -29
  553. package/packages/bridge/vitest.config.ts +0 -9
  554. package/packages/broker-sdk/README.md +0 -97
  555. package/packages/broker-sdk/dist/__tests__/facade.test.js +0 -257
  556. package/packages/broker-sdk/dist/__tests__/facade.test.js.map +0 -1
  557. package/packages/broker-sdk/dist/__tests__/integration.test.js +0 -139
  558. package/packages/broker-sdk/dist/__tests__/integration.test.js.map +0 -1
  559. package/packages/broker-sdk/dist/__tests__/quickstart.test.js +0 -176
  560. package/packages/broker-sdk/dist/__tests__/quickstart.test.js.map +0 -1
  561. package/packages/broker-sdk/dist/__tests__/unit.test.js +0 -192
  562. package/packages/broker-sdk/dist/__tests__/unit.test.js.map +0 -1
  563. package/packages/broker-sdk/dist/client.d.ts +0 -95
  564. package/packages/broker-sdk/dist/client.d.ts.map +0 -1
  565. package/packages/broker-sdk/dist/client.js +0 -372
  566. package/packages/broker-sdk/dist/client.js.map +0 -1
  567. package/packages/broker-sdk/dist/index.d.ts +0 -10
  568. package/packages/broker-sdk/dist/index.d.ts.map +0 -1
  569. package/packages/broker-sdk/dist/index.js +0 -10
  570. package/packages/broker-sdk/dist/index.js.map +0 -1
  571. package/packages/broker-sdk/dist/logs.d.ts +0 -47
  572. package/packages/broker-sdk/dist/logs.d.ts.map +0 -1
  573. package/packages/broker-sdk/dist/logs.js +0 -137
  574. package/packages/broker-sdk/dist/logs.js.map +0 -1
  575. package/packages/broker-sdk/dist/protocol.d.ts +0 -254
  576. package/packages/broker-sdk/dist/protocol.d.ts.map +0 -1
  577. package/packages/broker-sdk/dist/pty.d.ts.map +0 -1
  578. package/packages/broker-sdk/dist/pty.js +0 -14
  579. package/packages/broker-sdk/dist/pty.js.map +0 -1
  580. package/packages/broker-sdk/dist/relay.d.ts +0 -172
  581. package/packages/broker-sdk/dist/relay.d.ts.map +0 -1
  582. package/packages/broker-sdk/dist/relay.js +0 -486
  583. package/packages/broker-sdk/dist/relay.js.map +0 -1
  584. package/packages/broker-sdk/dist/relaycast.d.ts +0 -67
  585. package/packages/broker-sdk/dist/relaycast.d.ts.map +0 -1
  586. package/packages/broker-sdk/dist/relaycast.js +0 -150
  587. package/packages/broker-sdk/dist/relaycast.js.map +0 -1
  588. package/packages/broker-sdk/dist/shadow.d.ts +0 -100
  589. package/packages/broker-sdk/dist/shadow.d.ts.map +0 -1
  590. package/packages/broker-sdk/dist/shadow.js.map +0 -1
  591. package/packages/broker-sdk/dist/workflows/builder.d.ts +0 -101
  592. package/packages/broker-sdk/dist/workflows/builder.d.ts.map +0 -1
  593. package/packages/broker-sdk/dist/workflows/builder.js +0 -179
  594. package/packages/broker-sdk/dist/workflows/builder.js.map +0 -1
  595. package/packages/broker-sdk/dist/workflows/cli.d.ts +0 -10
  596. package/packages/broker-sdk/dist/workflows/cli.d.ts.map +0 -1
  597. package/packages/broker-sdk/dist/workflows/cli.js +0 -82
  598. package/packages/broker-sdk/dist/workflows/cli.js.map +0 -1
  599. package/packages/broker-sdk/dist/workflows/coordinator.d.ts +0 -69
  600. package/packages/broker-sdk/dist/workflows/coordinator.d.ts.map +0 -1
  601. package/packages/broker-sdk/dist/workflows/coordinator.js +0 -585
  602. package/packages/broker-sdk/dist/workflows/coordinator.js.map +0 -1
  603. package/packages/broker-sdk/dist/workflows/index.d.ts +0 -11
  604. package/packages/broker-sdk/dist/workflows/index.d.ts.map +0 -1
  605. package/packages/broker-sdk/dist/workflows/index.js +0 -11
  606. package/packages/broker-sdk/dist/workflows/index.js.map +0 -1
  607. package/packages/broker-sdk/dist/workflows/run.d.ts +0 -33
  608. package/packages/broker-sdk/dist/workflows/run.d.ts.map +0 -1
  609. package/packages/broker-sdk/dist/workflows/run.js +0 -28
  610. package/packages/broker-sdk/dist/workflows/run.js.map +0 -1
  611. package/packages/broker-sdk/dist/workflows/runner.d.ts +0 -136
  612. package/packages/broker-sdk/dist/workflows/runner.d.ts.map +0 -1
  613. package/packages/broker-sdk/dist/workflows/runner.js +0 -900
  614. package/packages/broker-sdk/dist/workflows/runner.js.map +0 -1
  615. package/packages/broker-sdk/dist/workflows/templates.d.ts +0 -47
  616. package/packages/broker-sdk/dist/workflows/templates.d.ts.map +0 -1
  617. package/packages/broker-sdk/dist/workflows/templates.js +0 -395
  618. package/packages/broker-sdk/dist/workflows/templates.js.map +0 -1
  619. package/packages/broker-sdk/dist/workflows/trajectory.d.ts +0 -80
  620. package/packages/broker-sdk/dist/workflows/trajectory.d.ts.map +0 -1
  621. package/packages/broker-sdk/dist/workflows/trajectory.js +0 -362
  622. package/packages/broker-sdk/dist/workflows/trajectory.js.map +0 -1
  623. package/packages/broker-sdk/dist/workflows/types.d.ts +0 -140
  624. package/packages/broker-sdk/dist/workflows/types.d.ts.map +0 -1
  625. package/packages/broker-sdk/dist/workflows/types.js +0 -8
  626. package/packages/broker-sdk/dist/workflows/types.js.map +0 -1
  627. package/packages/broker-sdk/package.json +0 -81
  628. package/packages/broker-sdk/scripts/bundle-agent-relay.mjs +0 -53
  629. package/packages/broker-sdk/src/__tests__/error-scenarios.test.ts +0 -682
  630. package/packages/broker-sdk/src/__tests__/facade.test.ts +0 -296
  631. package/packages/broker-sdk/src/__tests__/integration.test.ts +0 -170
  632. package/packages/broker-sdk/src/__tests__/quickstart.test.ts +0 -198
  633. package/packages/broker-sdk/src/__tests__/swarm-coordinator.test.ts +0 -772
  634. package/packages/broker-sdk/src/__tests__/unit.test.ts +0 -243
  635. package/packages/broker-sdk/src/__tests__/workflow-runner.test.ts +0 -333
  636. package/packages/broker-sdk/src/client.ts +0 -510
  637. package/packages/broker-sdk/src/index.ts +0 -9
  638. package/packages/broker-sdk/src/logs.ts +0 -163
  639. package/packages/broker-sdk/src/protocol.ts +0 -271
  640. package/packages/broker-sdk/src/pty.ts +0 -16
  641. package/packages/broker-sdk/src/relay.ts +0 -614
  642. package/packages/broker-sdk/src/relaycast.ts +0 -185
  643. package/packages/broker-sdk/src/shadow.ts +0 -230
  644. package/packages/broker-sdk/src/workflows/README.md +0 -514
  645. package/packages/broker-sdk/src/workflows/builder.ts +0 -241
  646. package/packages/broker-sdk/src/workflows/builtin-templates/bug-fix.yaml +0 -75
  647. package/packages/broker-sdk/src/workflows/builtin-templates/code-review.yaml +0 -82
  648. package/packages/broker-sdk/src/workflows/builtin-templates/documentation.yaml +0 -70
  649. package/packages/broker-sdk/src/workflows/builtin-templates/feature-dev.yaml +0 -76
  650. package/packages/broker-sdk/src/workflows/builtin-templates/refactor.yaml +0 -82
  651. package/packages/broker-sdk/src/workflows/builtin-templates/security-audit.yaml +0 -84
  652. package/packages/broker-sdk/src/workflows/cli.ts +0 -93
  653. package/packages/broker-sdk/src/workflows/coordinator.ts +0 -758
  654. package/packages/broker-sdk/src/workflows/index.ts +0 -10
  655. package/packages/broker-sdk/src/workflows/run.ts +0 -55
  656. package/packages/broker-sdk/src/workflows/runner.ts +0 -1184
  657. package/packages/broker-sdk/src/workflows/schema.json +0 -333
  658. package/packages/broker-sdk/src/workflows/templates.ts +0 -544
  659. package/packages/broker-sdk/src/workflows/trajectory.ts +0 -507
  660. package/packages/broker-sdk/src/workflows/types.ts +0 -208
  661. package/packages/broker-sdk/tsconfig.json +0 -22
  662. package/packages/broker-sdk/vitest.config.ts +0 -9
  663. package/packages/continuity/dist/formatter.d.ts +0 -57
  664. package/packages/continuity/dist/formatter.d.ts.map +0 -1
  665. package/packages/continuity/dist/formatter.js +0 -448
  666. package/packages/continuity/dist/formatter.js.map +0 -1
  667. package/packages/continuity/dist/handoff-store.d.ts +0 -67
  668. package/packages/continuity/dist/handoff-store.d.ts.map +0 -1
  669. package/packages/continuity/dist/handoff-store.js +0 -472
  670. package/packages/continuity/dist/handoff-store.js.map +0 -1
  671. package/packages/continuity/dist/index.d.ts +0 -10
  672. package/packages/continuity/dist/index.d.ts.map +0 -1
  673. package/packages/continuity/dist/index.js +0 -11
  674. package/packages/continuity/dist/index.js.map +0 -1
  675. package/packages/continuity/dist/ledger-store.d.ts +0 -110
  676. package/packages/continuity/dist/ledger-store.d.ts.map +0 -1
  677. package/packages/continuity/dist/ledger-store.js +0 -500
  678. package/packages/continuity/dist/ledger-store.js.map +0 -1
  679. package/packages/continuity/dist/manager.d.ts +0 -183
  680. package/packages/continuity/dist/manager.d.ts.map +0 -1
  681. package/packages/continuity/dist/manager.js +0 -616
  682. package/packages/continuity/dist/manager.js.map +0 -1
  683. package/packages/continuity/dist/parser.d.ts +0 -76
  684. package/packages/continuity/dist/parser.d.ts.map +0 -1
  685. package/packages/continuity/dist/parser.js +0 -579
  686. package/packages/continuity/dist/parser.js.map +0 -1
  687. package/packages/continuity/dist/types.d.ts +0 -180
  688. package/packages/continuity/dist/types.d.ts.map +0 -1
  689. package/packages/continuity/dist/types.js +0 -2
  690. package/packages/continuity/dist/types.js.map +0 -1
  691. package/packages/continuity/package.json +0 -40
  692. package/packages/continuity/src/formatter.ts +0 -536
  693. package/packages/continuity/src/handoff-store.ts +0 -523
  694. package/packages/continuity/src/index.ts +0 -12
  695. package/packages/continuity/src/ledger-store.ts +0 -594
  696. package/packages/continuity/src/manager.test.ts +0 -291
  697. package/packages/continuity/src/manager.ts +0 -774
  698. package/packages/continuity/src/parser.test.ts +0 -292
  699. package/packages/continuity/src/parser.ts +0 -680
  700. package/packages/continuity/src/types.ts +0 -211
  701. package/packages/continuity/tsconfig.json +0 -21
  702. package/packages/continuity/vitest.config.ts +0 -9
  703. package/packages/daemon/dist/agent-manager.d.ts +0 -134
  704. package/packages/daemon/dist/agent-manager.d.ts.map +0 -1
  705. package/packages/daemon/dist/agent-manager.js +0 -578
  706. package/packages/daemon/dist/agent-manager.js.map +0 -1
  707. package/packages/daemon/dist/agent-registry.d.ts +0 -99
  708. package/packages/daemon/dist/agent-registry.d.ts.map +0 -1
  709. package/packages/daemon/dist/agent-registry.js +0 -213
  710. package/packages/daemon/dist/agent-registry.js.map +0 -1
  711. package/packages/daemon/dist/agent-signing.d.ts +0 -158
  712. package/packages/daemon/dist/agent-signing.d.ts.map +0 -1
  713. package/packages/daemon/dist/agent-signing.js +0 -523
  714. package/packages/daemon/dist/agent-signing.js.map +0 -1
  715. package/packages/daemon/dist/api.d.ts +0 -106
  716. package/packages/daemon/dist/api.d.ts.map +0 -1
  717. package/packages/daemon/dist/api.js +0 -895
  718. package/packages/daemon/dist/api.js.map +0 -1
  719. package/packages/daemon/dist/auth.d.ts +0 -94
  720. package/packages/daemon/dist/auth.d.ts.map +0 -1
  721. package/packages/daemon/dist/auth.js +0 -197
  722. package/packages/daemon/dist/auth.js.map +0 -1
  723. package/packages/daemon/dist/channel-membership-store.d.ts +0 -55
  724. package/packages/daemon/dist/channel-membership-store.d.ts.map +0 -1
  725. package/packages/daemon/dist/channel-membership-store.js +0 -176
  726. package/packages/daemon/dist/channel-membership-store.js.map +0 -1
  727. package/packages/daemon/dist/cli-auth.d.ts +0 -97
  728. package/packages/daemon/dist/cli-auth.d.ts.map +0 -1
  729. package/packages/daemon/dist/cli-auth.js +0 -808
  730. package/packages/daemon/dist/cli-auth.js.map +0 -1
  731. package/packages/daemon/dist/cloud-sync.d.ts +0 -263
  732. package/packages/daemon/dist/cloud-sync.d.ts.map +0 -1
  733. package/packages/daemon/dist/cloud-sync.js +0 -820
  734. package/packages/daemon/dist/cloud-sync.js.map +0 -1
  735. package/packages/daemon/dist/connection.d.ts +0 -137
  736. package/packages/daemon/dist/connection.d.ts.map +0 -1
  737. package/packages/daemon/dist/connection.js +0 -465
  738. package/packages/daemon/dist/connection.js.map +0 -1
  739. package/packages/daemon/dist/consensus-integration.d.ts +0 -168
  740. package/packages/daemon/dist/consensus-integration.d.ts.map +0 -1
  741. package/packages/daemon/dist/consensus-integration.js +0 -371
  742. package/packages/daemon/dist/consensus-integration.js.map +0 -1
  743. package/packages/daemon/dist/consensus.d.ts +0 -269
  744. package/packages/daemon/dist/consensus.d.ts.map +0 -1
  745. package/packages/daemon/dist/consensus.js +0 -632
  746. package/packages/daemon/dist/consensus.js.map +0 -1
  747. package/packages/daemon/dist/delivery-tracker.d.ts +0 -34
  748. package/packages/daemon/dist/delivery-tracker.d.ts.map +0 -1
  749. package/packages/daemon/dist/delivery-tracker.js +0 -104
  750. package/packages/daemon/dist/delivery-tracker.js.map +0 -1
  751. package/packages/daemon/dist/enhanced-features.d.ts +0 -118
  752. package/packages/daemon/dist/enhanced-features.d.ts.map +0 -1
  753. package/packages/daemon/dist/enhanced-features.js +0 -177
  754. package/packages/daemon/dist/enhanced-features.js.map +0 -1
  755. package/packages/daemon/dist/index.d.ts +0 -29
  756. package/packages/daemon/dist/index.d.ts.map +0 -1
  757. package/packages/daemon/dist/index.js +0 -34
  758. package/packages/daemon/dist/index.js.map +0 -1
  759. package/packages/daemon/dist/orchestrator.d.ts +0 -217
  760. package/packages/daemon/dist/orchestrator.d.ts.map +0 -1
  761. package/packages/daemon/dist/orchestrator.js +0 -1172
  762. package/packages/daemon/dist/orchestrator.js.map +0 -1
  763. package/packages/daemon/dist/rate-limiter.d.ts +0 -68
  764. package/packages/daemon/dist/rate-limiter.d.ts.map +0 -1
  765. package/packages/daemon/dist/rate-limiter.js +0 -130
  766. package/packages/daemon/dist/rate-limiter.js.map +0 -1
  767. package/packages/daemon/dist/registry.d.ts +0 -9
  768. package/packages/daemon/dist/registry.d.ts.map +0 -1
  769. package/packages/daemon/dist/registry.js +0 -9
  770. package/packages/daemon/dist/registry.js.map +0 -1
  771. package/packages/daemon/dist/repo-manager.d.ts +0 -116
  772. package/packages/daemon/dist/repo-manager.d.ts.map +0 -1
  773. package/packages/daemon/dist/repo-manager.js +0 -384
  774. package/packages/daemon/dist/repo-manager.js.map +0 -1
  775. package/packages/daemon/dist/router.d.ts +0 -389
  776. package/packages/daemon/dist/router.d.ts.map +0 -1
  777. package/packages/daemon/dist/router.js +0 -1607
  778. package/packages/daemon/dist/router.js.map +0 -1
  779. package/packages/daemon/dist/server.d.ts +0 -201
  780. package/packages/daemon/dist/server.d.ts.map +0 -1
  781. package/packages/daemon/dist/server.js +0 -1791
  782. package/packages/daemon/dist/server.js.map +0 -1
  783. package/packages/daemon/dist/spawn-manager.d.ts +0 -119
  784. package/packages/daemon/dist/spawn-manager.d.ts.map +0 -1
  785. package/packages/daemon/dist/spawn-manager.js +0 -319
  786. package/packages/daemon/dist/spawn-manager.js.map +0 -1
  787. package/packages/daemon/dist/sync-queue.d.ts +0 -116
  788. package/packages/daemon/dist/sync-queue.d.ts.map +0 -1
  789. package/packages/daemon/dist/sync-queue.js +0 -361
  790. package/packages/daemon/dist/sync-queue.js.map +0 -1
  791. package/packages/daemon/dist/types.d.ts +0 -133
  792. package/packages/daemon/dist/types.d.ts.map +0 -1
  793. package/packages/daemon/dist/types.js +0 -6
  794. package/packages/daemon/dist/types.js.map +0 -1
  795. package/packages/daemon/dist/workspace-manager.d.ts +0 -80
  796. package/packages/daemon/dist/workspace-manager.d.ts.map +0 -1
  797. package/packages/daemon/dist/workspace-manager.js +0 -314
  798. package/packages/daemon/dist/workspace-manager.js.map +0 -1
  799. package/packages/daemon/package.json +0 -56
  800. package/packages/daemon/src/agent-manager.ts +0 -679
  801. package/packages/daemon/src/agent-registry.ts +0 -284
  802. package/packages/daemon/src/agent-signing.ts +0 -707
  803. package/packages/daemon/src/api.ts +0 -1034
  804. package/packages/daemon/src/auth.ts +0 -276
  805. package/packages/daemon/src/channel-membership-store.ts +0 -217
  806. package/packages/daemon/src/cli-auth.ts +0 -945
  807. package/packages/daemon/src/cloud-sync.ts +0 -1100
  808. package/packages/daemon/src/connection.ts +0 -561
  809. package/packages/daemon/src/consensus-integration.ts +0 -510
  810. package/packages/daemon/src/consensus.ts +0 -848
  811. package/packages/daemon/src/delivery-tracker.ts +0 -145
  812. package/packages/daemon/src/enhanced-features.ts +0 -390
  813. package/packages/daemon/src/index.ts +0 -48
  814. package/packages/daemon/src/orchestrator.test.ts +0 -231
  815. package/packages/daemon/src/orchestrator.ts +0 -1376
  816. package/packages/daemon/src/rate-limiter.ts +0 -172
  817. package/packages/daemon/src/registry.ts +0 -8
  818. package/packages/daemon/src/repo-manager.ts +0 -468
  819. package/packages/daemon/src/router.test.ts +0 -181
  820. package/packages/daemon/src/router.ts +0 -1925
  821. package/packages/daemon/src/server.ts +0 -2051
  822. package/packages/daemon/src/spawn-manager-set-model.test.ts +0 -144
  823. package/packages/daemon/src/spawn-manager.ts +0 -415
  824. package/packages/daemon/src/sync-queue.ts +0 -477
  825. package/packages/daemon/src/types.ts +0 -158
  826. package/packages/daemon/src/workspace-manager.ts +0 -371
  827. package/packages/daemon/tsconfig.json +0 -21
  828. package/packages/daemon/vitest.config.ts +0 -9
  829. package/packages/mcp/CHANGELOG.md +0 -28
  830. package/packages/mcp/LICENSE +0 -190
  831. package/packages/mcp/README.md +0 -266
  832. package/packages/mcp/dist/bin.d.ts +0 -12
  833. package/packages/mcp/dist/bin.d.ts.map +0 -1
  834. package/packages/mcp/dist/bin.js +0 -179
  835. package/packages/mcp/dist/bin.js.map +0 -1
  836. package/packages/mcp/dist/client-adapter.d.ts +0 -164
  837. package/packages/mcp/dist/client-adapter.d.ts.map +0 -1
  838. package/packages/mcp/dist/client-adapter.js +0 -231
  839. package/packages/mcp/dist/client-adapter.js.map +0 -1
  840. package/packages/mcp/dist/cloud.d.ts +0 -13
  841. package/packages/mcp/dist/cloud.d.ts.map +0 -1
  842. package/packages/mcp/dist/cloud.js +0 -25
  843. package/packages/mcp/dist/cloud.js.map +0 -1
  844. package/packages/mcp/dist/errors.d.ts +0 -9
  845. package/packages/mcp/dist/errors.d.ts.map +0 -1
  846. package/packages/mcp/dist/errors.js +0 -9
  847. package/packages/mcp/dist/errors.js.map +0 -1
  848. package/packages/mcp/dist/file-transport.d.ts +0 -103
  849. package/packages/mcp/dist/file-transport.d.ts.map +0 -1
  850. package/packages/mcp/dist/file-transport.js +0 -204
  851. package/packages/mcp/dist/file-transport.js.map +0 -1
  852. package/packages/mcp/dist/hybrid-client.d.ts +0 -5
  853. package/packages/mcp/dist/hybrid-client.d.ts.map +0 -1
  854. package/packages/mcp/dist/hybrid-client.js +0 -23
  855. package/packages/mcp/dist/hybrid-client.js.map +0 -1
  856. package/packages/mcp/dist/index.d.ts +0 -11
  857. package/packages/mcp/dist/index.d.ts.map +0 -1
  858. package/packages/mcp/dist/index.js +0 -25
  859. package/packages/mcp/dist/index.js.map +0 -1
  860. package/packages/mcp/dist/install-cli.d.ts +0 -35
  861. package/packages/mcp/dist/install-cli.d.ts.map +0 -1
  862. package/packages/mcp/dist/install-cli.js +0 -157
  863. package/packages/mcp/dist/install-cli.js.map +0 -1
  864. package/packages/mcp/dist/install.d.ts +0 -123
  865. package/packages/mcp/dist/install.d.ts.map +0 -1
  866. package/packages/mcp/dist/install.js +0 -661
  867. package/packages/mcp/dist/install.js.map +0 -1
  868. package/packages/mcp/dist/prompts/index.d.ts +0 -2
  869. package/packages/mcp/dist/prompts/index.d.ts.map +0 -1
  870. package/packages/mcp/dist/prompts/index.js +0 -2
  871. package/packages/mcp/dist/prompts/index.js.map +0 -1
  872. package/packages/mcp/dist/prompts/protocol.d.ts +0 -11
  873. package/packages/mcp/dist/prompts/protocol.d.ts.map +0 -1
  874. package/packages/mcp/dist/prompts/protocol.js +0 -160
  875. package/packages/mcp/dist/prompts/protocol.js.map +0 -1
  876. package/packages/mcp/dist/resources/agents.d.ts +0 -11
  877. package/packages/mcp/dist/resources/agents.d.ts.map +0 -1
  878. package/packages/mcp/dist/resources/agents.js +0 -17
  879. package/packages/mcp/dist/resources/agents.js.map +0 -1
  880. package/packages/mcp/dist/resources/inbox.d.ts +0 -11
  881. package/packages/mcp/dist/resources/inbox.d.ts.map +0 -1
  882. package/packages/mcp/dist/resources/inbox.js +0 -17
  883. package/packages/mcp/dist/resources/inbox.js.map +0 -1
  884. package/packages/mcp/dist/resources/index.d.ts +0 -4
  885. package/packages/mcp/dist/resources/index.d.ts.map +0 -1
  886. package/packages/mcp/dist/resources/index.js +0 -4
  887. package/packages/mcp/dist/resources/index.js.map +0 -1
  888. package/packages/mcp/dist/resources/project.d.ts +0 -11
  889. package/packages/mcp/dist/resources/project.d.ts.map +0 -1
  890. package/packages/mcp/dist/resources/project.js +0 -21
  891. package/packages/mcp/dist/resources/project.js.map +0 -1
  892. package/packages/mcp/dist/server.d.ts +0 -23
  893. package/packages/mcp/dist/server.d.ts.map +0 -1
  894. package/packages/mcp/dist/server.js +0 -317
  895. package/packages/mcp/dist/server.js.map +0 -1
  896. package/packages/mcp/dist/simple.d.ts +0 -170
  897. package/packages/mcp/dist/simple.d.ts.map +0 -1
  898. package/packages/mcp/dist/simple.js +0 -120
  899. package/packages/mcp/dist/simple.js.map +0 -1
  900. package/packages/mcp/dist/tools/index.d.ts +0 -20
  901. package/packages/mcp/dist/tools/index.d.ts.map +0 -1
  902. package/packages/mcp/dist/tools/index.js +0 -20
  903. package/packages/mcp/dist/tools/index.js.map +0 -1
  904. package/packages/mcp/dist/tools/relay-broadcast.d.ts +0 -20
  905. package/packages/mcp/dist/tools/relay-broadcast.d.ts.map +0 -1
  906. package/packages/mcp/dist/tools/relay-broadcast.js +0 -25
  907. package/packages/mcp/dist/tools/relay-broadcast.js.map +0 -1
  908. package/packages/mcp/dist/tools/relay-channel.d.ts +0 -75
  909. package/packages/mcp/dist/tools/relay-channel.d.ts.map +0 -1
  910. package/packages/mcp/dist/tools/relay-channel.js +0 -124
  911. package/packages/mcp/dist/tools/relay-channel.js.map +0 -1
  912. package/packages/mcp/dist/tools/relay-connected.d.ts +0 -17
  913. package/packages/mcp/dist/tools/relay-connected.d.ts.map +0 -1
  914. package/packages/mcp/dist/tools/relay-connected.js +0 -54
  915. package/packages/mcp/dist/tools/relay-connected.js.map +0 -1
  916. package/packages/mcp/dist/tools/relay-consensus.d.ts +0 -45
  917. package/packages/mcp/dist/tools/relay-consensus.d.ts.map +0 -1
  918. package/packages/mcp/dist/tools/relay-consensus.js +0 -80
  919. package/packages/mcp/dist/tools/relay-consensus.js.map +0 -1
  920. package/packages/mcp/dist/tools/relay-continuity.d.ts +0 -35
  921. package/packages/mcp/dist/tools/relay-continuity.d.ts.map +0 -1
  922. package/packages/mcp/dist/tools/relay-continuity.js +0 -101
  923. package/packages/mcp/dist/tools/relay-continuity.js.map +0 -1
  924. package/packages/mcp/dist/tools/relay-health.d.ts +0 -20
  925. package/packages/mcp/dist/tools/relay-health.d.ts.map +0 -1
  926. package/packages/mcp/dist/tools/relay-health.js +0 -130
  927. package/packages/mcp/dist/tools/relay-health.js.map +0 -1
  928. package/packages/mcp/dist/tools/relay-inbox.d.ts +0 -26
  929. package/packages/mcp/dist/tools/relay-inbox.d.ts.map +0 -1
  930. package/packages/mcp/dist/tools/relay-inbox.js +0 -58
  931. package/packages/mcp/dist/tools/relay-inbox.js.map +0 -1
  932. package/packages/mcp/dist/tools/relay-logs.d.ts +0 -20
  933. package/packages/mcp/dist/tools/relay-logs.d.ts.map +0 -1
  934. package/packages/mcp/dist/tools/relay-logs.js +0 -90
  935. package/packages/mcp/dist/tools/relay-logs.js.map +0 -1
  936. package/packages/mcp/dist/tools/relay-messages.d.ts +0 -32
  937. package/packages/mcp/dist/tools/relay-messages.d.ts.map +0 -1
  938. package/packages/mcp/dist/tools/relay-messages.js +0 -61
  939. package/packages/mcp/dist/tools/relay-messages.js.map +0 -1
  940. package/packages/mcp/dist/tools/relay-metrics.d.ts +0 -17
  941. package/packages/mcp/dist/tools/relay-metrics.d.ts.map +0 -1
  942. package/packages/mcp/dist/tools/relay-metrics.js +0 -124
  943. package/packages/mcp/dist/tools/relay-metrics.js.map +0 -1
  944. package/packages/mcp/dist/tools/relay-release.d.ts +0 -20
  945. package/packages/mcp/dist/tools/relay-release.d.ts.map +0 -1
  946. package/packages/mcp/dist/tools/relay-release.js +0 -44
  947. package/packages/mcp/dist/tools/relay-release.js.map +0 -1
  948. package/packages/mcp/dist/tools/relay-remove-agent.d.ts +0 -20
  949. package/packages/mcp/dist/tools/relay-remove-agent.d.ts.map +0 -1
  950. package/packages/mcp/dist/tools/relay-remove-agent.js +0 -50
  951. package/packages/mcp/dist/tools/relay-remove-agent.js.map +0 -1
  952. package/packages/mcp/dist/tools/relay-send.d.ts +0 -29
  953. package/packages/mcp/dist/tools/relay-send.d.ts.map +0 -1
  954. package/packages/mcp/dist/tools/relay-send.js +0 -73
  955. package/packages/mcp/dist/tools/relay-send.js.map +0 -1
  956. package/packages/mcp/dist/tools/relay-set-model.d.ts +0 -23
  957. package/packages/mcp/dist/tools/relay-set-model.d.ts.map +0 -1
  958. package/packages/mcp/dist/tools/relay-set-model.js +0 -52
  959. package/packages/mcp/dist/tools/relay-set-model.js.map +0 -1
  960. package/packages/mcp/dist/tools/relay-shadow.d.ts +0 -30
  961. package/packages/mcp/dist/tools/relay-shadow.d.ts.map +0 -1
  962. package/packages/mcp/dist/tools/relay-shadow.js +0 -55
  963. package/packages/mcp/dist/tools/relay-shadow.js.map +0 -1
  964. package/packages/mcp/dist/tools/relay-spawn.d.ts +0 -36
  965. package/packages/mcp/dist/tools/relay-spawn.d.ts.map +0 -1
  966. package/packages/mcp/dist/tools/relay-spawn.js +0 -73
  967. package/packages/mcp/dist/tools/relay-spawn.js.map +0 -1
  968. package/packages/mcp/dist/tools/relay-status.d.ts +0 -11
  969. package/packages/mcp/dist/tools/relay-status.d.ts.map +0 -1
  970. package/packages/mcp/dist/tools/relay-status.js +0 -43
  971. package/packages/mcp/dist/tools/relay-status.js.map +0 -1
  972. package/packages/mcp/dist/tools/relay-subscribe.d.ts +0 -27
  973. package/packages/mcp/dist/tools/relay-subscribe.d.ts.map +0 -1
  974. package/packages/mcp/dist/tools/relay-subscribe.js +0 -49
  975. package/packages/mcp/dist/tools/relay-subscribe.js.map +0 -1
  976. package/packages/mcp/dist/tools/relay-who.d.ts +0 -20
  977. package/packages/mcp/dist/tools/relay-who.d.ts.map +0 -1
  978. package/packages/mcp/dist/tools/relay-who.js +0 -62
  979. package/packages/mcp/dist/tools/relay-who.js.map +0 -1
  980. package/packages/mcp/package.json +0 -82
  981. package/packages/mcp/src/bin.ts +0 -200
  982. package/packages/mcp/src/client-adapter.ts +0 -358
  983. package/packages/mcp/src/cloud.ts +0 -41
  984. package/packages/mcp/src/errors.ts +0 -17
  985. package/packages/mcp/src/file-transport.ts +0 -275
  986. package/packages/mcp/src/hybrid-client.ts +0 -25
  987. package/packages/mcp/src/index.ts +0 -143
  988. package/packages/mcp/src/install-cli.ts +0 -210
  989. package/packages/mcp/src/install.ts +0 -820
  990. package/packages/mcp/src/prompts/index.ts +0 -1
  991. package/packages/mcp/src/prompts/protocol.ts +0 -164
  992. package/packages/mcp/src/resources/agents.ts +0 -21
  993. package/packages/mcp/src/resources/inbox.ts +0 -21
  994. package/packages/mcp/src/resources/index.ts +0 -3
  995. package/packages/mcp/src/resources/project.ts +0 -29
  996. package/packages/mcp/src/server.ts +0 -475
  997. package/packages/mcp/src/simple.ts +0 -214
  998. package/packages/mcp/src/tools/index.ts +0 -155
  999. package/packages/mcp/src/tools/relay-broadcast.ts +0 -32
  1000. package/packages/mcp/src/tools/relay-channel.ts +0 -151
  1001. package/packages/mcp/src/tools/relay-connected.ts +0 -67
  1002. package/packages/mcp/src/tools/relay-consensus.ts +0 -92
  1003. package/packages/mcp/src/tools/relay-continuity.ts +0 -127
  1004. package/packages/mcp/src/tools/relay-health.ts +0 -148
  1005. package/packages/mcp/src/tools/relay-inbox.ts +0 -70
  1006. package/packages/mcp/src/tools/relay-logs.ts +0 -106
  1007. package/packages/mcp/src/tools/relay-messages.ts +0 -66
  1008. package/packages/mcp/src/tools/relay-metrics.ts +0 -142
  1009. package/packages/mcp/src/tools/relay-release.ts +0 -54
  1010. package/packages/mcp/src/tools/relay-remove-agent.ts +0 -58
  1011. package/packages/mcp/src/tools/relay-send.ts +0 -84
  1012. package/packages/mcp/src/tools/relay-set-model.ts +0 -62
  1013. package/packages/mcp/src/tools/relay-shadow.ts +0 -67
  1014. package/packages/mcp/src/tools/relay-spawn.ts +0 -87
  1015. package/packages/mcp/src/tools/relay-status.ts +0 -57
  1016. package/packages/mcp/src/tools/relay-subscribe.ts +0 -61
  1017. package/packages/mcp/src/tools/relay-who.ts +0 -75
  1018. package/packages/mcp/tests/client.test.ts +0 -451
  1019. package/packages/mcp/tests/discover.test.ts +0 -256
  1020. package/packages/mcp/tests/install.test.ts +0 -123
  1021. package/packages/mcp/tests/prompts.test.ts +0 -12
  1022. package/packages/mcp/tests/resources.test.ts +0 -53
  1023. package/packages/mcp/tests/tools.test.ts +0 -1516
  1024. package/packages/mcp/tsconfig.json +0 -22
  1025. package/packages/mcp/vitest.config.ts +0 -9
  1026. package/packages/protocol/dist/channels.d.ts +0 -137
  1027. package/packages/protocol/dist/channels.d.ts.map +0 -1
  1028. package/packages/protocol/dist/channels.js +0 -154
  1029. package/packages/protocol/dist/channels.js.map +0 -1
  1030. package/packages/protocol/dist/framing.d.ts +0 -80
  1031. package/packages/protocol/dist/framing.d.ts.map +0 -1
  1032. package/packages/protocol/dist/framing.js +0 -206
  1033. package/packages/protocol/dist/framing.js.map +0 -1
  1034. package/packages/protocol/dist/id-generator.d.ts +0 -35
  1035. package/packages/protocol/dist/id-generator.d.ts.map +0 -1
  1036. package/packages/protocol/dist/id-generator.js +0 -60
  1037. package/packages/protocol/dist/id-generator.js.map +0 -1
  1038. package/packages/protocol/dist/index.d.ts +0 -5
  1039. package/packages/protocol/dist/index.d.ts.map +0 -1
  1040. package/packages/protocol/dist/index.js +0 -5
  1041. package/packages/protocol/dist/index.js.map +0 -1
  1042. package/packages/protocol/dist/relay-pty-schemas.d.ts +0 -340
  1043. package/packages/protocol/dist/relay-pty-schemas.d.ts.map +0 -1
  1044. package/packages/protocol/dist/relay-pty-schemas.js +0 -60
  1045. package/packages/protocol/dist/relay-pty-schemas.js.map +0 -1
  1046. package/packages/protocol/dist/types.d.ts +0 -793
  1047. package/packages/protocol/dist/types.d.ts.map +0 -1
  1048. package/packages/protocol/dist/types.js +0 -8
  1049. package/packages/protocol/dist/types.js.map +0 -1
  1050. package/packages/protocol/package.json +0 -61
  1051. package/packages/protocol/src/channels.test.ts +0 -330
  1052. package/packages/protocol/src/channels.ts +0 -270
  1053. package/packages/protocol/src/framing.test.ts +0 -164
  1054. package/packages/protocol/src/framing.ts +0 -242
  1055. package/packages/protocol/src/id-generator.ts +0 -69
  1056. package/packages/protocol/src/index.ts +0 -4
  1057. package/packages/protocol/src/relay-pty-schemas.ts +0 -400
  1058. package/packages/protocol/src/types.test.ts +0 -271
  1059. package/packages/protocol/src/types.ts +0 -988
  1060. package/packages/protocol/tsconfig.json +0 -21
  1061. package/packages/protocol/vitest.config.ts +0 -9
  1062. package/packages/resiliency/dist/cgroup-manager.d.ts +0 -152
  1063. package/packages/resiliency/dist/cgroup-manager.d.ts.map +0 -1
  1064. package/packages/resiliency/dist/cgroup-manager.js +0 -394
  1065. package/packages/resiliency/dist/cgroup-manager.js.map +0 -1
  1066. package/packages/resiliency/dist/context-persistence.d.ts +0 -140
  1067. package/packages/resiliency/dist/context-persistence.d.ts.map +0 -1
  1068. package/packages/resiliency/dist/context-persistence.js +0 -397
  1069. package/packages/resiliency/dist/context-persistence.js.map +0 -1
  1070. package/packages/resiliency/dist/crash-insights.d.ts +0 -156
  1071. package/packages/resiliency/dist/crash-insights.d.ts.map +0 -1
  1072. package/packages/resiliency/dist/crash-insights.js +0 -492
  1073. package/packages/resiliency/dist/crash-insights.js.map +0 -1
  1074. package/packages/resiliency/dist/gossip-health.d.ts +0 -137
  1075. package/packages/resiliency/dist/gossip-health.d.ts.map +0 -1
  1076. package/packages/resiliency/dist/gossip-health.js +0 -241
  1077. package/packages/resiliency/dist/gossip-health.js.map +0 -1
  1078. package/packages/resiliency/dist/health-monitor.d.ts +0 -97
  1079. package/packages/resiliency/dist/health-monitor.d.ts.map +0 -1
  1080. package/packages/resiliency/dist/health-monitor.js +0 -291
  1081. package/packages/resiliency/dist/health-monitor.js.map +0 -1
  1082. package/packages/resiliency/dist/index.d.ts +0 -69
  1083. package/packages/resiliency/dist/index.d.ts.map +0 -1
  1084. package/packages/resiliency/dist/index.js +0 -69
  1085. package/packages/resiliency/dist/index.js.map +0 -1
  1086. package/packages/resiliency/dist/leader-watchdog.d.ts +0 -109
  1087. package/packages/resiliency/dist/leader-watchdog.d.ts.map +0 -1
  1088. package/packages/resiliency/dist/leader-watchdog.js +0 -189
  1089. package/packages/resiliency/dist/leader-watchdog.js.map +0 -1
  1090. package/packages/resiliency/dist/logger.d.ts +0 -114
  1091. package/packages/resiliency/dist/logger.d.ts.map +0 -1
  1092. package/packages/resiliency/dist/logger.js +0 -250
  1093. package/packages/resiliency/dist/logger.js.map +0 -1
  1094. package/packages/resiliency/dist/memory-monitor.d.ts +0 -172
  1095. package/packages/resiliency/dist/memory-monitor.d.ts.map +0 -1
  1096. package/packages/resiliency/dist/memory-monitor.js +0 -599
  1097. package/packages/resiliency/dist/memory-monitor.js.map +0 -1
  1098. package/packages/resiliency/dist/metrics.d.ts +0 -115
  1099. package/packages/resiliency/dist/metrics.d.ts.map +0 -1
  1100. package/packages/resiliency/dist/metrics.js +0 -239
  1101. package/packages/resiliency/dist/metrics.js.map +0 -1
  1102. package/packages/resiliency/dist/provider-context.d.ts +0 -100
  1103. package/packages/resiliency/dist/provider-context.d.ts.map +0 -1
  1104. package/packages/resiliency/dist/provider-context.js +0 -362
  1105. package/packages/resiliency/dist/provider-context.js.map +0 -1
  1106. package/packages/resiliency/dist/stateless-lead.d.ts +0 -149
  1107. package/packages/resiliency/dist/stateless-lead.d.ts.map +0 -1
  1108. package/packages/resiliency/dist/stateless-lead.js +0 -308
  1109. package/packages/resiliency/dist/stateless-lead.js.map +0 -1
  1110. package/packages/resiliency/dist/supervisor.d.ts +0 -147
  1111. package/packages/resiliency/dist/supervisor.d.ts.map +0 -1
  1112. package/packages/resiliency/dist/supervisor.js +0 -459
  1113. package/packages/resiliency/dist/supervisor.js.map +0 -1
  1114. package/packages/resiliency/package.json +0 -38
  1115. package/packages/resiliency/src/cgroup-manager.ts +0 -468
  1116. package/packages/resiliency/src/context-persistence.ts +0 -538
  1117. package/packages/resiliency/src/crash-insights.test.ts +0 -620
  1118. package/packages/resiliency/src/crash-insights.ts +0 -660
  1119. package/packages/resiliency/src/gossip-health.ts +0 -333
  1120. package/packages/resiliency/src/health-monitor.ts +0 -371
  1121. package/packages/resiliency/src/index.ts +0 -157
  1122. package/packages/resiliency/src/leader-watchdog.ts +0 -260
  1123. package/packages/resiliency/src/logger.ts +0 -320
  1124. package/packages/resiliency/src/memory-monitor.test.ts +0 -637
  1125. package/packages/resiliency/src/memory-monitor.ts +0 -740
  1126. package/packages/resiliency/src/metrics.ts +0 -311
  1127. package/packages/resiliency/src/provider-context.ts +0 -452
  1128. package/packages/resiliency/src/stateless-lead.ts +0 -408
  1129. package/packages/resiliency/src/supervisor.ts +0 -578
  1130. package/packages/resiliency/tsconfig.json +0 -21
  1131. package/packages/resiliency/vitest.config.ts +0 -9
  1132. package/packages/sdk/dist/discovery.d.ts +0 -10
  1133. package/packages/sdk/dist/discovery.d.ts.map +0 -1
  1134. package/packages/sdk/dist/discovery.js +0 -22
  1135. package/packages/sdk/dist/discovery.js.map +0 -1
  1136. package/packages/sdk/dist/errors.d.ts +0 -9
  1137. package/packages/sdk/dist/errors.d.ts.map +0 -1
  1138. package/packages/sdk/dist/errors.js +0 -9
  1139. package/packages/sdk/dist/errors.js.map +0 -1
  1140. package/packages/sdk/dist/protocol/index.d.ts +0 -8
  1141. package/packages/sdk/dist/protocol/index.d.ts.map +0 -1
  1142. package/packages/sdk/dist/protocol/index.js +0 -8
  1143. package/packages/sdk/dist/protocol/index.js.map +0 -1
  1144. package/packages/sdk/examples/SWARM_CAPABILITIES.md +0 -498
  1145. package/packages/sdk/examples/SWARM_PATTERNS.md +0 -541
  1146. package/packages/sdk/src/client.test.ts +0 -1041
  1147. package/packages/sdk/src/discovery.ts +0 -38
  1148. package/packages/sdk/src/errors.ts +0 -17
  1149. package/packages/sdk/src/logs.test.ts +0 -98
  1150. package/packages/sdk/src/protocol/framing.test.ts +0 -164
  1151. package/packages/sdk/src/protocol/index.ts +0 -8
  1152. package/packages/spawner/.trajectories/index.json +0 -5
  1153. package/packages/spawner/API.md +0 -256
  1154. package/packages/spawner/dist/index.d.ts +0 -8
  1155. package/packages/spawner/dist/index.d.ts.map +0 -1
  1156. package/packages/spawner/dist/index.js +0 -8
  1157. package/packages/spawner/dist/index.js.map +0 -1
  1158. package/packages/spawner/dist/types.d.ts +0 -552
  1159. package/packages/spawner/dist/types.d.ts.map +0 -1
  1160. package/packages/spawner/dist/types.js +0 -193
  1161. package/packages/spawner/dist/types.js.map +0 -1
  1162. package/packages/spawner/package.json +0 -47
  1163. package/packages/spawner/src/index.ts +0 -8
  1164. package/packages/spawner/src/types.test.ts +0 -385
  1165. package/packages/spawner/src/types.ts +0 -228
  1166. package/packages/spawner/tsconfig.json +0 -19
  1167. package/packages/spawner/vitest.config.ts +0 -9
  1168. package/packages/state/dist/agent-state.d.ts +0 -40
  1169. package/packages/state/dist/agent-state.d.ts.map +0 -1
  1170. package/packages/state/dist/agent-state.js +0 -120
  1171. package/packages/state/dist/agent-state.js.map +0 -1
  1172. package/packages/state/dist/index.d.ts +0 -8
  1173. package/packages/state/dist/index.d.ts.map +0 -1
  1174. package/packages/state/dist/index.js +0 -8
  1175. package/packages/state/dist/index.js.map +0 -1
  1176. package/packages/state/package.json +0 -37
  1177. package/packages/state/src/agent-state.test.ts +0 -335
  1178. package/packages/state/src/agent-state.ts +0 -153
  1179. package/packages/state/src/index.ts +0 -12
  1180. package/packages/state/tsconfig.json +0 -21
  1181. package/packages/state/vitest.config.ts +0 -9
  1182. package/packages/storage/dist/adapter.d.ts +0 -189
  1183. package/packages/storage/dist/adapter.d.ts.map +0 -1
  1184. package/packages/storage/dist/adapter.js +0 -267
  1185. package/packages/storage/dist/adapter.js.map +0 -1
  1186. package/packages/storage/dist/batched-sqlite-adapter.d.ts +0 -75
  1187. package/packages/storage/dist/batched-sqlite-adapter.d.ts.map +0 -1
  1188. package/packages/storage/dist/batched-sqlite-adapter.js +0 -189
  1189. package/packages/storage/dist/batched-sqlite-adapter.js.map +0 -1
  1190. package/packages/storage/dist/dead-letter-queue.d.ts +0 -196
  1191. package/packages/storage/dist/dead-letter-queue.d.ts.map +0 -1
  1192. package/packages/storage/dist/dead-letter-queue.js +0 -427
  1193. package/packages/storage/dist/dead-letter-queue.js.map +0 -1
  1194. package/packages/storage/dist/dlq-adapter.d.ts +0 -195
  1195. package/packages/storage/dist/dlq-adapter.d.ts.map +0 -1
  1196. package/packages/storage/dist/dlq-adapter.js +0 -664
  1197. package/packages/storage/dist/dlq-adapter.js.map +0 -1
  1198. package/packages/storage/dist/index.d.ts +0 -6
  1199. package/packages/storage/dist/index.d.ts.map +0 -1
  1200. package/packages/storage/dist/index.js +0 -7
  1201. package/packages/storage/dist/index.js.map +0 -1
  1202. package/packages/storage/dist/jsonl-adapter.d.ts +0 -91
  1203. package/packages/storage/dist/jsonl-adapter.d.ts.map +0 -1
  1204. package/packages/storage/dist/jsonl-adapter.js +0 -580
  1205. package/packages/storage/dist/jsonl-adapter.js.map +0 -1
  1206. package/packages/storage/dist/sqlite-adapter.d.ts +0 -131
  1207. package/packages/storage/dist/sqlite-adapter.d.ts.map +0 -1
  1208. package/packages/storage/dist/sqlite-adapter.js +0 -865
  1209. package/packages/storage/dist/sqlite-adapter.js.map +0 -1
  1210. package/packages/storage/package.json +0 -74
  1211. package/packages/storage/src/adapter.ts +0 -446
  1212. package/packages/storage/src/batched-sqlite-adapter.test.ts +0 -256
  1213. package/packages/storage/src/batched-sqlite-adapter.ts +0 -239
  1214. package/packages/storage/src/dead-letter-queue.ts +0 -643
  1215. package/packages/storage/src/dlq-adapter.test.ts +0 -509
  1216. package/packages/storage/src/dlq-adapter.ts +0 -954
  1217. package/packages/storage/src/index.ts +0 -6
  1218. package/packages/storage/src/jsonl-adapter.test.ts +0 -239
  1219. package/packages/storage/src/jsonl-adapter.ts +0 -704
  1220. package/packages/storage/src/memory-adapter.test.ts +0 -36
  1221. package/packages/storage/src/sqlite-adapter.test.ts +0 -580
  1222. package/packages/storage/src/sqlite-adapter.ts +0 -1099
  1223. package/packages/storage/tsconfig.json +0 -21
  1224. package/packages/storage/vitest.config.ts +0 -9
  1225. package/packages/wrapper/dist/__fixtures__/claude-outputs.d.ts +0 -49
  1226. package/packages/wrapper/dist/__fixtures__/claude-outputs.d.ts.map +0 -1
  1227. package/packages/wrapper/dist/__fixtures__/claude-outputs.js +0 -443
  1228. package/packages/wrapper/dist/__fixtures__/claude-outputs.js.map +0 -1
  1229. package/packages/wrapper/dist/__fixtures__/codex-outputs.d.ts +0 -9
  1230. package/packages/wrapper/dist/__fixtures__/codex-outputs.d.ts.map +0 -1
  1231. package/packages/wrapper/dist/__fixtures__/codex-outputs.js +0 -94
  1232. package/packages/wrapper/dist/__fixtures__/codex-outputs.js.map +0 -1
  1233. package/packages/wrapper/dist/__fixtures__/gemini-outputs.d.ts +0 -19
  1234. package/packages/wrapper/dist/__fixtures__/gemini-outputs.d.ts.map +0 -1
  1235. package/packages/wrapper/dist/__fixtures__/gemini-outputs.js +0 -144
  1236. package/packages/wrapper/dist/__fixtures__/gemini-outputs.js.map +0 -1
  1237. package/packages/wrapper/dist/__fixtures__/index.d.ts +0 -68
  1238. package/packages/wrapper/dist/__fixtures__/index.d.ts.map +0 -1
  1239. package/packages/wrapper/dist/__fixtures__/index.js +0 -44
  1240. package/packages/wrapper/dist/__fixtures__/index.js.map +0 -1
  1241. package/packages/wrapper/dist/auth-detection.d.ts +0 -49
  1242. package/packages/wrapper/dist/auth-detection.d.ts.map +0 -1
  1243. package/packages/wrapper/dist/auth-detection.js +0 -199
  1244. package/packages/wrapper/dist/auth-detection.js.map +0 -1
  1245. package/packages/wrapper/dist/base-wrapper.d.ts +0 -254
  1246. package/packages/wrapper/dist/base-wrapper.d.ts.map +0 -1
  1247. package/packages/wrapper/dist/base-wrapper.js +0 -664
  1248. package/packages/wrapper/dist/base-wrapper.js.map +0 -1
  1249. package/packages/wrapper/dist/client.d.ts +0 -291
  1250. package/packages/wrapper/dist/client.d.ts.map +0 -1
  1251. package/packages/wrapper/dist/client.js +0 -926
  1252. package/packages/wrapper/dist/client.js.map +0 -1
  1253. package/packages/wrapper/dist/id-generator.d.ts +0 -35
  1254. package/packages/wrapper/dist/id-generator.d.ts.map +0 -1
  1255. package/packages/wrapper/dist/id-generator.js +0 -60
  1256. package/packages/wrapper/dist/id-generator.js.map +0 -1
  1257. package/packages/wrapper/dist/idle-detector.d.ts +0 -114
  1258. package/packages/wrapper/dist/idle-detector.d.ts.map +0 -1
  1259. package/packages/wrapper/dist/idle-detector.js +0 -317
  1260. package/packages/wrapper/dist/idle-detector.js.map +0 -1
  1261. package/packages/wrapper/dist/inbox.d.ts +0 -37
  1262. package/packages/wrapper/dist/inbox.d.ts.map +0 -1
  1263. package/packages/wrapper/dist/inbox.js +0 -73
  1264. package/packages/wrapper/dist/inbox.js.map +0 -1
  1265. package/packages/wrapper/dist/index.d.ts +0 -40
  1266. package/packages/wrapper/dist/index.d.ts.map +0 -1
  1267. package/packages/wrapper/dist/index.js +0 -53
  1268. package/packages/wrapper/dist/index.js.map +0 -1
  1269. package/packages/wrapper/dist/opencode-api.d.ts +0 -106
  1270. package/packages/wrapper/dist/opencode-api.d.ts.map +0 -1
  1271. package/packages/wrapper/dist/opencode-api.js +0 -219
  1272. package/packages/wrapper/dist/opencode-api.js.map +0 -1
  1273. package/packages/wrapper/dist/opencode-wrapper.d.ts +0 -161
  1274. package/packages/wrapper/dist/opencode-wrapper.d.ts.map +0 -1
  1275. package/packages/wrapper/dist/opencode-wrapper.js +0 -438
  1276. package/packages/wrapper/dist/opencode-wrapper.js.map +0 -1
  1277. package/packages/wrapper/dist/parser.d.ts +0 -236
  1278. package/packages/wrapper/dist/parser.d.ts.map +0 -1
  1279. package/packages/wrapper/dist/parser.js +0 -1238
  1280. package/packages/wrapper/dist/parser.js.map +0 -1
  1281. package/packages/wrapper/dist/prompt-composer.d.ts +0 -67
  1282. package/packages/wrapper/dist/prompt-composer.d.ts.map +0 -1
  1283. package/packages/wrapper/dist/prompt-composer.js +0 -168
  1284. package/packages/wrapper/dist/prompt-composer.js.map +0 -1
  1285. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts +0 -486
  1286. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts.map +0 -1
  1287. package/packages/wrapper/dist/relay-pty-orchestrator.js +0 -2550
  1288. package/packages/wrapper/dist/relay-pty-orchestrator.js.map +0 -1
  1289. package/packages/wrapper/dist/shared.d.ts +0 -262
  1290. package/packages/wrapper/dist/shared.d.ts.map +0 -1
  1291. package/packages/wrapper/dist/shared.js +0 -507
  1292. package/packages/wrapper/dist/shared.js.map +0 -1
  1293. package/packages/wrapper/dist/stuck-detector.d.ts +0 -161
  1294. package/packages/wrapper/dist/stuck-detector.d.ts.map +0 -1
  1295. package/packages/wrapper/dist/stuck-detector.js +0 -402
  1296. package/packages/wrapper/dist/stuck-detector.js.map +0 -1
  1297. package/packages/wrapper/dist/tmux-resolver.d.ts +0 -55
  1298. package/packages/wrapper/dist/tmux-resolver.d.ts.map +0 -1
  1299. package/packages/wrapper/dist/tmux-resolver.js +0 -175
  1300. package/packages/wrapper/dist/tmux-resolver.js.map +0 -1
  1301. package/packages/wrapper/dist/tmux-wrapper.d.ts +0 -352
  1302. package/packages/wrapper/dist/tmux-wrapper.d.ts.map +0 -1
  1303. package/packages/wrapper/dist/tmux-wrapper.js +0 -1816
  1304. package/packages/wrapper/dist/tmux-wrapper.js.map +0 -1
  1305. package/packages/wrapper/dist/trajectory-integration.d.ts +0 -292
  1306. package/packages/wrapper/dist/trajectory-integration.d.ts.map +0 -1
  1307. package/packages/wrapper/dist/trajectory-integration.js +0 -979
  1308. package/packages/wrapper/dist/trajectory-integration.js.map +0 -1
  1309. package/packages/wrapper/dist/wrapper-events.d.ts +0 -489
  1310. package/packages/wrapper/dist/wrapper-events.d.ts.map +0 -1
  1311. package/packages/wrapper/dist/wrapper-events.js +0 -252
  1312. package/packages/wrapper/dist/wrapper-events.js.map +0 -1
  1313. package/packages/wrapper/dist/wrapper-types.d.ts +0 -41
  1314. package/packages/wrapper/dist/wrapper-types.d.ts.map +0 -1
  1315. package/packages/wrapper/dist/wrapper-types.js +0 -7
  1316. package/packages/wrapper/dist/wrapper-types.js.map +0 -1
  1317. package/packages/wrapper/package.json +0 -60
  1318. package/packages/wrapper/src/__fixtures__/claude-outputs.ts +0 -471
  1319. package/packages/wrapper/src/__fixtures__/codex-outputs.ts +0 -99
  1320. package/packages/wrapper/src/__fixtures__/gemini-outputs.ts +0 -151
  1321. package/packages/wrapper/src/__fixtures__/index.ts +0 -47
  1322. package/packages/wrapper/src/auth-detection.ts +0 -244
  1323. package/packages/wrapper/src/base-wrapper.test.ts +0 -589
  1324. package/packages/wrapper/src/base-wrapper.ts +0 -841
  1325. package/packages/wrapper/src/client.test.ts +0 -351
  1326. package/packages/wrapper/src/client.ts +0 -1166
  1327. package/packages/wrapper/src/id-generator.test.ts +0 -71
  1328. package/packages/wrapper/src/id-generator.ts +0 -69
  1329. package/packages/wrapper/src/idle-detector.test.ts +0 -418
  1330. package/packages/wrapper/src/idle-detector.ts +0 -384
  1331. package/packages/wrapper/src/inbox.test.ts +0 -233
  1332. package/packages/wrapper/src/inbox.ts +0 -89
  1333. package/packages/wrapper/src/index.ts +0 -199
  1334. package/packages/wrapper/src/opencode-api.test.ts +0 -292
  1335. package/packages/wrapper/src/opencode-api.ts +0 -285
  1336. package/packages/wrapper/src/opencode-wrapper.ts +0 -541
  1337. package/packages/wrapper/src/parser.regression.test.ts +0 -251
  1338. package/packages/wrapper/src/parser.test.ts +0 -1359
  1339. package/packages/wrapper/src/parser.ts +0 -1477
  1340. package/packages/wrapper/src/prompt-composer.test.ts +0 -219
  1341. package/packages/wrapper/src/prompt-composer.ts +0 -231
  1342. package/packages/wrapper/src/relay-pty-orchestrator.test.ts +0 -1386
  1343. package/packages/wrapper/src/relay-pty-orchestrator.ts +0 -3041
  1344. package/packages/wrapper/src/shared.test.ts +0 -467
  1345. package/packages/wrapper/src/shared.ts +0 -652
  1346. package/packages/wrapper/src/stuck-detector.test.ts +0 -303
  1347. package/packages/wrapper/src/stuck-detector.ts +0 -511
  1348. package/packages/wrapper/src/tmux-resolver.test.ts +0 -104
  1349. package/packages/wrapper/src/tmux-resolver.ts +0 -207
  1350. package/packages/wrapper/src/tmux-wrapper.test.ts +0 -316
  1351. package/packages/wrapper/src/tmux-wrapper.ts +0 -2095
  1352. package/packages/wrapper/src/trajectory-detection.test.ts +0 -151
  1353. package/packages/wrapper/src/trajectory-integration.ts +0 -1261
  1354. package/packages/wrapper/src/wrapper-events.ts +0 -395
  1355. package/packages/wrapper/src/wrapper-types.ts +0 -45
  1356. package/packages/wrapper/tsconfig.json +0 -19
  1357. package/packages/wrapper/vitest.config.ts +0 -9
  1358. /package/packages/{broker-sdk → sdk}/dist/__tests__/facade.test.d.ts +0 -0
  1359. /package/packages/{broker-sdk → sdk}/dist/__tests__/facade.test.d.ts.map +0 -0
  1360. /package/packages/{broker-sdk → sdk}/dist/__tests__/integration.test.d.ts +0 -0
  1361. /package/packages/{broker-sdk → sdk}/dist/__tests__/integration.test.d.ts.map +0 -0
  1362. /package/packages/{broker-sdk → sdk}/dist/__tests__/quickstart.test.d.ts +0 -0
  1363. /package/packages/{broker-sdk → sdk}/dist/__tests__/quickstart.test.d.ts.map +0 -0
  1364. /package/packages/{broker-sdk → sdk}/dist/__tests__/unit.test.d.ts +0 -0
  1365. /package/packages/{broker-sdk → sdk}/dist/__tests__/unit.test.d.ts.map +0 -0
  1366. /package/packages/{broker-sdk → sdk}/dist/browser.d.ts +0 -0
  1367. /package/packages/{broker-sdk → sdk}/dist/browser.d.ts.map +0 -0
  1368. /package/packages/{broker-sdk → sdk}/dist/browser.js +0 -0
  1369. /package/packages/{broker-sdk → sdk}/dist/browser.js.map +0 -0
  1370. /package/packages/{broker-sdk → sdk}/dist/consensus-helpers.d.ts +0 -0
  1371. /package/packages/{broker-sdk → sdk}/dist/consensus-helpers.d.ts.map +0 -0
  1372. /package/packages/{broker-sdk → sdk}/dist/consensus-helpers.js +0 -0
  1373. /package/packages/{broker-sdk → sdk}/dist/consensus-helpers.js.map +0 -0
  1374. /package/packages/{broker-sdk → sdk}/dist/consensus.d.ts +0 -0
  1375. /package/packages/{broker-sdk → sdk}/dist/consensus.d.ts.map +0 -0
  1376. /package/packages/{broker-sdk → sdk}/dist/consensus.js +0 -0
  1377. /package/packages/{broker-sdk → sdk}/dist/consensus.js.map +0 -0
  1378. /package/packages/{broker-sdk → sdk}/dist/examples/demo.d.ts +0 -0
  1379. /package/packages/{broker-sdk → sdk}/dist/examples/demo.d.ts.map +0 -0
  1380. /package/packages/{broker-sdk → sdk}/dist/examples/demo.js +0 -0
  1381. /package/packages/{broker-sdk → sdk}/dist/examples/demo.js.map +0 -0
  1382. /package/packages/{broker-sdk → sdk}/dist/examples/example.d.ts +0 -0
  1383. /package/packages/{broker-sdk → sdk}/dist/examples/example.d.ts.map +0 -0
  1384. /package/packages/{broker-sdk → sdk}/dist/examples/example.js +0 -0
  1385. /package/packages/{broker-sdk → sdk}/dist/examples/example.js.map +0 -0
  1386. /package/packages/{broker-sdk → sdk}/dist/examples/quickstart.d.ts +0 -0
  1387. /package/packages/{broker-sdk → sdk}/dist/examples/quickstart.d.ts.map +0 -0
  1388. /package/packages/{broker-sdk → sdk}/dist/examples/quickstart.js +0 -0
  1389. /package/packages/{broker-sdk → sdk}/dist/examples/quickstart.js.map +0 -0
  1390. /package/packages/{broker-sdk → sdk}/dist/examples/ralph-loop.d.ts +0 -0
  1391. /package/packages/{broker-sdk → sdk}/dist/examples/ralph-loop.d.ts.map +0 -0
  1392. /package/packages/{broker-sdk → sdk}/dist/examples/ralph-loop.js +0 -0
  1393. /package/packages/{broker-sdk → sdk}/dist/examples/ralph-loop.js.map +0 -0
  1394. /package/packages/{broker-sdk → sdk}/dist/protocol.js +0 -0
  1395. /package/packages/{broker-sdk → sdk}/dist/protocol.js.map +0 -0
  1396. /package/packages/{broker-sdk → sdk}/dist/pty.d.ts +0 -0
  1397. /package/packages/{broker-sdk → sdk}/dist/shadow.js +0 -0
  1398. /package/packages/{broker-sdk → sdk}/dist/workflows/barrier.d.ts +0 -0
  1399. /package/packages/{broker-sdk → sdk}/dist/workflows/barrier.d.ts.map +0 -0
  1400. /package/packages/{broker-sdk → sdk}/dist/workflows/barrier.js +0 -0
  1401. /package/packages/{broker-sdk → sdk}/dist/workflows/barrier.js.map +0 -0
  1402. /package/packages/{broker-sdk → sdk}/dist/workflows/memory-db.d.ts +0 -0
  1403. /package/packages/{broker-sdk → sdk}/dist/workflows/memory-db.d.ts.map +0 -0
  1404. /package/packages/{broker-sdk → sdk}/dist/workflows/memory-db.js +0 -0
  1405. /package/packages/{broker-sdk → sdk}/dist/workflows/memory-db.js.map +0 -0
  1406. /package/packages/{broker-sdk → sdk}/dist/workflows/state.d.ts +0 -0
  1407. /package/packages/{broker-sdk → sdk}/dist/workflows/state.d.ts.map +0 -0
  1408. /package/packages/{broker-sdk → sdk}/dist/workflows/state.js +0 -0
  1409. /package/packages/{broker-sdk → sdk}/dist/workflows/state.js.map +0 -0
  1410. /package/packages/{broker-sdk → sdk}/src/__tests__/workflow-trajectory.test.ts +0 -0
  1411. /package/packages/{broker-sdk → sdk}/src/browser.ts +0 -0
  1412. /package/packages/{broker-sdk → sdk}/src/consensus-helpers.ts +0 -0
  1413. /package/packages/{broker-sdk → sdk}/src/consensus.ts +0 -0
  1414. /package/packages/{broker-sdk → sdk}/src/examples/demo.ts +0 -0
  1415. /package/packages/{broker-sdk → sdk}/src/examples/example.ts +0 -0
  1416. /package/packages/{broker-sdk → sdk}/src/examples/quickstart.ts +0 -0
  1417. /package/packages/{broker-sdk → sdk}/src/examples/ralph-loop.ts +0 -0
  1418. /package/packages/{broker-sdk → sdk}/src/examples/sample-prd.json +0 -0
  1419. /package/packages/{broker-sdk → sdk}/src/workflows/barrier.ts +0 -0
  1420. /package/packages/{broker-sdk → sdk}/src/workflows/memory-db.ts +0 -0
  1421. /package/packages/{broker-sdk → sdk}/src/workflows/state.ts +0 -0
@@ -1,3041 +0,0 @@
1
- /**
2
- * RelayPtyOrchestrator - Orchestrates the relay-pty Rust binary
3
- *
4
- * This wrapper spawns the relay-pty binary and communicates via Unix socket.
5
- * It provides the same interface as PtyWrapper but with improved latency
6
- * (~550ms vs ~1700ms) by using direct PTY writes instead of tmux send-keys.
7
- *
8
- * Architecture:
9
- * 1. Spawn relay-pty --name {agentName} -- {command} as child process
10
- * 2. Connect to socket for injection:
11
- * - With WORKSPACE_ID: /tmp/relay/{workspaceId}/sockets/{agentName}.sock
12
- * - Without: /tmp/relay-pty-{agentName}.sock (legacy)
13
- * 3. Parse stdout for relay commands (relay-pty echoes all output)
14
- * 4. Translate SEND envelopes → inject messages via socket
15
- *
16
- * @see docs/RUST_WRAPPER_DESIGN.md for protocol details
17
- */
18
-
19
- import { spawn, ChildProcess } from 'node:child_process';
20
- import { createConnection, Socket } from 'node:net';
21
- import { createHash } from 'node:crypto';
22
- import { join, dirname } from 'node:path';
23
- import { homedir, freemem, totalmem } from 'node:os';
24
- import { execSync } from 'node:child_process';
25
- import {
26
- existsSync,
27
- unlinkSync,
28
- mkdirSync,
29
- symlinkSync,
30
- lstatSync,
31
- rmSync,
32
- watch,
33
- readdirSync,
34
- readlinkSync,
35
- writeFileSync,
36
- appendFileSync,
37
- accessSync,
38
- constants as fsConstants,
39
- } from 'node:fs';
40
- import type { FSWatcher } from 'node:fs';
41
- import { getProjectPaths } from '@agent-relay/config/project-namespace';
42
- import { getAgentOutboxTemplate } from '@agent-relay/config/relay-file-writer';
43
- import { fileURLToPath } from 'node:url';
44
-
45
- // Get the directory where this module is located
46
- const __filename = fileURLToPath(import.meta.url);
47
- const __dirname = dirname(__filename);
48
- import { BaseWrapper, type BaseWrapperConfig } from './base-wrapper.js';
49
- import { parseSummaryWithDetails, parseSessionEndFromOutput } from './parser.js';
50
- import type { SendPayload, SendMeta, Envelope } from '@agent-relay/protocol/types';
51
- import type { ChannelMessagePayload } from '@agent-relay/protocol/channels';
52
- import { findRelayPtyBinary as findRelayPtyBinaryUtil } from '@agent-relay/utils/relay-pty-path';
53
- import {
54
- type QueuedMessage,
55
- stripAnsi,
56
- sleep,
57
- buildInjectionString,
58
- AdaptiveThrottle,
59
- } from './shared.js';
60
- import {
61
- getMemoryMonitor,
62
- type AgentMemoryMonitor,
63
- type MemoryAlert,
64
- formatBytes,
65
- getCgroupManager,
66
- type CgroupManager,
67
- } from '@agent-relay/resiliency';
68
-
69
- // ============================================================================
70
- // Types for relay-pty socket protocol
71
- // ============================================================================
72
-
73
- const MAX_SOCKET_PATH_LENGTH = 107;
74
-
75
- /**
76
- * Maximum size for output buffers (rawBuffer, outputBuffer) in bytes.
77
- * Prevents RangeError: Invalid string length when agents produce lots of output.
78
- * Set to 10MB - enough to capture context but won't exhaust memory.
79
- */
80
- const MAX_OUTPUT_BUFFER_SIZE = 10 * 1024 * 1024; // 10MB
81
-
82
- // ============================================================================
83
- // Activity Verification Constants
84
- // ============================================================================
85
-
86
- /**
87
- * Activity patterns used to verify that a CLI has received and started processing
88
- * an injected task. These patterns work across Claude Code, Codex, and Droid/Gemini.
89
- *
90
- * The problem we're solving: Rust confirms "delivered to PTY" but that doesn't mean
91
- * the CLI processed it. The T-003 failure showed the CLI wasn't ready when input arrived.
92
- *
93
- * @see https://github.com/your-org/relay/issues/XXX for the original investigation
94
- */
95
- const ACTIVITY_VERIFICATION = {
96
- /** Time to wait for activity patterns after injection (ms) */
97
- TIMEOUT_MS: 5000,
98
- /** How often to check for activity patterns (ms) */
99
- POLL_INTERVAL_MS: 200,
100
- /** Maximum retries when no activity is detected */
101
- MAX_RETRIES: 3,
102
- /** Delay between retries (ms) */
103
- RETRY_DELAY_MS: 500,
104
-
105
- /**
106
- * Patterns indicating the task was received and displayed.
107
- * These are the primary verification patterns.
108
- */
109
- TASK_RECEIVED_PATTERNS: [
110
- /\[Pasted text #\d+/, // Claude Code shows "[Pasted text #1 +95 lines]"
111
- /› Relay message from/, // Codex shows "› Relay message from"
112
- /Relay message from \w+ \[[\w-]+\]/, // Droid/Gemini shows "Relay message from Agent [id]:"
113
- ],
114
-
115
- /**
116
- * Patterns indicating the CLI is thinking/processing.
117
- * Secondary verification - proves the CLI is active.
118
- */
119
- THINKING_PATTERNS: [
120
- /\(.*esc to (?:interrupt|stop)\)/i, // All CLIs: "(esc to interrupt)" or "(Press ESC to stop)"
121
- /[✻✶✳✢·✽⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏]/, // Spinner characters (Claude + Droid)
122
- /Thinking\.\.\./, // Droid: "Thinking..."
123
- /Working/, // Codex: "Working"
124
- /Forming|Noodling|Manifesting/i, // Claude Code thinking states
125
- ],
126
-
127
- /**
128
- * Patterns indicating tool execution started.
129
- * Tertiary verification - proves the CLI is working.
130
- */
131
- TOOL_EXECUTION_PATTERNS: [
132
- /⏺\s*(Bash|Read|Write|Edit|Glob|Grep|Task|WebFetch)/, // Claude Code tool markers
133
- /•\s*Running/, // Codex: "• Running: command"
134
- ],
135
- } as const;
136
-
137
- function hashWorkspaceId(workspaceId: string): string {
138
- return createHash('sha256').update(workspaceId).digest('hex').slice(0, 12);
139
- }
140
-
141
- /**
142
- * Request types sent to relay-pty socket
143
- */
144
- interface InjectRequest {
145
- type: 'inject';
146
- id: string;
147
- from: string;
148
- body: string;
149
- priority: number;
150
- }
151
-
152
- interface StatusRequest {
153
- type: 'status';
154
- }
155
-
156
- interface ShutdownRequest {
157
- type: 'shutdown';
158
- }
159
-
160
- /**
161
- * Send just Enter key (for stuck input recovery)
162
- * Used when message was written to PTY but Enter wasn't processed
163
- */
164
- interface SendEnterRequest {
165
- type: 'send_enter';
166
- /** Message ID this is for (for tracking) */
167
- id: string;
168
- }
169
-
170
- type RelayPtyRequest = InjectRequest | StatusRequest | ShutdownRequest | SendEnterRequest;
171
-
172
- /**
173
- * Response types received from relay-pty socket
174
- */
175
- interface InjectResultResponse {
176
- type: 'inject_result';
177
- id: string;
178
- status: 'queued' | 'injecting' | 'delivered' | 'failed';
179
- timestamp: number;
180
- error?: string;
181
- }
182
-
183
- interface StatusResponse {
184
- type: 'status';
185
- agent_idle: boolean;
186
- queue_length: number;
187
- cursor_position?: [number, number];
188
- last_output_ms: number;
189
- }
190
-
191
- interface BackpressureResponse {
192
- type: 'backpressure';
193
- queue_length: number;
194
- accept: boolean;
195
- }
196
-
197
- interface ErrorResponse {
198
- type: 'error';
199
- message: string;
200
- }
201
-
202
- interface ShutdownAckResponse {
203
- type: 'shutdown_ack';
204
- }
205
-
206
- /**
207
- * Response for SendEnter request (stuck input recovery)
208
- */
209
- interface SendEnterResultResponse {
210
- type: 'send_enter_result';
211
- /** Message ID this is for */
212
- id: string;
213
- /** Whether Enter was sent successfully */
214
- success: boolean;
215
- /** Unix timestamp in milliseconds */
216
- timestamp: number;
217
- }
218
-
219
- type RelayPtyResponse =
220
- | InjectResultResponse
221
- | StatusResponse
222
- | BackpressureResponse
223
- | ErrorResponse
224
- | ShutdownAckResponse
225
- | SendEnterResultResponse;
226
-
227
- /**
228
- * Configuration for RelayPtyOrchestrator
229
- */
230
- export interface RelayPtyOrchestratorConfig extends BaseWrapperConfig {
231
- /** Path to relay-pty binary (default: searches PATH and ./relay-pty/target/release) */
232
- relayPtyPath?: string;
233
- /** Socket connect timeout in ms (default: 5000) */
234
- socketConnectTimeoutMs?: number;
235
- /** Socket reconnect attempts (default: 3) */
236
- socketReconnectAttempts?: number;
237
- /** Callback when agent exits */
238
- onExit?: (code: number) => void;
239
- /** Callback when injection fails after retries */
240
- onInjectionFailed?: (messageId: string, error: string) => void;
241
- /** Enable debug logging (default: false) */
242
- debug?: boolean;
243
- /** Force headless mode (use pipes instead of inheriting TTY) */
244
- headless?: boolean;
245
- /** CPU limit percentage per agent (1-100 per core, e.g., 50 = 50% of one core). Requires cgroups v2. */
246
- cpuLimitPercent?: number;
247
- }
248
-
249
- /**
250
- * Events emitted by RelayPtyOrchestrator
251
- */
252
- export interface RelayPtyOrchestratorEvents {
253
- output: (data: string) => void;
254
- exit: (code: number) => void;
255
- error: (error: Error) => void;
256
- 'injection-failed': (event: { messageId: string; from: string; error: string }) => void;
257
- 'backpressure': (event: { queueLength: number; accept: boolean }) => void;
258
- 'summary': (event: { agentName: string; summary: unknown }) => void;
259
- 'session-end': (event: { agentName: string; marker: unknown }) => void;
260
- }
261
-
262
- /**
263
- * Orchestrator for relay-pty Rust binary
264
- *
265
- * Extends BaseWrapper to provide the same interface as PtyWrapper
266
- * but uses the relay-pty binary for improved injection reliability.
267
- */
268
- export class RelayPtyOrchestrator extends BaseWrapper {
269
- protected override config: RelayPtyOrchestratorConfig;
270
-
271
- // Process management
272
- private relayPtyProcess?: ChildProcess;
273
- private socketPath: string;
274
- private _logPath: string;
275
- private _outboxPath: string;
276
- private _legacyOutboxPath: string; // Legacy /tmp/relay-outbox path for backwards compat
277
- private _canonicalOutboxPath: string; // Canonical ~/.agent-relay/outbox path (agents write here)
278
- private _workspaceId?: string; // For symlink setup
279
- private socket?: Socket;
280
- private socketConnected = false;
281
-
282
- // Output buffering
283
- private outputBuffer = '';
284
- private rawBuffer = '';
285
- private lastParsedLength = 0;
286
- private bufferTrimCount = 0;
287
-
288
- // Interactive mode (show output to terminal)
289
- private isInteractive = false;
290
-
291
- // Injection state
292
- private pendingInjections: Map<string, {
293
- resolve: (success: boolean) => void;
294
- reject: (error: Error) => void;
295
- timeout: NodeJS.Timeout;
296
- from: string; // For verification pattern matching
297
- shortId: string; // First 8 chars of messageId for verification
298
- retryCount: number; // Track retry attempts
299
- originalBody: string; // Original injection content for retries
300
- }> = new Map();
301
- private backpressureActive = false;
302
- private readyForMessages = false;
303
-
304
- // Adaptive throttle for message queue - adjusts delay based on success/failure
305
- private throttle = new AdaptiveThrottle();
306
-
307
- // Unread message indicator state
308
- private lastUnreadIndicatorTime = 0;
309
- private readonly UNREAD_INDICATOR_COOLDOWN_MS = 5000; // Don't spam indicators
310
-
311
- // Track whether any output has been received from the CLI
312
- private hasReceivedOutput = false;
313
-
314
- // Queue monitor for stuck message detection
315
- private queueMonitorTimer?: NodeJS.Timeout;
316
- private readonly QUEUE_MONITOR_INTERVAL_MS = 5000; // Check every 5 seconds
317
- private injectionStartTime = 0; // Track when isInjecting was set to true
318
- private readonly MAX_INJECTION_STUCK_MS = 60000; // Force reset after 60 seconds
319
-
320
- // Protocol monitor for detecting agent mistakes (e.g., empty AGENT_RELAY_NAME)
321
- private protocolWatcher?: FSWatcher;
322
- private protocolReminderCooldown = 0; // Prevent spam
323
- private readonly PROTOCOL_REMINDER_COOLDOWN_MS = 30000; // 30 second cooldown between reminders
324
-
325
- // Periodic protocol reminder for long sessions (agents sometimes forget the protocol)
326
- private periodicReminderTimer?: NodeJS.Timeout;
327
- private readonly PERIODIC_REMINDER_INTERVAL_MS = 45 * 60 * 1000; // 45 minutes
328
- private sessionStartTime = 0;
329
-
330
- // Track if agent is being gracefully stopped (vs crashed)
331
- private isGracefulStop = false;
332
-
333
- // Track early process exit for better error messages
334
- private earlyExitInfo?: { code: number | null; signal: NodeJS.Signals | null; stderr: string };
335
-
336
- // Memory/CPU monitoring
337
- private memoryMonitor: AgentMemoryMonitor;
338
- private memoryAlertHandler: ((alert: MemoryAlert) => void) | null = null;
339
-
340
- // CPU limiting via cgroups (optional, Linux only)
341
- private cgroupManager: CgroupManager;
342
- private hasCgroupSetup = false;
343
-
344
- // Note: sessionEndProcessed and lastSummaryRawContent are inherited from BaseWrapper
345
-
346
- /**
347
- * Gather system diagnostics for debugging SIGKILL/unexpected exits.
348
- * Returns a formatted string with memory, process, and system info.
349
- */
350
- private static gatherSigkillDiagnostics(agentName: string, pid?: number): string {
351
- const lines: string[] = [];
352
-
353
- try {
354
- // Memory info
355
- const free = freemem();
356
- const total = totalmem();
357
- const usedPercent = Math.round((1 - free / total) * 100);
358
- lines.push(`Memory: ${Math.round(free / 1024 / 1024)}MB free / ${Math.round(total / 1024 / 1024)}MB total (${usedPercent}% used)`);
359
-
360
- // Process count (try to get relay-pty count)
361
- try {
362
- const psOutput = execSync('ps aux | grep -c relay-pty || echo 0', { encoding: 'utf-8', timeout: 1000 }).trim();
363
- lines.push(`relay-pty processes: ${psOutput}`);
364
- } catch {
365
- // Ignore - ps may not be available
366
- }
367
-
368
- // Check for OOM killer messages (Linux only)
369
- try {
370
- const dmesgOutput = execSync('dmesg -T 2>/dev/null | grep -i "killed process" | tail -3 || true', {
371
- encoding: 'utf-8',
372
- timeout: 1000
373
- }).trim();
374
- if (dmesgOutput) {
375
- lines.push(`Recent OOM kills: ${dmesgOutput.replace(/\n/g, ' | ')}`);
376
- }
377
- } catch {
378
- // Ignore - dmesg may require permissions
379
- }
380
-
381
- // Include PID if known
382
- if (pid) {
383
- lines.push(`Killed process PID: ${pid}`);
384
- }
385
-
386
- lines.push(`Agent name: ${agentName}`);
387
- lines.push(`Timestamp: ${new Date().toISOString()}`);
388
- } catch (err) {
389
- lines.push(`Diagnostics error: ${err instanceof Error ? err.message : String(err)}`);
390
- }
391
-
392
- return lines.join('\n ');
393
- }
394
-
395
- constructor(config: RelayPtyOrchestratorConfig) {
396
- super(config);
397
- this.config = config;
398
-
399
- // Validate agent name to prevent path traversal attacks
400
- if (config.name.includes('..') || config.name.includes('/') || config.name.includes('\\')) {
401
- throw new Error(`Invalid agent name: "${config.name}" contains path traversal characters`);
402
- }
403
-
404
- // Get project paths (used for logs and local mode)
405
- const projectPaths = getProjectPaths(config.cwd);
406
-
407
- // Canonical outbox path - agents ALWAYS write here (transparent symlink in workspace mode)
408
- // Uses ~/.agent-relay/outbox/{agentName}/ so agents don't need to know about workspace IDs
409
- this._canonicalOutboxPath = join(projectPaths.dataDir, 'outbox', config.name);
410
-
411
- // Check for workspace namespacing (for multi-tenant cloud deployment)
412
- // WORKSPACE_ID can be in process.env or passed via config.env
413
- const workspaceId = config.env?.WORKSPACE_ID || process.env.WORKSPACE_ID;
414
- this._workspaceId = workspaceId;
415
-
416
- if (workspaceId) {
417
- // Workspace mode: relay-pty watches the actual workspace path
418
- // Canonical path (~/.agent-relay/outbox/) will be symlinked to workspace path
419
- const getWorkspacePaths = (id: string) => {
420
- const workspaceDir = `/tmp/relay/${id}`;
421
- return {
422
- workspaceDir,
423
- socketPath: `${workspaceDir}/sockets/${config.name}.sock`,
424
- outboxPath: `${workspaceDir}/outbox/${config.name}`,
425
- };
426
- };
427
-
428
- let paths = getWorkspacePaths(workspaceId);
429
- if (paths.socketPath.length > MAX_SOCKET_PATH_LENGTH) {
430
- const hashedWorkspaceId = hashWorkspaceId(workspaceId);
431
- const hashedPaths = getWorkspacePaths(hashedWorkspaceId);
432
- console.warn(
433
- `[relay-pty-orchestrator:${config.name}] Socket path too long (${paths.socketPath.length} chars); using hashed workspace id ${hashedWorkspaceId}`
434
- );
435
- paths = hashedPaths;
436
- }
437
-
438
- if (paths.socketPath.length > MAX_SOCKET_PATH_LENGTH) {
439
- throw new Error(`Socket path exceeds ${MAX_SOCKET_PATH_LENGTH} chars: ${paths.socketPath.length}`);
440
- }
441
-
442
- this.socketPath = paths.socketPath;
443
- // relay-pty watches the actual workspace path
444
- this._outboxPath = paths.outboxPath;
445
- // Legacy path for backwards compat (older agents might still use /tmp/relay-outbox)
446
- this._legacyOutboxPath = `/tmp/relay-outbox/${config.name}`;
447
- } else {
448
- // Local mode: use project paths directly (no symlinks needed)
449
- this._outboxPath = this._canonicalOutboxPath;
450
- // Socket path: use ~/.agent-relay/sockets/{projectId}/{agentName}.sock
451
- // This keeps paths short (uses 12-char hashed projectId) while staying organized
452
- // Example: /Users/foo/.agent-relay/sockets/abc123def456/MyAgent.sock (~65 chars)
453
- this.socketPath = join(homedir(), '.agent-relay', 'sockets', projectPaths.projectId, `${config.name}.sock`);
454
- // Legacy path for backwards compat (older agents might still use /tmp/relay-outbox)
455
- // Even in local mode, we need this symlink for agents with stale instructions
456
- this._legacyOutboxPath = `/tmp/relay-outbox/${config.name}`;
457
- }
458
- if (this.socketPath.length > MAX_SOCKET_PATH_LENGTH) {
459
- throw new Error(`Socket path exceeds ${MAX_SOCKET_PATH_LENGTH} chars: ${this.socketPath.length}`);
460
- }
461
-
462
- // Generate log path using project paths
463
- this._logPath = join(projectPaths.teamDir, 'worker-logs', `${config.name}.log`);
464
-
465
- // Check if we're running interactively (stdin is a TTY)
466
- // If headless mode is forced via config, always use pipes
467
- this.isInteractive = config.headless ? false : (process.stdin.isTTY === true);
468
-
469
- // Initialize memory monitor (shared singleton, 10s polling interval)
470
- this.memoryMonitor = getMemoryMonitor({ checkIntervalMs: 10_000 });
471
-
472
- // Initialize cgroup manager for CPU limiting (shared singleton)
473
- this.cgroupManager = getCgroupManager();
474
- }
475
-
476
- /**
477
- * Debug log - only outputs when debug is enabled
478
- * Writes to log file to avoid polluting TUI output
479
- */
480
- private log(message: string): void {
481
- if (this.config.debug) {
482
- const logLine = `${new Date().toISOString()} [relay-pty-orchestrator:${this.config.name}] ${message}\n`;
483
- try {
484
- const logDir = dirname(this._logPath);
485
- if (!existsSync(logDir)) {
486
- mkdirSync(logDir, { recursive: true });
487
- }
488
- appendFileSync(this._logPath, logLine);
489
- } catch {
490
- // Fallback to stderr if file write fails (only during init before _logPath is set)
491
- }
492
- }
493
- }
494
-
495
- /**
496
- * Error log - always outputs (errors are important)
497
- * Writes to log file to avoid polluting TUI output
498
- */
499
- private logError(message: string): void {
500
- const logLine = `${new Date().toISOString()} [relay-pty-orchestrator:${this.config.name}] ERROR: ${message}\n`;
501
- try {
502
- const logDir = dirname(this._logPath);
503
- if (!existsSync(logDir)) {
504
- mkdirSync(logDir, { recursive: true });
505
- }
506
- appendFileSync(this._logPath, logLine);
507
- } catch {
508
- // Fallback to stderr if file write fails (only during init before _logPath is set)
509
- }
510
- }
511
-
512
- /**
513
- * Get the outbox path for this agent (for documentation purposes)
514
- */
515
- get outboxPath(): string {
516
- return this._outboxPath;
517
- }
518
-
519
- // =========================================================================
520
- // Abstract method implementations (required by BaseWrapper)
521
- // =========================================================================
522
-
523
- /**
524
- * Start the relay-pty process and connect to socket
525
- */
526
- override async start(): Promise<void> {
527
- if (this.running) return;
528
-
529
- this.log(` Starting...`);
530
-
531
- // Ensure socket directory exists (for workspace-namespaced paths)
532
- const socketDir = dirname(this.socketPath);
533
- try {
534
- if (!existsSync(socketDir)) {
535
- mkdirSync(socketDir, { recursive: true });
536
- this.log(` Created socket directory: ${socketDir}`);
537
- }
538
- } catch (err: any) {
539
- this.logError(` Failed to create socket directory: ${err.message}`);
540
- }
541
-
542
- // Clean up any stale socket from previous crashed process
543
- try {
544
- if (existsSync(this.socketPath)) {
545
- this.log(` Removing stale socket: ${this.socketPath}`);
546
- unlinkSync(this.socketPath);
547
- }
548
- } catch (err: any) {
549
- this.logError(` Failed to clean up socket: ${err.message}`);
550
- }
551
-
552
- // Set up outbox directory structure
553
- // - Workspace mode:
554
- // 1. Create actual workspace path /tmp/relay/{workspaceId}/outbox/{name}
555
- // 2. Symlink canonical ~/.agent-relay/outbox/{name} -> workspace path
556
- // 3. Optional: symlink /tmp/relay-outbox/{name} -> workspace path (backwards compat)
557
- // - Local mode: just create ~/.agent-relay/{projectId}/outbox/{name} directly
558
- try {
559
- // Ensure the actual outbox directory exists (where relay-pty watches)
560
- const outboxDir = dirname(this._outboxPath);
561
- if (!existsSync(outboxDir)) {
562
- mkdirSync(outboxDir, { recursive: true });
563
- }
564
- if (!existsSync(this._outboxPath)) {
565
- mkdirSync(this._outboxPath, { recursive: true });
566
- }
567
- this.log(` Created outbox directory: ${this._outboxPath}`);
568
-
569
- // Helper to create a symlink, cleaning up existing path first
570
- const createSymlinkSafe = (linkPath: string, targetPath: string) => {
571
- const linkParent = dirname(linkPath);
572
- if (!existsSync(linkParent)) {
573
- mkdirSync(linkParent, { recursive: true });
574
- }
575
-
576
- // Remove existing path if it exists (file, symlink, or directory)
577
- // Use lstatSync instead of existsSync to detect broken symlinks
578
- // (existsSync returns false for broken symlinks, but the symlink itself still exists)
579
- let pathExists = false;
580
- try {
581
- lstatSync(linkPath);
582
- pathExists = true;
583
- } catch {
584
- // Path doesn't exist at all - proceed to create symlink
585
- }
586
-
587
- if (pathExists) {
588
- try {
589
- const stats = lstatSync(linkPath);
590
- if (stats.isSymbolicLink()) {
591
- // Handle both valid and broken symlinks
592
- try {
593
- const currentTarget = readlinkSync(linkPath);
594
- if (currentTarget === targetPath) {
595
- // Symlink already points to correct target, no need to recreate
596
- this.log(` Symlink already exists and is correct: ${linkPath} -> ${targetPath}`);
597
- return;
598
- }
599
- } catch {
600
- // Broken symlink (target doesn't exist) - remove it
601
- this.log(` Removing broken symlink: ${linkPath}`);
602
- }
603
- unlinkSync(linkPath);
604
- } else if (stats.isFile()) {
605
- unlinkSync(linkPath);
606
- } else if (stats.isDirectory()) {
607
- // Force remove directory - this is critical for fixing existing directories
608
- rmSync(linkPath, { recursive: true, force: true });
609
- // Verify removal succeeded using lstatSync to catch broken symlinks
610
- try {
611
- lstatSync(linkPath);
612
- throw new Error(`Failed to remove existing directory: ${linkPath}`);
613
- } catch (err: any) {
614
- if (err.code !== 'ENOENT') {
615
- throw err; // Re-throw if it's not a "doesn't exist" error
616
- }
617
- // Path successfully removed
618
- }
619
- }
620
- } catch (err: any) {
621
- // Log cleanup errors instead of silently ignoring them
622
- this.logError(` Failed to clean up existing path ${linkPath}: ${err.message}`);
623
- throw err; // Re-throw to prevent symlink creation on failed cleanup
624
- }
625
- }
626
-
627
- // Create the symlink
628
- try {
629
- symlinkSync(targetPath, linkPath);
630
- // Verify symlink was created correctly
631
- if (!existsSync(linkPath)) {
632
- throw new Error(`Symlink creation failed: ${linkPath}`);
633
- }
634
- const verifyStats = lstatSync(linkPath);
635
- if (!verifyStats.isSymbolicLink()) {
636
- throw new Error(`Created path is not a symlink: ${linkPath}`);
637
- }
638
- const verifyTarget = readlinkSync(linkPath);
639
- if (verifyTarget !== targetPath) {
640
- throw new Error(`Symlink points to wrong target: expected ${targetPath}, got ${verifyTarget}`);
641
- }
642
- this.log(` Created symlink: ${linkPath} -> ${targetPath}`);
643
- } catch (err: any) {
644
- this.logError(` Failed to create symlink ${linkPath} -> ${targetPath}: ${err.message}`);
645
- throw err;
646
- }
647
- };
648
-
649
- // In workspace mode, create symlinks so agents can use canonical path
650
- if (this._workspaceId) {
651
- // Symlink canonical path (~/.agent-relay/outbox/{name}) -> workspace path
652
- // This is the PRIMARY symlink - agents write to canonical path, relay-pty watches workspace path
653
- if (this._canonicalOutboxPath !== this._outboxPath) {
654
- createSymlinkSafe(this._canonicalOutboxPath, this._outboxPath);
655
- }
656
-
657
- // Also create legacy /tmp/relay-outbox symlink for backwards compat with older agents
658
- if (this._legacyOutboxPath !== this._outboxPath && this._legacyOutboxPath !== this._canonicalOutboxPath) {
659
- createSymlinkSafe(this._legacyOutboxPath, this._outboxPath);
660
- }
661
- }
662
-
663
- // In local mode, also create legacy symlink for backwards compat with stale instructions
664
- if (!this._workspaceId && this._legacyOutboxPath !== this._outboxPath) {
665
- createSymlinkSafe(this._legacyOutboxPath, this._outboxPath);
666
- }
667
- } catch (err: any) {
668
- this.logError(` Failed to set up outbox: ${err.message}`);
669
- }
670
-
671
- // Write MCP identity file so MCP servers can discover their agent name
672
- // This is needed because Claude Code may not pass through env vars to MCP server processes
673
- try {
674
- const projectPaths = getProjectPaths(this.config.cwd);
675
- const identityDir = join(projectPaths.dataDir);
676
- if (!existsSync(identityDir)) {
677
- mkdirSync(identityDir, { recursive: true });
678
- }
679
- // Write a per-process identity file (using PPID so MCP server finds parent's identity)
680
- const identityPath = join(identityDir, `mcp-identity-${process.pid}`);
681
- writeFileSync(identityPath, this.config.name, 'utf-8');
682
- this.log(` Wrote MCP identity file: ${identityPath}`);
683
-
684
- // Also write a simple identity file (for single-agent scenarios)
685
- const simpleIdentityPath = join(identityDir, 'mcp-identity');
686
- writeFileSync(simpleIdentityPath, this.config.name, 'utf-8');
687
- } catch (err: any) {
688
- this.logError(` Failed to write MCP identity file: ${err.message}`);
689
- }
690
-
691
- // Find relay-pty binary
692
- const binaryPath = this.findRelayPtyBinary();
693
- if (!binaryPath) {
694
- throw new Error('relay-pty binary not found. Build with: cd relay-pty && cargo build --release');
695
- }
696
-
697
- try {
698
- accessSync(binaryPath, fsConstants.X_OK);
699
- } catch (err: any) {
700
- throw new Error(`relay-pty binary not executable at ${binaryPath}: ${err?.message ?? 'permission denied'}. Build with: cd relay-pty && cargo build --release, or ensure the binary has execute permissions.`);
701
- }
702
-
703
- this.log(` Using binary: ${binaryPath}`);
704
-
705
- // Spawn relay-pty process FIRST (before connecting to daemon)
706
- // This ensures the CLI is actually running before we register with the daemon
707
- await this.spawnRelayPty(binaryPath);
708
-
709
- // Wait for socket to become available and connect
710
- await this.connectToSocket();
711
-
712
- // Connect to relay daemon AFTER CLI is spawned
713
- // This prevents the spawner from seeing us as "registered" before the CLI runs
714
- try {
715
- await this.client.connect();
716
- this.log(` Relay daemon connected`);
717
- } catch (err: any) {
718
- this.logError(` Relay connect failed: ${err.message}`);
719
- }
720
-
721
- this.running = true;
722
- // DON'T set readyForMessages yet - wait for CLI to be ready first
723
- // This prevents messages from being injected during CLI startup
724
- this.startStuckDetection();
725
- this.startQueueMonitor();
726
- this.startProtocolMonitor();
727
- this.startPeriodicReminder();
728
-
729
- this.log(` Socket connected: ${this.socketConnected}`);
730
- this.log(` Relay client state: ${this.client.state}`);
731
-
732
- // Wait for CLI to be fully ready (output received + idle state)
733
- // This ensures we don't inject messages while the CLI is still starting up
734
- // Messages arriving via daemon during this time will be queued but not processed
735
- this.log(` Waiting for CLI to be ready before accepting messages...`);
736
- const cliReady = await this.waitUntilCliReady(30000, 100);
737
- if (cliReady) {
738
- this.log(` CLI is ready, enabling message processing`);
739
- } else {
740
- this.log(` CLI readiness timeout, enabling message processing anyway`);
741
- }
742
-
743
- // Now enable message processing
744
- this.readyForMessages = true;
745
- this.log(` Ready for messages`);
746
-
747
- // Process any queued messages that arrived during startup
748
- this.processMessageQueue();
749
- }
750
-
751
- /**
752
- * Stop the relay-pty process gracefully
753
- */
754
- override async stop(): Promise<void> {
755
- if (!this.running) return;
756
- this.isGracefulStop = true; // Mark as graceful to prevent crash broadcast
757
- this.running = false;
758
- this.stopStuckDetection();
759
- this.stopQueueMonitor();
760
- this.stopProtocolMonitor();
761
- this.stopPeriodicReminder();
762
-
763
- // Clear socket reconnect timer
764
- if (this.socketReconnectTimer) {
765
- clearTimeout(this.socketReconnectTimer);
766
- this.socketReconnectTimer = undefined;
767
- }
768
-
769
- // Unregister from memory monitor
770
- this.memoryMonitor.unregister(this.config.name);
771
- if (this.memoryAlertHandler) {
772
- this.memoryMonitor.off('alert', this.memoryAlertHandler);
773
- this.memoryAlertHandler = null;
774
- }
775
-
776
- // Clean up cgroup if we set one up
777
- if (this.hasCgroupSetup) {
778
- await this.cgroupManager.removeAgentCgroup(this.config.name);
779
- this.hasCgroupSetup = false;
780
- }
781
-
782
- // Auto-save continuity state before shutdown
783
- // Pass sessionEndData to populate handoff (fixes empty handoff issue)
784
- if (this.continuity) {
785
- try {
786
- await this.continuity.autoSave(this.config.name, 'session_end', this.sessionEndData);
787
- this.log(` Continuity auto-saved`);
788
- } catch (err: any) {
789
- this.logError(`Continuity auto-save failed: ${err.message}`);
790
- }
791
- }
792
-
793
- this.log(` Stopping...`);
794
-
795
- // Send shutdown command via socket
796
- if (this.socket && this.socketConnected) {
797
- try {
798
- await this.sendSocketRequest({ type: 'shutdown' });
799
- } catch {
800
- // Ignore errors during shutdown
801
- }
802
- }
803
-
804
- // Close socket
805
- this.disconnectSocket();
806
-
807
- // Kill process if still running
808
- if (this.relayPtyProcess && !this.relayPtyProcess.killed) {
809
- this.relayPtyProcess.kill('SIGTERM');
810
-
811
- // Force kill after timeout
812
- await Promise.race([
813
- new Promise<void>((resolve) => {
814
- this.relayPtyProcess?.on('exit', () => resolve());
815
- }),
816
- sleep(5000).then(() => {
817
- if (this.relayPtyProcess && !this.relayPtyProcess.killed) {
818
- this.relayPtyProcess.kill('SIGKILL');
819
- }
820
- }),
821
- ]);
822
- }
823
-
824
- // Cleanup relay client
825
- this.destroyClient();
826
-
827
- // Clean up socket file
828
- try {
829
- if (existsSync(this.socketPath)) {
830
- unlinkSync(this.socketPath);
831
- this.log(` Cleaned up socket: ${this.socketPath}`);
832
- }
833
- } catch (err: any) {
834
- this.logError(` Failed to clean up socket: ${err.message}`);
835
- }
836
-
837
- // Clean up mcp-identity file for this process
838
- try {
839
- const projectPaths = getProjectPaths(this.config.cwd);
840
- const identityPath = join(projectPaths.dataDir, `mcp-identity-${process.pid}`);
841
- if (existsSync(identityPath)) {
842
- unlinkSync(identityPath);
843
- this.log(` Cleaned up identity file: ${identityPath}`);
844
- }
845
- } catch (err: any) {
846
- this.logError(` Failed to clean up identity file: ${err.message}`);
847
- }
848
-
849
- this.log(` Stopped`);
850
- }
851
-
852
- /**
853
- * Inject content into the agent via socket
854
- */
855
- protected async performInjection(_content: string): Promise<void> {
856
- // This is called by BaseWrapper but we handle injection differently
857
- // via the socket protocol in processMessageQueue
858
- throw new Error('Use injectMessage() instead of performInjection()');
859
- }
860
-
861
- /**
862
- * Get cleaned output for parsing
863
- */
864
- protected getCleanOutput(): string {
865
- return stripAnsi(this.rawBuffer);
866
- }
867
-
868
- // =========================================================================
869
- // Process management
870
- // =========================================================================
871
-
872
- /**
873
- * Find the relay-pty binary
874
- * Uses shared utility from @agent-relay/utils
875
- */
876
- private findRelayPtyBinary(): string | null {
877
- // Check config path first
878
- if (this.config.relayPtyPath && existsSync(this.config.relayPtyPath)) {
879
- return this.config.relayPtyPath;
880
- }
881
-
882
- // Use shared utility with current module's __dirname
883
- return findRelayPtyBinaryUtil(__dirname);
884
- }
885
-
886
- /**
887
- * Spawn the relay-pty process
888
- */
889
- private async spawnRelayPty(binaryPath: string): Promise<void> {
890
- // Get terminal dimensions for proper rendering
891
- const rows = process.stdout.rows || 24;
892
- const cols = process.stdout.columns || 80;
893
-
894
- const args = [
895
- '--name', this.config.name,
896
- '--socket', this.socketPath,
897
- '--idle-timeout', String(this.config.idleBeforeInjectMs ?? 500),
898
- '--json-output', // Enable Rust parsing output
899
- '--rows', String(rows),
900
- '--cols', String(cols),
901
- '--log-level', 'warn', // Only show warnings and errors
902
- '--log-file', this._logPath, // Enable output logging
903
- '--outbox', this._outboxPath, // Enable file-based relay messages
904
- '--', this.config.command,
905
- ...(this.config.args ?? []),
906
- ];
907
-
908
- this.log(` Spawning: ${binaryPath} ${args.join(' ')}`);
909
-
910
- // Reset early exit info from any previous spawn attempt
911
- this.earlyExitInfo = undefined;
912
-
913
- // For interactive mode, let Rust directly inherit stdin/stdout from the terminal
914
- // This is more robust than manual forwarding through pipes
915
- // We still pipe stderr to capture JSON parsed commands
916
- const stdio: ('inherit' | 'pipe')[] = this.isInteractive
917
- ? ['inherit', 'inherit', 'pipe'] // Rust handles terminal directly
918
- : ['pipe', 'pipe', 'pipe']; // Headless mode - we handle I/O
919
-
920
- const proc = spawn(binaryPath, args, {
921
- cwd: this.config.cwd ?? process.cwd(),
922
- env: {
923
- ...process.env,
924
- ...this.config.env,
925
- AGENT_RELAY_NAME: this.config.name,
926
- RELAY_AGENT_NAME: this.config.name, // MCP server uses this env var
927
- AGENT_RELAY_OUTBOX: this._canonicalOutboxPath, // Agents use this for outbox path
928
- TERM: 'xterm-256color',
929
- },
930
- stdio,
931
- });
932
- this.relayPtyProcess = proc;
933
-
934
- // Handle stdout (agent output) - only in headless mode
935
- if (!this.isInteractive && proc.stdout) {
936
- proc.stdout.on('data', (data: Buffer) => {
937
- const text = data.toString();
938
- this.handleOutput(text);
939
- });
940
- }
941
-
942
- // Capture stderr for early exit diagnosis
943
- let stderrBuffer = '';
944
-
945
- // Handle stderr (relay-pty logs and JSON output) - always needed
946
- // Also captures to buffer for error diagnostics if process dies early
947
- if (proc.stderr) {
948
- proc.stderr.on('data', (data: Buffer) => {
949
- const text = data.toString();
950
- stderrBuffer += text;
951
- this.handleStderr(text);
952
- });
953
- }
954
-
955
- // Handle exit
956
- proc.on('exit', (code, signal) => {
957
- const exitCode = code ?? (signal === 'SIGKILL' ? 137 : 1);
958
- this.log(` Process exited: code=${exitCode} signal=${signal}`);
959
-
960
- // Capture early exit info for better error messages if socket not yet connected
961
- if (!this.socketConnected) {
962
- this.earlyExitInfo = { code, signal, stderr: stderrBuffer };
963
- }
964
-
965
- // Enhanced logging for SIGKILL/137 exits (likely OOM or resource limits)
966
- if (signal === 'SIGKILL' || exitCode === 137) {
967
- const diagnostics = RelayPtyOrchestrator.gatherSigkillDiagnostics(this.config.name, proc.pid);
968
- this.logError(` SIGKILL DETECTED - gathering diagnostics:\n ${diagnostics}`);
969
- console.error(`[relay-pty-orchestrator] SIGKILL for ${this.config.name}:\n ${diagnostics}`);
970
- }
971
-
972
- this.running = false;
973
-
974
- // Get crash context before unregistering from memory monitor
975
- const crashContext = this.memoryMonitor.getCrashContext(this.config.name);
976
-
977
- // Unregister from memory monitor
978
- this.memoryMonitor.unregister(this.config.name);
979
- if (this.memoryAlertHandler) {
980
- this.memoryMonitor.off('alert', this.memoryAlertHandler);
981
- this.memoryAlertHandler = null;
982
- }
983
-
984
- // Clean up cgroup (fire and forget - process already exited)
985
- if (this.hasCgroupSetup) {
986
- this.cgroupManager.removeAgentCgroup(this.config.name).catch(() => {});
987
- this.hasCgroupSetup = false;
988
- }
989
-
990
- // Broadcast crash notification if not a graceful stop
991
- if (!this.isGracefulStop && this.client.state === 'READY') {
992
- const canBroadcast = typeof (this.client as any).broadcast === 'function';
993
- const isNormalExit = exitCode === 0;
994
- const wasKilled = signal === 'SIGKILL' || signal === 'SIGTERM' || exitCode === 137;
995
-
996
- if (!isNormalExit) {
997
- const reason = wasKilled
998
- ? `killed by signal ${signal || 'SIGKILL'}`
999
- : `exit code ${exitCode}`;
1000
-
1001
- // Include crash context analysis if available
1002
- const contextInfo = crashContext.likelyCause !== 'unknown'
1003
- ? ` Likely cause: ${crashContext.likelyCause}. ${crashContext.analysisNotes.slice(0, 2).join('. ')}`
1004
- : '';
1005
-
1006
- const message = `AGENT CRASHED: "${this.config.name}" has died unexpectedly (${reason}).${contextInfo}`;
1007
-
1008
- this.log(` Broadcasting crash notification: ${message}`);
1009
- if (canBroadcast) {
1010
- this.client.broadcast(message, 'message', {
1011
- isSystemMessage: true,
1012
- agentName: this.config.name,
1013
- exitCode,
1014
- signal: signal || undefined,
1015
- crashType: 'unexpected_exit',
1016
- crashContext: {
1017
- likelyCause: crashContext.likelyCause,
1018
- peakMemory: crashContext.peakMemory,
1019
- averageMemory: crashContext.averageMemory,
1020
- memoryTrend: crashContext.memoryTrend,
1021
- },
1022
- });
1023
- } else {
1024
- this.log(' broadcast skipped: client.broadcast not available');
1025
- }
1026
- }
1027
- }
1028
-
1029
- this.emit('exit', exitCode);
1030
- this.config.onExit?.(exitCode);
1031
- });
1032
-
1033
- // Handle error
1034
- proc.on('error', (err) => {
1035
- this.logError(` Process error: ${err.message}`);
1036
- this.emit('error', err);
1037
- });
1038
-
1039
- // Wait for process to start
1040
- await sleep(500);
1041
-
1042
- if (proc.exitCode !== null) {
1043
- // Include any captured stderr in the error for debugging
1044
- const stderrInfo = stderrBuffer ? `\nStderr: ${stderrBuffer.slice(0, 500)}` : '';
1045
- throw new Error(`relay-pty exited immediately with code ${proc.exitCode}${stderrInfo}`);
1046
- }
1047
-
1048
- // Register for memory/CPU monitoring
1049
- if (proc.pid) {
1050
- this.memoryMonitor.register(this.config.name, proc.pid);
1051
- this.memoryMonitor.start(); // Idempotent - starts if not already running
1052
-
1053
- // Set up CPU limiting via cgroups (if configured and available)
1054
- // This prevents one agent from starving others during npm install/build
1055
- if (this.config.cpuLimitPercent && this.config.cpuLimitPercent > 0) {
1056
- this.setupCgroupLimit(proc.pid, this.config.cpuLimitPercent).catch((err) => {
1057
- this.log(` Failed to set up cgroup CPU limit: ${err.message}`);
1058
- });
1059
- }
1060
-
1061
- // Set up alert handler to send resource alerts to dashboard only (not other agents)
1062
- this.memoryAlertHandler = (alert: MemoryAlert) => {
1063
- if (alert.agentName !== this.config.name) return;
1064
- if (this.client.state !== 'READY') return;
1065
-
1066
- const message = alert.type === 'recovered'
1067
- ? `AGENT RECOVERED: "${this.config.name}" memory usage returned to normal.`
1068
- : `AGENT RESOURCE ALERT: "${this.config.name}" - ${alert.message} (${formatBytes(alert.currentRss)})`;
1069
-
1070
- this.log(` Sending resource alert to users: ${message}`);
1071
- // Send to all human users - agents don't need to know about each other's resource usage
1072
- this.client.sendMessage('@users', message, 'message', {
1073
- isSystemMessage: true,
1074
- agentName: this.config.name,
1075
- alertType: alert.type,
1076
- currentMemory: alert.currentRss,
1077
- threshold: alert.threshold,
1078
- recommendation: alert.recommendation,
1079
- });
1080
- };
1081
- this.memoryMonitor.on('alert', this.memoryAlertHandler);
1082
- }
1083
- }
1084
-
1085
- /**
1086
- * Set up cgroup CPU limit for this agent
1087
- */
1088
- private async setupCgroupLimit(pid: number, cpuPercent: number): Promise<void> {
1089
- await this.cgroupManager.initialize();
1090
-
1091
- if (!this.cgroupManager.isAvailable()) {
1092
- this.log(` cgroups not available, skipping CPU limit`);
1093
- return;
1094
- }
1095
-
1096
- const created = await this.cgroupManager.createAgentCgroup(this.config.name, { cpuPercent });
1097
- if (!created) {
1098
- return;
1099
- }
1100
-
1101
- const added = await this.cgroupManager.addProcess(this.config.name, pid);
1102
- if (added) {
1103
- this.hasCgroupSetup = true;
1104
- this.log(` CPU limit set to ${cpuPercent}% for agent ${this.config.name}`);
1105
- }
1106
- }
1107
-
1108
- /**
1109
- * Handle output from relay-pty stdout (headless mode only)
1110
- * In interactive mode, stdout goes directly to terminal via inherited stdio
1111
- */
1112
- private handleOutput(data: string): void {
1113
- // Skip processing if agent is no longer running (prevents ghost messages after release)
1114
- if (!this.running) {
1115
- return;
1116
- }
1117
-
1118
- this.rawBuffer += data;
1119
- this.outputBuffer += data;
1120
- this.hasReceivedOutput = true;
1121
-
1122
- // Trim buffers if they exceed max size to prevent RangeError: Invalid string length
1123
- // Keep the most recent output (tail) as it's more relevant for pattern matching
1124
- let buffersTrimmed = false;
1125
- if (this.rawBuffer.length > MAX_OUTPUT_BUFFER_SIZE) {
1126
- const trimAmount = this.rawBuffer.length - MAX_OUTPUT_BUFFER_SIZE;
1127
- this.rawBuffer = this.rawBuffer.slice(-MAX_OUTPUT_BUFFER_SIZE);
1128
- // Adjust lastParsedLength to stay in sync with the trimmed buffer
1129
- // This ensures parseRelayCommands() doesn't skip content or re-parse old content
1130
- this.lastParsedLength = Math.max(0, this.lastParsedLength - trimAmount);
1131
- buffersTrimmed = true;
1132
- }
1133
- if (this.outputBuffer.length > MAX_OUTPUT_BUFFER_SIZE) {
1134
- this.outputBuffer = this.outputBuffer.slice(-MAX_OUTPUT_BUFFER_SIZE);
1135
- buffersTrimmed = true;
1136
- }
1137
- if (buffersTrimmed) {
1138
- this.bufferTrimCount += 1;
1139
- }
1140
-
1141
- // Feed to idle detector
1142
- this.feedIdleDetectorOutput(data);
1143
-
1144
- // Check for unread messages and append indicator if needed
1145
- const indicator = this.formatUnreadIndicator();
1146
- const outputWithIndicator = indicator ? data + indicator : data;
1147
-
1148
- // Emit output event (with indicator if present)
1149
- this.emit('output', outputWithIndicator);
1150
-
1151
- // Stream to daemon if configured
1152
- if (this.config.streamLogs !== false && this.client.state === 'READY') {
1153
- this.client.sendLog(outputWithIndicator);
1154
- }
1155
-
1156
- // Parse for relay commands
1157
- this.parseRelayCommands();
1158
-
1159
- // Check for summary and session end
1160
- const cleanContent = stripAnsi(this.rawBuffer);
1161
- this.checkForSummary(cleanContent);
1162
- this.checkForSessionEnd(cleanContent);
1163
- }
1164
-
1165
- /**
1166
- * Format an unread message indicator if there are pending messages.
1167
- * Returns empty string if no pending messages or within cooldown period.
1168
- *
1169
- * Example output:
1170
- * ───────────────────────────
1171
- * 📬 2 unread messages (from: Alice, Bob)
1172
- */
1173
- private formatUnreadIndicator(): string {
1174
- const queueLength = this.messageQueue.length;
1175
- if (queueLength === 0) {
1176
- return '';
1177
- }
1178
-
1179
- // Check cooldown to avoid spamming
1180
- const now = Date.now();
1181
- if (now - this.lastUnreadIndicatorTime < this.UNREAD_INDICATOR_COOLDOWN_MS) {
1182
- return '';
1183
- }
1184
- this.lastUnreadIndicatorTime = now;
1185
-
1186
- // Collect unique sender names
1187
- const senders = [...new Set(this.messageQueue.map(m => m.from))];
1188
- const senderList = senders.slice(0, 3).join(', ');
1189
- const moreCount = senders.length > 3 ? ` +${senders.length - 3} more` : '';
1190
-
1191
- const line = '─'.repeat(27);
1192
- const messageWord = queueLength === 1 ? 'message' : 'messages';
1193
-
1194
- return `\n${line}\n📬 ${queueLength} unread ${messageWord} (from: ${senderList}${moreCount})\n`;
1195
- }
1196
-
1197
- /**
1198
- * Handle stderr from relay-pty (logs and JSON parsed commands)
1199
- */
1200
- private handleStderr(data: string): void {
1201
- // Skip processing if agent is no longer running (prevents ghost messages after release)
1202
- if (!this.running) {
1203
- return;
1204
- }
1205
-
1206
- // relay-pty outputs JSON parsed commands to stderr with --json-output
1207
- const lines = data.split('\n').filter(l => l.trim());
1208
- for (const line of lines) {
1209
- if (line.startsWith('{')) {
1210
- // JSON output - parsed relay command from Rust
1211
- try {
1212
- const parsed = JSON.parse(line);
1213
- if (parsed.type === 'relay_command' && parsed.kind) {
1214
- // Log parsed commands (only in debug mode to avoid TUI pollution)
1215
- if (parsed.kind === 'spawn' || parsed.kind === 'release') {
1216
- this.log(`Rust parsed [${parsed.kind}]: ${JSON.stringify({
1217
- spawn_name: parsed.spawn_name,
1218
- spawn_cli: parsed.spawn_cli,
1219
- spawn_task: parsed.spawn_task?.substring(0, 50),
1220
- release_name: parsed.release_name,
1221
- })}`);
1222
- } else {
1223
- this.log(`Rust parsed [${parsed.kind}]: ${parsed.from} -> ${parsed.to}`);
1224
- }
1225
- this.handleRustParsedCommand(parsed);
1226
- } else if (parsed.type === 'continuity') {
1227
- // Handle continuity commands from relay-pty file-based protocol
1228
- this.log(`Rust parsed [continuity]: action=${parsed.action}`);
1229
- this.handleRustContinuityCommand(parsed);
1230
- }
1231
- } catch (e) {
1232
- // Not JSON, just log (only in debug mode)
1233
- if (this.config.debug) {
1234
- console.error(`[relay-pty:${this.config.name}] ${line}`);
1235
- }
1236
- }
1237
- } else {
1238
- // Non-JSON stderr - only show in debug mode (logs, info messages)
1239
- if (this.config.debug) {
1240
- console.error(`[relay-pty:${this.config.name}] ${line}`);
1241
- }
1242
- }
1243
- }
1244
- }
1245
-
1246
- /**
1247
- * Handle a parsed command from Rust relay-pty
1248
- * Rust outputs structured JSON with 'kind' field: "message", "spawn", "release"
1249
- */
1250
- private handleRustParsedCommand(parsed: {
1251
- type: string;
1252
- kind: string;
1253
- from: string;
1254
- to: string;
1255
- body: string;
1256
- raw: string;
1257
- thread?: string;
1258
- spawn_name?: string;
1259
- spawn_cli?: string;
1260
- spawn_task?: string;
1261
- spawn_cwd?: string;
1262
- release_name?: string;
1263
- }): void {
1264
- switch (parsed.kind) {
1265
- case 'spawn':
1266
- if (parsed.spawn_name && parsed.spawn_cli) {
1267
- this.log(` Spawn detected: ${parsed.spawn_name} (${parsed.spawn_cli})${parsed.spawn_cwd ? ` in ${parsed.spawn_cwd}` : ''}`);
1268
- this.handleSpawnCommand(parsed.spawn_name, parsed.spawn_cli, parsed.spawn_task || '', parsed.spawn_cwd);
1269
- }
1270
- break;
1271
-
1272
- case 'release':
1273
- if (parsed.release_name) {
1274
- this.log(`Release: ${parsed.release_name}`);
1275
- this.handleReleaseCommand(parsed.release_name);
1276
- } else {
1277
- this.logError(`Missing release_name in parsed command: ${JSON.stringify(parsed)}`);
1278
- }
1279
- break;
1280
-
1281
- case 'message':
1282
- default:
1283
- this.sendRelayCommand({
1284
- to: parsed.to,
1285
- kind: 'message',
1286
- body: parsed.body,
1287
- thread: parsed.thread,
1288
- raw: parsed.raw,
1289
- });
1290
- break;
1291
- }
1292
- }
1293
-
1294
- /**
1295
- * Handle continuity command from Rust relay-pty
1296
- *
1297
- * Maps from Rust ContinuityCommand format to TypeScript ContinuityCommand
1298
- * and forwards to the ContinuityManager.
1299
- *
1300
- * Rust format: { type: "continuity", action: string, content: string }
1301
- * TypeScript format: { type: 'save' | 'load' | 'uncertain', content?: string, item?: string }
1302
- */
1303
- private async handleRustContinuityCommand(parsed: {
1304
- type: string;
1305
- action: string;
1306
- content: string;
1307
- }): Promise<void> {
1308
- if (!this.continuity) {
1309
- this.log('Continuity not initialized, skipping continuity command');
1310
- return;
1311
- }
1312
-
1313
- // Map Rust action to TypeScript ContinuityCommand type
1314
- const action = parsed.action.toLowerCase();
1315
- if (!['save', 'load', 'uncertain'].includes(action)) {
1316
- this.logError(`Unknown continuity action: ${parsed.action}`);
1317
- return;
1318
- }
1319
-
1320
- // Build TypeScript ContinuityCommand
1321
- const command: { type: 'save' | 'load' | 'uncertain'; content?: string; item?: string } = {
1322
- type: action as 'save' | 'load' | 'uncertain',
1323
- };
1324
-
1325
- if (action === 'save' && parsed.content) {
1326
- command.content = parsed.content;
1327
- } else if (action === 'uncertain' && parsed.content) {
1328
- command.item = parsed.content;
1329
- }
1330
-
1331
- // Deduplication (same logic as base-wrapper)
1332
- const cmdHash = `${command.type}:${command.content || command.item || 'no-content'}`;
1333
- if (command.content && this.processedContinuityCommands.has(cmdHash)) {
1334
- this.log(`Continuity command already processed: ${cmdHash}`);
1335
- return;
1336
- }
1337
- this.processedContinuityCommands.add(cmdHash);
1338
-
1339
- // Limit dedup set size
1340
- if (this.processedContinuityCommands.size > 100) {
1341
- const oldest = this.processedContinuityCommands.values().next().value;
1342
- if (oldest) this.processedContinuityCommands.delete(oldest);
1343
- }
1344
-
1345
- try {
1346
- this.log(`Processing continuity command: ${command.type}`);
1347
- const response = await this.continuity.handleCommand(this.config.name, command);
1348
- if (response) {
1349
- // Queue response for injection (e.g., for 'load' command)
1350
- this.messageQueue.push({
1351
- from: 'system',
1352
- body: response,
1353
- messageId: `continuity-${Date.now()}`,
1354
- thread: 'continuity-response',
1355
- });
1356
- this.log(`Queued continuity response for injection`);
1357
- } else {
1358
- this.log(`Continuity command ${command.type} completed (no response)`);
1359
- }
1360
- } catch (err: any) {
1361
- this.logError(`Continuity command failed: ${err.message}`);
1362
- }
1363
- }
1364
-
1365
- /**
1366
- * Handle spawn command (from Rust stderr JSON parsing)
1367
- *
1368
- * Note: We do NOT send the initial task message here because the spawner
1369
- * now handles it after waitUntilCliReady(). Sending it here would cause
1370
- * duplicate task delivery.
1371
- */
1372
- private handleSpawnCommand(name: string, cli: string, task: string, cwd?: string): void {
1373
- const key = `spawn:${name}:${cli}`;
1374
- if (this.processedSpawnCommands.has(key)) {
1375
- this.log(`Spawn already processed: ${key}`);
1376
- return;
1377
- }
1378
- this.processedSpawnCommands.add(key);
1379
-
1380
- // Log spawn attempts (only in debug mode to avoid TUI pollution)
1381
- this.log(`SPAWN REQUEST: ${name} (${cli})${cwd ? ` cwd=${cwd}` : ''}`);
1382
- this.log(` client=${this.client.state}, dashboardPort=${this.config.dashboardPort}, onSpawn=${!!this.config.onSpawn}`);
1383
-
1384
- // Try daemon socket first (most reliable - daemon has relay-pty binary),
1385
- // then dashboard API, then onSpawn callback as final fallback.
1386
- this.executeSpawnWithFallbacks(name, cli, task, cwd).catch(err => {
1387
- this.logError(`SPAWN FAILED: ${name} - all methods exhausted: ${err.message}`);
1388
- });
1389
- }
1390
-
1391
- /**
1392
- * Execute spawn with daemon-first fallback chain.
1393
- * Order: daemon socket → dashboard API → onSpawn callback
1394
- */
1395
- private async executeSpawnWithFallbacks(name: string, cli: string, task: string, cwd?: string): Promise<void> {
1396
- // 1. Try daemon socket spawn first (daemon always has access to relay-pty)
1397
- if (this.client.state === 'READY') {
1398
- try {
1399
- this.log(`Spawning ${name} via daemon socket`);
1400
- const result = await this.client.spawn({ name, cli, task, cwd });
1401
- if (result.success) {
1402
- this.log(`SPAWN SUCCESS: ${name} via daemon socket`);
1403
- // Also register cwd with dashboard API so agentCwdMap is populated
1404
- // (daemon socket spawn bypasses /api/spawn which normally sets this)
1405
- if (cwd && this.config.dashboardPort) {
1406
- this.registerCwdWithDashboard(name, cwd).catch(err => {
1407
- this.log(`Failed to register cwd with dashboard: ${err.message}`);
1408
- });
1409
- }
1410
- } else {
1411
- // Daemon explicitly rejected - respect its decision (policy, duplicate, etc.)
1412
- this.logError(`Daemon spawn rejected: ${result.error}`);
1413
- }
1414
- // Always return if daemon responded - only fall through on transport errors
1415
- return;
1416
- } catch (err: any) {
1417
- this.logError(`Daemon spawn transport error: ${err.message}`);
1418
- }
1419
- }
1420
-
1421
- // 2. Fall back to dashboard API
1422
- if (this.config.dashboardPort) {
1423
- try {
1424
- this.log(`Spawning ${name} via dashboard API at port ${this.config.dashboardPort}`);
1425
- await this.spawnViaDashboardApi(name, cli, task, cwd);
1426
- this.log(`SPAWN SUCCESS: ${name} via dashboard API`);
1427
- return;
1428
- } catch (err: any) {
1429
- this.logError(`Dashboard spawn failed: ${err.message}`);
1430
- }
1431
- }
1432
-
1433
- // 3. Final fallback: onSpawn callback
1434
- if (this.config.onSpawn) {
1435
- this.log(`Spawning ${name} via onSpawn callback`);
1436
- await this.config.onSpawn(name, cli, task, cwd);
1437
- return;
1438
- }
1439
-
1440
- throw new Error(`No spawn mechanism available (client=${this.client.state}, dashboardPort=${this.config.dashboardPort}, onSpawn=${!!this.config.onSpawn})`);
1441
- }
1442
-
1443
- /**
1444
- * Handle release command
1445
- */
1446
- private handleReleaseCommand(name: string): void {
1447
- const key = `release:${name}`;
1448
- if (this.processedReleaseCommands.has(key)) {
1449
- return;
1450
- }
1451
- this.processedReleaseCommands.add(key);
1452
-
1453
- this.log(` Release: ${name}`);
1454
-
1455
- // Try daemon socket first, then dashboard API, then callback
1456
- this.executeReleaseWithFallbacks(name).catch(err => {
1457
- this.logError(`RELEASE FAILED: ${name} - all methods exhausted: ${err.message}`);
1458
- });
1459
- }
1460
-
1461
- /**
1462
- * Execute release with daemon-first fallback chain.
1463
- * Order: daemon socket → dashboard API → onRelease callback
1464
- */
1465
- private async executeReleaseWithFallbacks(name: string): Promise<void> {
1466
- // 1. Try daemon socket release first
1467
- if (this.client.state === 'READY') {
1468
- try {
1469
- const result = await this.client.release(name);
1470
- if (result.success) {
1471
- return;
1472
- }
1473
- // Daemon explicitly rejected - respect its decision
1474
- this.logError(`Daemon release rejected: ${result.error}`);
1475
- // Always return if daemon responded - only fall through on transport errors
1476
- return;
1477
- } catch (err: any) {
1478
- this.logError(`Daemon release transport error: ${err.message}`);
1479
- }
1480
- }
1481
-
1482
- // 2. Fall back to dashboard API
1483
- if (this.config.dashboardPort) {
1484
- try {
1485
- await this.releaseViaDashboardApi(name);
1486
- return;
1487
- } catch (err: any) {
1488
- this.logError(`Dashboard release failed: ${err.message}`);
1489
- }
1490
- }
1491
-
1492
- // 3. Final fallback: onRelease callback
1493
- if (this.config.onRelease) {
1494
- await this.config.onRelease(name);
1495
- return;
1496
- }
1497
-
1498
- throw new Error(`No release mechanism available (client=${this.client.state}, dashboardPort=${this.config.dashboardPort}, onRelease=${!!this.config.onRelease})`);
1499
- }
1500
-
1501
- /**
1502
- * Register an agent's cwd with the dashboard API.
1503
- * Used after daemon socket spawns which bypass /api/spawn and its agentCwdMap.
1504
- */
1505
- private async registerCwdWithDashboard(name: string, cwd: string): Promise<void> {
1506
- const url = `http://localhost:${this.config.dashboardPort}/api/agents/${encodeURIComponent(name)}/cwd`;
1507
- const response = await fetch(url, {
1508
- method: 'PUT',
1509
- headers: { 'Content-Type': 'application/json' },
1510
- body: JSON.stringify({ cwd }),
1511
- });
1512
- if (!response.ok) {
1513
- throw new Error(`HTTP ${response.status}`);
1514
- }
1515
- }
1516
-
1517
- /**
1518
- * Spawn agent via dashboard API
1519
- */
1520
- private async spawnViaDashboardApi(name: string, cli: string, task: string, cwd?: string): Promise<void> {
1521
- const url = `http://localhost:${this.config.dashboardPort}/api/spawn`;
1522
- const body: Record<string, string | undefined> = {
1523
- name,
1524
- cli,
1525
- task,
1526
- spawnerName: this.config.name, // Include spawner name so task appears from correct agent
1527
- cwd,
1528
- };
1529
-
1530
- try {
1531
- const response = await fetch(url, {
1532
- method: 'POST',
1533
- headers: { 'Content-Type': 'application/json' },
1534
- body: JSON.stringify(body),
1535
- });
1536
-
1537
- if (!response.ok) {
1538
- const errorBody = await response.text().catch(() => 'unknown');
1539
- throw new Error(`HTTP ${response.status}: ${errorBody}`);
1540
- }
1541
-
1542
- const result = await response.json().catch(() => ({})) as { success?: boolean; error?: string };
1543
- if (result.success === false) {
1544
- throw new Error(result.error || 'Spawn failed without specific error');
1545
- }
1546
- } catch (err: any) {
1547
- // Enhance error with context
1548
- if (err.code === 'ECONNREFUSED') {
1549
- throw new Error(`Dashboard not reachable at ${url} (connection refused)`);
1550
- }
1551
- throw err;
1552
- }
1553
- }
1554
-
1555
- /**
1556
- * Release agent via dashboard API
1557
- */
1558
- private async releaseViaDashboardApi(name: string): Promise<void> {
1559
- const response = await fetch(`http://localhost:${this.config.dashboardPort}/api/spawned/${encodeURIComponent(name)}`, {
1560
- method: 'DELETE',
1561
- });
1562
- if (!response.ok) {
1563
- const body = await response.json().catch(() => ({ error: 'Unknown' })) as { error?: string };
1564
- throw new Error(`HTTP ${response.status}: ${body.error || 'Unknown error'}`);
1565
- }
1566
- this.log(`Released ${name} via dashboard API`);
1567
- }
1568
-
1569
- // =========================================================================
1570
- // Socket communication
1571
- // =========================================================================
1572
-
1573
- /**
1574
- * Check if the relay-pty process is still alive
1575
- */
1576
- private isProcessAlive(): boolean {
1577
- if (!this.relayPtyProcess || this.relayPtyProcess.exitCode !== null) {
1578
- return false;
1579
- }
1580
- try {
1581
- // Signal 0 checks if process exists without killing it
1582
- process.kill(this.relayPtyProcess.pid!, 0);
1583
- return true;
1584
- } catch {
1585
- return false;
1586
- }
1587
- }
1588
-
1589
- /**
1590
- * Connect to the relay-pty socket
1591
- */
1592
- private async connectToSocket(): Promise<void> {
1593
- const timeout = this.config.socketConnectTimeoutMs ?? 5000;
1594
- const maxAttempts = this.config.socketReconnectAttempts ?? 3;
1595
-
1596
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1597
- // Check if relay-pty process died before attempting connection
1598
- if (!this.isProcessAlive()) {
1599
- const exitInfo = this.earlyExitInfo;
1600
- if (exitInfo) {
1601
- const exitReason = exitInfo.signal
1602
- ? `signal ${exitInfo.signal}`
1603
- : `code ${exitInfo.code ?? 'unknown'}`;
1604
- const stderrHint = exitInfo.stderr
1605
- ? `\n stderr: ${exitInfo.stderr.trim().slice(0, 500)}`
1606
- : '';
1607
-
1608
- // Add enhanced diagnostics for SIGKILL (likely OOM or resource limit)
1609
- const diagnostics = exitInfo.signal === 'SIGKILL' || exitInfo.code === 137
1610
- ? `\n Diagnostics (SIGKILL often indicates OOM or resource limits):\n ${RelayPtyOrchestrator.gatherSigkillDiagnostics(this.config.name, this.relayPtyProcess?.pid)}`
1611
- : '';
1612
-
1613
- throw new Error(`relay-pty process died early (${exitReason}).${stderrHint}${diagnostics}`);
1614
- }
1615
- throw new Error('relay-pty process died before socket could be created');
1616
- }
1617
-
1618
- try {
1619
- await this.attemptSocketConnection(timeout);
1620
- this.log(` Socket connected`);
1621
- return;
1622
- } catch (err: any) {
1623
- this.logError(` Socket connect attempt ${attempt}/${maxAttempts} failed: ${err.message}`);
1624
- if (attempt < maxAttempts) {
1625
- await sleep(1000 * attempt); // Exponential backoff
1626
- }
1627
- }
1628
- }
1629
-
1630
- // Final check for process death after all attempts
1631
- if (!this.isProcessAlive() && this.earlyExitInfo) {
1632
- const exitInfo = this.earlyExitInfo;
1633
- const exitReason = exitInfo.signal
1634
- ? `signal ${exitInfo.signal}`
1635
- : `code ${exitInfo.code ?? 'unknown'}`;
1636
- const stderrHint = exitInfo.stderr
1637
- ? `\n stderr: ${exitInfo.stderr.trim().slice(0, 500)}`
1638
- : '';
1639
-
1640
- // Add enhanced diagnostics for SIGKILL
1641
- const diagnostics = exitInfo.signal === 'SIGKILL' || exitInfo.code === 137
1642
- ? `\n Diagnostics (SIGKILL often indicates OOM or resource limits):\n ${RelayPtyOrchestrator.gatherSigkillDiagnostics(this.config.name, this.relayPtyProcess?.pid)}`
1643
- : '';
1644
-
1645
- throw new Error(`relay-pty process died during socket connection (${exitReason}).${stderrHint}${diagnostics}`);
1646
- }
1647
-
1648
- throw new Error(`Failed to connect to socket after ${maxAttempts} attempts`);
1649
- }
1650
-
1651
- /**
1652
- * Attempt a single socket connection
1653
- */
1654
- private attemptSocketConnection(timeout: number): Promise<void> {
1655
- return new Promise((resolve, reject) => {
1656
- // Clean up any existing socket before creating new one
1657
- // This prevents orphaned sockets with stale event handlers
1658
- if (this.socket) {
1659
- // Remove all listeners to prevent the old socket's 'close' event
1660
- // from triggering another reconnect cycle
1661
- this.socket.removeAllListeners();
1662
- this.socket.destroy();
1663
- this.socket = undefined;
1664
- }
1665
-
1666
- const timer = setTimeout(() => {
1667
- reject(new Error('Socket connection timeout'));
1668
- }, timeout);
1669
-
1670
- this.socket = createConnection(this.socketPath, () => {
1671
- clearTimeout(timer);
1672
- this.socketConnected = true;
1673
- resolve();
1674
- });
1675
-
1676
- this.socket.on('error', (err) => {
1677
- clearTimeout(timer);
1678
- this.socketConnected = false;
1679
- reject(err);
1680
- });
1681
-
1682
- // Handle 'end' event - server closed its write side (half-close)
1683
- this.socket.on('end', () => {
1684
- this.socketConnected = false;
1685
- this.log(` Socket received end (server closed write side)`);
1686
- });
1687
-
1688
- this.socket.on('close', () => {
1689
- this.socketConnected = false;
1690
- this.log(` Socket closed`);
1691
- // Auto-reconnect if not intentionally stopped
1692
- if (this.running && !this.isGracefulStop) {
1693
- this.scheduleSocketReconnect();
1694
- }
1695
- });
1696
-
1697
- // Handle incoming data (responses)
1698
- let buffer = '';
1699
- this.socket.on('data', (data: Buffer) => {
1700
- buffer += data.toString();
1701
-
1702
- // Process complete lines
1703
- const lines = buffer.split('\n');
1704
- buffer = lines.pop() ?? ''; // Keep incomplete line in buffer
1705
-
1706
- for (const line of lines) {
1707
- if (line.trim()) {
1708
- this.handleSocketResponse(line);
1709
- }
1710
- }
1711
- });
1712
- });
1713
- }
1714
-
1715
- /**
1716
- * Disconnect from socket
1717
- */
1718
- private disconnectSocket(): void {
1719
- if (this.socket) {
1720
- this.socket.destroy();
1721
- this.socket = undefined;
1722
- this.socketConnected = false;
1723
- }
1724
-
1725
- // Reject all pending injections
1726
- for (const [_id, pending] of this.pendingInjections) {
1727
- clearTimeout(pending.timeout);
1728
- pending.reject(new Error('Socket disconnected'));
1729
- }
1730
- this.pendingInjections.clear();
1731
- }
1732
-
1733
- /** Timer for socket reconnection */
1734
- private socketReconnectTimer?: NodeJS.Timeout;
1735
- /** Current reconnection attempt count */
1736
- private socketReconnectAttempt = 0;
1737
-
1738
- /**
1739
- * Schedule a socket reconnection attempt with exponential backoff
1740
- */
1741
- private scheduleSocketReconnect(): void {
1742
- const maxAttempts = this.config.socketReconnectAttempts ?? 3;
1743
-
1744
- // Clear any existing timer
1745
- if (this.socketReconnectTimer) {
1746
- clearTimeout(this.socketReconnectTimer);
1747
- this.socketReconnectTimer = undefined;
1748
- }
1749
-
1750
- if (this.socketReconnectAttempt >= maxAttempts) {
1751
- this.logError(` Socket reconnect failed after ${maxAttempts} attempts`);
1752
- // Reset counter for future reconnects (processMessageQueue can trigger new cycle)
1753
- this.socketReconnectAttempt = 0;
1754
- // Note: socketReconnectTimer is already undefined, allowing processMessageQueue
1755
- // to trigger a new reconnection cycle when new messages arrive
1756
- return;
1757
- }
1758
-
1759
- this.socketReconnectAttempt++;
1760
- const delay = Math.min(1000 * Math.pow(2, this.socketReconnectAttempt - 1), 10000); // Max 10s
1761
-
1762
- this.log(` Scheduling socket reconnect in ${delay}ms (attempt ${this.socketReconnectAttempt}/${maxAttempts})`);
1763
-
1764
- this.socketReconnectTimer = setTimeout(async () => {
1765
- // Clear timer reference now that callback is executing
1766
- this.socketReconnectTimer = undefined;
1767
-
1768
- if (!this.running || this.isGracefulStop) {
1769
- return;
1770
- }
1771
-
1772
- try {
1773
- const timeout = this.config.socketConnectTimeoutMs ?? 5000;
1774
- await this.attemptSocketConnection(timeout);
1775
- this.log(` Socket reconnected successfully`);
1776
- this.socketReconnectAttempt = 0; // Reset on success
1777
-
1778
- // Process any queued messages that were waiting
1779
- if (this.messageQueue.length > 0 && !this.isInjecting) {
1780
- this.log(` Processing ${this.messageQueue.length} queued messages after reconnect`);
1781
- this.processMessageQueue();
1782
- }
1783
- } catch (err: any) {
1784
- this.logError(` Socket reconnect attempt ${this.socketReconnectAttempt} failed: ${err.message}`);
1785
- // Schedule another attempt
1786
- this.scheduleSocketReconnect();
1787
- }
1788
- }, delay);
1789
- }
1790
-
1791
- /**
1792
- * Send a request to the socket and optionally wait for response
1793
- */
1794
- private sendSocketRequest(request: RelayPtyRequest): Promise<void> {
1795
- return new Promise((resolve, reject) => {
1796
- if (!this.socket || !this.socketConnected) {
1797
- reject(new Error('Socket not connected'));
1798
- return;
1799
- }
1800
-
1801
- const json = JSON.stringify(request) + '\n';
1802
- this.socket.write(json, (err) => {
1803
- if (err) {
1804
- reject(err);
1805
- } else {
1806
- resolve();
1807
- }
1808
- });
1809
- });
1810
- }
1811
-
1812
- /**
1813
- * Handle a response from the socket
1814
- */
1815
- private handleSocketResponse(line: string): void {
1816
- try {
1817
- const response = JSON.parse(line) as RelayPtyResponse;
1818
-
1819
- switch (response.type) {
1820
- case 'inject_result':
1821
- // handleInjectResult is async (does verification), but we don't await here
1822
- // Errors are handled internally by the method
1823
- this.handleInjectResult(response).catch((err: Error) => {
1824
- this.logError(` Error handling inject result: ${err.message}`);
1825
- });
1826
- break;
1827
-
1828
- case 'status':
1829
- // Status responses are typically requested explicitly
1830
- this.log(` Status: idle=${response.agent_idle} queue=${response.queue_length}`);
1831
- break;
1832
-
1833
- case 'backpressure':
1834
- this.handleBackpressure(response);
1835
- break;
1836
-
1837
- case 'error':
1838
- this.logError(` Socket error: ${response.message}`);
1839
- break;
1840
-
1841
- case 'shutdown_ack':
1842
- this.log(` Shutdown acknowledged`);
1843
- break;
1844
-
1845
- case 'send_enter_result':
1846
- // SendEnter is no longer used - trust Rust delivery confirmation
1847
- this.log(` Received send_enter_result (deprecated)`);
1848
- break;
1849
- }
1850
- } catch (err: any) {
1851
- this.logError(` Failed to parse socket response: ${err.message}`);
1852
- }
1853
- }
1854
-
1855
- /**
1856
- * Handle injection result response
1857
- * After Rust reports 'delivered', verifies the message appeared in output.
1858
- * If verification fails, retries up to MAX_RETRIES times.
1859
- */
1860
- private async handleInjectResult(response: InjectResultResponse): Promise<void> {
1861
- this.log(` handleInjectResult: id=${response.id.substring(0, 8)} status=${response.status}`);
1862
-
1863
- const pending = this.pendingInjections.get(response.id);
1864
- if (!pending) {
1865
- // Response for unknown message - might be from a previous session
1866
- this.log(` No pending injection found for ${response.id.substring(0, 8)}`);
1867
- return;
1868
- }
1869
-
1870
- if (response.status === 'delivered') {
1871
- // Rust says it sent the message + Enter key
1872
- // Trust Rust's delivery confirmation - relay-pty writes directly to PTY which is very reliable.
1873
- //
1874
- // IMPORTANT: We don't verify by looking for the message in output because:
1875
- // 1. TUI CLIs (Claude, Codex, Gemini) don't echo input like traditional terminals
1876
- // 2. The injected text appears as INPUT to the PTY, not OUTPUT
1877
- // 3. Output-based verification always fails for TUIs, causing unnecessary retries
1878
- //
1879
- // This is different from tmux-wrapper where we inject via tmux send-keys
1880
- // and can observe the echoed input in the pane output.
1881
- this.log(` Message ${pending.shortId} delivered by Rust ✓`);
1882
-
1883
- clearTimeout(pending.timeout);
1884
- this.pendingInjections.delete(response.id);
1885
- if (pending.retryCount === 0) {
1886
- this.injectionMetrics.successFirstTry++;
1887
- } else {
1888
- this.injectionMetrics.successWithRetry++;
1889
- }
1890
- this.injectionMetrics.total++;
1891
- pending.resolve(true);
1892
- } else if (response.status === 'failed') {
1893
- clearTimeout(pending.timeout);
1894
- this.pendingInjections.delete(response.id);
1895
- this.injectionMetrics.failed++;
1896
- this.injectionMetrics.total++;
1897
- pending.resolve(false);
1898
- this.logError(` Message ${pending.shortId} failed: ${response.error}`);
1899
- this.emit('injection-failed', {
1900
- messageId: response.id,
1901
- from: pending.from,
1902
- error: response.error ?? 'Unknown error',
1903
- });
1904
- }
1905
- // queued/injecting are intermediate states - wait for final status
1906
- }
1907
-
1908
- /**
1909
- * Handle backpressure notification
1910
- */
1911
- private handleBackpressure(response: BackpressureResponse): void {
1912
- const wasActive = this.backpressureActive;
1913
- this.backpressureActive = !response.accept;
1914
-
1915
- if (this.backpressureActive !== wasActive) {
1916
- this.log(` Backpressure: ${this.backpressureActive ? 'ACTIVE' : 'cleared'} (queue=${response.queue_length})`);
1917
- this.emit('backpressure', { queueLength: response.queue_length, accept: response.accept });
1918
-
1919
- // Resume processing if backpressure cleared
1920
- if (!this.backpressureActive) {
1921
- this.processMessageQueue();
1922
- }
1923
- }
1924
- }
1925
-
1926
- // =========================================================================
1927
- // Message handling
1928
- // =========================================================================
1929
-
1930
- /**
1931
- * Inject a message into the agent via socket
1932
- */
1933
- private async injectMessage(msg: QueuedMessage, retryCount = 0): Promise<boolean> {
1934
- const shortId = msg.messageId.substring(0, 8);
1935
- this.log(` === INJECT START: ${shortId} from ${msg.from} (attempt ${retryCount + 1}) ===`);
1936
-
1937
- if (!this.socket || !this.socketConnected) {
1938
- this.logError(` Cannot inject - socket not connected`);
1939
- return false;
1940
- }
1941
-
1942
- // Build injection content
1943
- const content = buildInjectionString(msg);
1944
- this.log(` Injection content (${content.length} bytes): ${content.substring(0, 100)}...`);
1945
-
1946
- // Create request
1947
- const request: InjectRequest = {
1948
- type: 'inject',
1949
- id: msg.messageId,
1950
- from: msg.from,
1951
- body: content,
1952
- priority: msg.importance ?? 0,
1953
- };
1954
-
1955
- this.log(` Sending inject request to socket...`);
1956
-
1957
- // Create promise for result
1958
- return new Promise<boolean>((resolve, reject) => {
1959
- const timeout = setTimeout(() => {
1960
- this.logError(` Inject timeout for ${shortId} after 30s`);
1961
- this.pendingInjections.delete(msg.messageId);
1962
- resolve(false); // Timeout = failure
1963
- }, 30000); // 30 second timeout for injection
1964
-
1965
- this.pendingInjections.set(msg.messageId, {
1966
- resolve,
1967
- reject,
1968
- timeout,
1969
- from: msg.from,
1970
- shortId,
1971
- retryCount,
1972
- originalBody: content,
1973
- });
1974
-
1975
- // Send request
1976
- this.sendSocketRequest(request)
1977
- .then(() => {
1978
- this.log(` Socket request sent for ${shortId}`);
1979
- })
1980
- .catch((err) => {
1981
- this.logError(` Socket request failed for ${shortId}: ${err.message}`);
1982
- clearTimeout(timeout);
1983
- this.pendingInjections.delete(msg.messageId);
1984
- resolve(false);
1985
- });
1986
- });
1987
- }
1988
-
1989
- /**
1990
- * Process queued messages
1991
- */
1992
- private async processMessageQueue(): Promise<void> {
1993
- // Debug: Log blocking conditions when queue has messages
1994
- if (this.messageQueue.length > 0) {
1995
- if (!this.readyForMessages) {
1996
- this.log(` Queue blocked: readyForMessages=false (queue=${this.messageQueue.length})`);
1997
- return;
1998
- }
1999
- if (this.backpressureActive) {
2000
- this.log(` Queue blocked: backpressure active (queue=${this.messageQueue.length})`);
2001
- return;
2002
- }
2003
- if (this.isInjecting) {
2004
- // Already injecting - the finally block will process next message
2005
- // But add a safety timeout in case injection gets stuck
2006
- const elapsed = this.injectionStartTime > 0 ? Date.now() - this.injectionStartTime : 0;
2007
- if (elapsed > 35000) {
2008
- this.logError(` Injection stuck for ${elapsed}ms, forcing reset`);
2009
- this.isInjecting = false;
2010
- this.injectionStartTime = 0;
2011
- }
2012
- return;
2013
- }
2014
- }
2015
-
2016
- if (this.messageQueue.length === 0) {
2017
- return;
2018
- }
2019
-
2020
- // Proactively reconnect socket if disconnected and we have messages to send
2021
- if (!this.socketConnected && !this.socketReconnectTimer) {
2022
- this.log(` Socket disconnected, triggering reconnect before processing queue`);
2023
- this.scheduleSocketReconnect();
2024
- return; // Wait for reconnection to complete
2025
- }
2026
-
2027
- if (!this.socketConnected) {
2028
- // Reconnection in progress, wait for it
2029
- this.log(` Queue waiting: socket reconnecting (queue=${this.messageQueue.length})`);
2030
- return;
2031
- }
2032
-
2033
- // Check if agent is in editor mode - delay injection if so
2034
- const idleResult = this.idleDetector.checkIdle();
2035
- if (idleResult.inEditorMode) {
2036
- this.log(` Agent in editor mode, delaying injection (queue: ${this.messageQueue.length})`);
2037
- // Check again in 2 seconds
2038
- setTimeout(() => this.processMessageQueue(), 2000);
2039
- return;
2040
- }
2041
-
2042
- this.isInjecting = true;
2043
- this.injectionStartTime = Date.now();
2044
-
2045
- const msg = this.messageQueue.shift()!;
2046
- const bodyPreview = msg.body.substring(0, 50).replace(/\n/g, '\\n');
2047
- this.log(` Processing message from ${msg.from}: "${bodyPreview}..." (remaining=${this.messageQueue.length})`);
2048
-
2049
- try {
2050
- const success = await this.injectMessage(msg);
2051
-
2052
- // Metrics are now tracked in handleInjectResult which knows about retries
2053
- if (!success) {
2054
- // Record failure for adaptive throttling
2055
- this.throttle.recordFailure();
2056
- this.logError(` Injection failed for message ${msg.messageId.substring(0, 8)}`);
2057
- this.config.onInjectionFailed?.(msg.messageId, 'Injection failed');
2058
- this.sendSyncAck(msg.messageId, msg.sync, 'ERROR', { error: 'injection_failed' });
2059
- } else {
2060
- // Record success for adaptive throttling
2061
- this.throttle.recordSuccess();
2062
- this.sendSyncAck(msg.messageId, msg.sync, 'OK');
2063
- }
2064
- } catch (err: any) {
2065
- this.logError(` Injection error: ${err.message}`);
2066
- // Track metrics for exceptions (not handled by handleInjectResult)
2067
- this.injectionMetrics.failed++;
2068
- this.injectionMetrics.total++;
2069
- // Record failure for adaptive throttling
2070
- this.throttle.recordFailure();
2071
- this.sendSyncAck(msg.messageId, msg.sync, 'ERROR', { error: err.message });
2072
- } finally {
2073
- this.isInjecting = false;
2074
- this.injectionStartTime = 0;
2075
-
2076
- // Process next message after adaptive delay (faster when healthy, slower under stress)
2077
- if (this.messageQueue.length > 0 && !this.backpressureActive) {
2078
- const delay = this.throttle.getDelay();
2079
- setTimeout(() => this.processMessageQueue(), delay);
2080
- }
2081
- }
2082
- }
2083
-
2084
- /**
2085
- * Override handleIncomingMessage to trigger queue processing
2086
- */
2087
- protected override handleIncomingMessage(
2088
- from: string,
2089
- payload: SendPayload,
2090
- messageId: string,
2091
- meta?: SendMeta,
2092
- originalTo?: string
2093
- ): void {
2094
- this.log(` === MESSAGE RECEIVED: ${messageId.substring(0, 8)} from ${from} ===`);
2095
- this.log(` Body preview: ${payload.body?.substring(0, 100) ?? '(no body)'}...`);
2096
- super.handleIncomingMessage(from, payload, messageId, meta, originalTo);
2097
- this.log(` Queue length after add: ${this.messageQueue.length}`);
2098
- this.processMessageQueue();
2099
- }
2100
-
2101
- /**
2102
- * Override handleIncomingChannelMessage to trigger queue processing.
2103
- * Without this override, channel messages would be queued but processMessageQueue()
2104
- * would never be called, causing messages to get stuck until the queue monitor runs.
2105
- */
2106
- protected override handleIncomingChannelMessage(
2107
- from: string,
2108
- channel: string,
2109
- body: string,
2110
- envelope: Envelope<ChannelMessagePayload>
2111
- ): void {
2112
- this.log(` === CHANNEL MESSAGE RECEIVED: ${envelope.id.substring(0, 8)} from ${from} on ${channel} ===`);
2113
- this.log(` Body preview: ${body?.substring(0, 100) ?? '(no body)'}...`);
2114
- super.handleIncomingChannelMessage(from, channel, body, envelope);
2115
- this.log(` Queue length after add: ${this.messageQueue.length}`);
2116
- this.processMessageQueue();
2117
- }
2118
-
2119
- // =========================================================================
2120
- // Queue monitor - Detect and process stuck messages
2121
- // =========================================================================
2122
-
2123
- /**
2124
- * Start the queue monitor to periodically check for stuck messages.
2125
- * This ensures messages don't get orphaned in the queue when the agent is idle.
2126
- */
2127
- private startQueueMonitor(): void {
2128
- if (this.queueMonitorTimer) {
2129
- return; // Already started
2130
- }
2131
-
2132
- this.log(` Starting queue monitor (interval: ${this.QUEUE_MONITOR_INTERVAL_MS}ms)`);
2133
-
2134
- this.queueMonitorTimer = setInterval(() => {
2135
- this.checkForStuckQueue();
2136
- }, this.QUEUE_MONITOR_INTERVAL_MS);
2137
-
2138
- // Don't keep process alive just for queue monitoring
2139
- this.queueMonitorTimer.unref?.();
2140
- }
2141
-
2142
- /**
2143
- * Stop the queue monitor.
2144
- */
2145
- private stopQueueMonitor(): void {
2146
- if (this.queueMonitorTimer) {
2147
- clearInterval(this.queueMonitorTimer);
2148
- this.queueMonitorTimer = undefined;
2149
- this.log(` Queue monitor stopped`);
2150
- }
2151
- }
2152
-
2153
- // =========================================================================
2154
- // Protocol monitoring (detect agent mistakes like empty AGENT_RELAY_NAME)
2155
- // =========================================================================
2156
-
2157
- /**
2158
- * Start watching for protocol issues in the outbox directory.
2159
- * Detects common mistakes like:
2160
- * - Empty AGENT_RELAY_NAME causing files at outbox//
2161
- * - Files created directly in outbox/ instead of agent subdirectory
2162
- */
2163
- private startProtocolMonitor(): void {
2164
- // Get the outbox parent directory (one level up from agent's outbox)
2165
- const parentDir = dirname(this._canonicalOutboxPath);
2166
-
2167
- // Ensure parent directory exists
2168
- try {
2169
- if (!existsSync(parentDir)) {
2170
- mkdirSync(parentDir, { recursive: true });
2171
- }
2172
- } catch {
2173
- // Ignore - directory may already exist
2174
- }
2175
-
2176
- try {
2177
- this.protocolWatcher = watch(parentDir, (eventType, filename) => {
2178
- if (eventType === 'rename' && filename) {
2179
- // Check for files directly in parent (not in agent subdirectory)
2180
- // This happens when $AGENT_RELAY_NAME is empty
2181
- const fullPath = join(parentDir, filename);
2182
- try {
2183
- // If it's a file (not directory) directly in the parent, that's an issue
2184
- if (existsSync(fullPath) && !lstatSync(fullPath).isDirectory()) {
2185
- this.handleProtocolIssue('file_in_root', filename);
2186
- }
2187
- // Check for empty-named directory (double slash symptom)
2188
- if (filename === '' || filename.startsWith('/')) {
2189
- this.handleProtocolIssue('empty_agent_name', filename);
2190
- }
2191
- } catch {
2192
- // Ignore stat errors
2193
- }
2194
- }
2195
- });
2196
-
2197
- // Don't keep process alive just for protocol monitoring
2198
- this.protocolWatcher.unref?.();
2199
- this.log(` Protocol monitor started on ${parentDir}`);
2200
- } catch (err: any) {
2201
- // Don't fail start() if protocol monitoring fails
2202
- this.logError(` Failed to start protocol monitor: ${err.message}`);
2203
- }
2204
-
2205
- // Also do an initial scan for existing issues
2206
- this.scanForProtocolIssues();
2207
- }
2208
-
2209
- /**
2210
- * Stop the protocol monitor.
2211
- */
2212
- private stopProtocolMonitor(): void {
2213
- if (this.protocolWatcher) {
2214
- this.protocolWatcher.close();
2215
- this.protocolWatcher = undefined;
2216
- this.log(` Protocol monitor stopped`);
2217
- }
2218
- }
2219
-
2220
- /**
2221
- * Scan for existing protocol issues (called once at startup).
2222
- */
2223
- private scanForProtocolIssues(): void {
2224
- const parentDir = dirname(this._canonicalOutboxPath);
2225
- try {
2226
- if (!existsSync(parentDir)) return;
2227
-
2228
- const entries = readdirSync(parentDir);
2229
- for (const entry of entries) {
2230
- const fullPath = join(parentDir, entry);
2231
- try {
2232
- // Check for files directly in parent (should only be directories)
2233
- if (!lstatSync(fullPath).isDirectory()) {
2234
- this.handleProtocolIssue('file_in_root', entry);
2235
- break; // Only report once
2236
- }
2237
- } catch {
2238
- // Ignore stat errors
2239
- }
2240
- }
2241
- } catch {
2242
- // Ignore scan errors
2243
- }
2244
- }
2245
-
2246
- /**
2247
- * Handle a detected protocol issue by injecting a helpful reminder.
2248
- */
2249
- private handleProtocolIssue(issue: 'empty_agent_name' | 'file_in_root', filename: string): void {
2250
- const now = Date.now();
2251
-
2252
- // Respect cooldown to avoid spamming
2253
- if (now - this.protocolReminderCooldown < this.PROTOCOL_REMINDER_COOLDOWN_MS) {
2254
- return;
2255
- }
2256
- this.protocolReminderCooldown = now;
2257
-
2258
- this.log(` Protocol issue detected: ${issue} (${filename})`);
2259
-
2260
- const reminders: Record<string, string> = {
2261
- empty_agent_name: `⚠️ **Protocol Issue Detected**
2262
-
2263
- Your \`$AGENT_RELAY_NAME\` environment variable appears to be empty or unset.
2264
- Your agent name is: **${this.config.name}**
2265
-
2266
- Correct outbox path: \`$AGENT_RELAY_OUTBOX\`
2267
-
2268
- When writing relay files, use:
2269
- \`\`\`bash
2270
- cat > $AGENT_RELAY_OUTBOX/msg << 'EOF'
2271
- TO: TargetAgent
2272
-
2273
- Your message here
2274
- EOF
2275
- \`\`\`
2276
- Then output: \`->relay-file:msg\``,
2277
-
2278
- file_in_root: `⚠️ **Protocol Issue Detected**
2279
-
2280
- Found file "${filename}" directly in the outbox root instead of using the proper path.
2281
- Your agent name is: **${this.config.name}**
2282
-
2283
- The \`$AGENT_RELAY_OUTBOX\` path already points to your agent's directory.
2284
- Write files directly inside it:
2285
-
2286
- \`\`\`bash
2287
- cat > $AGENT_RELAY_OUTBOX/msg << 'EOF'
2288
- TO: TargetAgent
2289
-
2290
- Your message here
2291
- EOF
2292
- \`\`\`
2293
- Then output: \`->relay-file:msg\``,
2294
- };
2295
-
2296
- const reminder = reminders[issue];
2297
- if (reminder) {
2298
- this.injectProtocolReminder(reminder);
2299
- }
2300
- }
2301
-
2302
- /**
2303
- * Inject a protocol reminder message to the agent.
2304
- */
2305
- private injectProtocolReminder(message: string): void {
2306
- const queuedMsg: QueuedMessage = {
2307
- from: 'system',
2308
- body: message,
2309
- messageId: `protocol-reminder-${Date.now()}`,
2310
- importance: 2, // Higher priority
2311
- };
2312
-
2313
- this.messageQueue.unshift(queuedMsg); // Add to front of queue
2314
- this.log(` Queued protocol reminder (queue size: ${this.messageQueue.length})`);
2315
-
2316
- // Trigger processing if not already in progress
2317
- if (!this.isInjecting && this.readyForMessages) {
2318
- this.processMessageQueue();
2319
- }
2320
- }
2321
-
2322
- // =========================================================================
2323
- // Periodic protocol reminders (for long sessions where agents forget protocol)
2324
- // =========================================================================
2325
-
2326
- /**
2327
- * Start sending periodic protocol reminders.
2328
- * Agents in long sessions sometimes forget the relay protocol - these
2329
- * reminders help them stay on track without user intervention.
2330
- */
2331
- private startPeriodicReminder(): void {
2332
- this.sessionStartTime = Date.now();
2333
-
2334
- this.periodicReminderTimer = setInterval(() => {
2335
- this.sendPeriodicProtocolReminder();
2336
- }, this.PERIODIC_REMINDER_INTERVAL_MS);
2337
-
2338
- // Don't keep process alive just for reminders
2339
- this.periodicReminderTimer.unref?.();
2340
-
2341
- const intervalMinutes = Math.round(this.PERIODIC_REMINDER_INTERVAL_MS / 60000);
2342
- this.log(` Periodic protocol reminder started (interval: ${intervalMinutes} minutes)`);
2343
- }
2344
-
2345
- /**
2346
- * Stop periodic protocol reminders.
2347
- */
2348
- private stopPeriodicReminder(): void {
2349
- if (this.periodicReminderTimer) {
2350
- clearInterval(this.periodicReminderTimer);
2351
- this.periodicReminderTimer = undefined;
2352
- this.log(` Periodic protocol reminder stopped`);
2353
- }
2354
- }
2355
-
2356
- /**
2357
- * Send a periodic protocol reminder to the agent.
2358
- * This reminds agents about proper relay communication format after long sessions.
2359
- */
2360
- private sendPeriodicProtocolReminder(): void {
2361
- // Don't send if not ready
2362
- if (!this.running || !this.readyForMessages) {
2363
- return;
2364
- }
2365
-
2366
- const sessionDurationMinutes = Math.round((Date.now() - this.sessionStartTime) / 60000);
2367
-
2368
- const reminder = `📋 **Protocol Reminder** (Session: ${sessionDurationMinutes} minutes)
2369
-
2370
- You are **${this.config.name}** in a multi-agent relay system. Here's how to communicate:
2371
-
2372
- **Sending Messages:**
2373
- \`\`\`bash
2374
- cat > $AGENT_RELAY_OUTBOX/msg << 'EOF'
2375
- TO: *
2376
-
2377
- Your message here
2378
- EOF
2379
- \`\`\`
2380
- Then output: \`->relay-file:msg\`
2381
-
2382
- Use \`TO: *\` to broadcast to all agents, or \`TO: AgentName\` for a specific agent.
2383
-
2384
- **Spawning Agents:**
2385
- \`\`\`bash
2386
- cat > $AGENT_RELAY_OUTBOX/spawn << 'EOF'
2387
- KIND: spawn
2388
- NAME: WorkerName
2389
- CLI: claude
2390
-
2391
- Task description here
2392
- EOF
2393
- \`\`\`
2394
- Then output: \`->relay-file:spawn\`
2395
-
2396
- **Message Format:**
2397
- - \`TO: AgentName\` for direct messages
2398
- - \`TO: *\` to broadcast to all agents
2399
- - \`TO: #channel\` for channel messages
2400
-
2401
- 📖 See **AGENTS.md** in the project root for full protocol documentation.`;
2402
-
2403
- this.log(` Sending periodic protocol reminder (session: ${sessionDurationMinutes}m)`);
2404
- this.injectProtocolReminder(reminder);
2405
- }
2406
-
2407
- /**
2408
- * Check for messages stuck in the queue and process them if the agent is idle.
2409
- *
2410
- * This handles cases where:
2411
- * 1. Messages arrived while the agent was busy and the retry mechanism failed
2412
- * 2. Socket disconnection/reconnection left messages orphaned
2413
- * 3. Injection timeouts occurred without proper queue resumption
2414
- */
2415
- private checkForStuckQueue(): void {
2416
- // Skip if not ready for messages
2417
- if (!this.readyForMessages || !this.running) {
2418
- return;
2419
- }
2420
-
2421
- // Skip if queue is empty
2422
- if (this.messageQueue.length === 0) {
2423
- return;
2424
- }
2425
-
2426
- // Check if currently injecting
2427
- if (this.isInjecting) {
2428
- // Check if injection has been stuck for too long
2429
- const stuckDuration = Date.now() - this.injectionStartTime;
2430
- if (stuckDuration > this.MAX_INJECTION_STUCK_MS) {
2431
- this.logError(` ⚠️ Injection stuck for ${Math.round(stuckDuration / 1000)}s - force resetting`);
2432
- this.isInjecting = false;
2433
- this.injectionStartTime = 0;
2434
- // Clear any pending injections that might be stuck
2435
- for (const [id, pending] of this.pendingInjections) {
2436
- clearTimeout(pending.timeout);
2437
- this.logError(` Clearing stuck pending injection: ${id.substring(0, 8)}`);
2438
- }
2439
- this.pendingInjections.clear();
2440
- // Continue to process the queue below
2441
- } else {
2442
- return; // Still within normal injection time
2443
- }
2444
- }
2445
-
2446
- // Skip if backpressure is active
2447
- if (this.backpressureActive) {
2448
- return;
2449
- }
2450
-
2451
- // Check if the agent is idle (high confidence)
2452
- const idleResult = this.idleDetector.checkIdle({ minSilenceMs: 2000 });
2453
- if (!idleResult.isIdle) {
2454
- // Agent is still working, let it finish
2455
- return;
2456
- }
2457
-
2458
- // We have messages in the queue, agent is idle, not currently injecting
2459
- // This is a stuck queue situation - trigger processing
2460
- const senders = [...new Set(this.messageQueue.map(m => m.from))];
2461
- this.log(` ⚠️ Queue monitor: Found ${this.messageQueue.length} stuck message(s) from [${senders.join(', ')}]`);
2462
- this.log(` ⚠️ Agent is idle (confidence: ${(idleResult.confidence * 100).toFixed(0)}%), triggering queue processing`);
2463
-
2464
- // Process the queue
2465
- this.processMessageQueue();
2466
- }
2467
-
2468
- // =========================================================================
2469
- // Output parsing
2470
- // =========================================================================
2471
-
2472
- /**
2473
- * Parse relay commands from output
2474
- */
2475
- private parseRelayCommands(): void {
2476
- const cleanContent = stripAnsi(this.rawBuffer);
2477
-
2478
- if (cleanContent.length <= this.lastParsedLength) {
2479
- return;
2480
- }
2481
-
2482
- // Parse new content with lookback for fenced messages
2483
- const lookbackStart = Math.max(0, this.lastParsedLength - 500);
2484
- const contentToParse = cleanContent.substring(lookbackStart);
2485
-
2486
- // Parse fenced messages
2487
- this.parseFencedMessages(contentToParse);
2488
-
2489
- // Parse single-line messages
2490
- this.parseSingleLineMessages(contentToParse);
2491
-
2492
- // Parse spawn/release commands
2493
- this.parseSpawnReleaseCommands(contentToParse);
2494
-
2495
- this.lastParsedLength = cleanContent.length;
2496
- }
2497
-
2498
- /**
2499
- * Parse fenced multi-line messages
2500
- */
2501
- private parseFencedMessages(content: string): void {
2502
- const escapedPrefix = this.relayPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2503
- const fencePattern = new RegExp(
2504
- `${escapedPrefix}(\\S+)(?:\\s+\\[thread:([\\w-]+)\\])?\\s*<<<([\\s\\S]*?)>>>`,
2505
- 'g'
2506
- );
2507
-
2508
- let match;
2509
- while ((match = fencePattern.exec(content)) !== null) {
2510
- const target = match[1];
2511
- const thread = match[2];
2512
- const body = match[3].trim();
2513
-
2514
- if (!body || target === 'spawn' || target === 'release') {
2515
- continue;
2516
- }
2517
-
2518
- this.sendRelayCommand({
2519
- to: target,
2520
- kind: 'message',
2521
- body,
2522
- thread,
2523
- raw: match[0],
2524
- });
2525
- }
2526
- }
2527
-
2528
- /**
2529
- * Parse single-line messages
2530
- */
2531
- private parseSingleLineMessages(content: string): void {
2532
- const lines = content.split('\n');
2533
- const escapedPrefix = this.relayPrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2534
- const pattern = new RegExp(`${escapedPrefix}(\\S+)(?:\\s+\\[thread:([\\w-]+)\\])?\\s+(.+)$`);
2535
-
2536
- for (const line of lines) {
2537
- // Skip fenced messages
2538
- if (line.includes('<<<') || line.includes('>>>')) {
2539
- continue;
2540
- }
2541
-
2542
- const match = line.match(pattern);
2543
- if (!match) {
2544
- continue;
2545
- }
2546
-
2547
- const target = match[1];
2548
- const thread = match[2];
2549
- const body = match[3].trim();
2550
-
2551
- if (!body || target === 'spawn' || target === 'release') {
2552
- continue;
2553
- }
2554
-
2555
- this.sendRelayCommand({
2556
- to: target,
2557
- kind: 'message',
2558
- body,
2559
- thread,
2560
- raw: line,
2561
- });
2562
- }
2563
- }
2564
-
2565
- // =========================================================================
2566
- // Summary and session end detection
2567
- // =========================================================================
2568
-
2569
- /**
2570
- * Check for [[SUMMARY]] blocks
2571
- */
2572
- private checkForSummary(content: string): void {
2573
- const result = parseSummaryWithDetails(content);
2574
- if (!result.found || !result.valid) {
2575
- return;
2576
- }
2577
-
2578
- if (result.rawContent === this.lastSummaryRawContent) {
2579
- return;
2580
- }
2581
- this.lastSummaryRawContent = result.rawContent ?? '';
2582
-
2583
- this.emit('summary', {
2584
- agentName: this.config.name,
2585
- summary: result.summary,
2586
- });
2587
- }
2588
-
2589
- /**
2590
- * Check for [[SESSION_END]] blocks
2591
- */
2592
- private checkForSessionEnd(content: string): void {
2593
- if (this.sessionEndProcessed) {
2594
- return;
2595
- }
2596
-
2597
- const sessionEnd = parseSessionEndFromOutput(content);
2598
- if (!sessionEnd) {
2599
- return;
2600
- }
2601
-
2602
- // Store SESSION_END data for use in autoSave (fixes empty handoff issue)
2603
- this.sessionEndData = sessionEnd;
2604
-
2605
- this.sessionEndProcessed = true;
2606
- this.emit('session-end', {
2607
- agentName: this.config.name,
2608
- marker: sessionEnd,
2609
- });
2610
- }
2611
-
2612
- // =========================================================================
2613
- // Public API
2614
- // =========================================================================
2615
-
2616
- /**
2617
- * Query status from relay-pty
2618
- */
2619
- async queryStatus(): Promise<StatusResponse | null> {
2620
- if (!this.socket || !this.socketConnected) {
2621
- return null;
2622
- }
2623
-
2624
- try {
2625
- await this.sendSocketRequest({ type: 'status' });
2626
- // Response will come asynchronously via handleSocketResponse
2627
- // For now, return null - could implement request/response matching
2628
- return null;
2629
- } catch {
2630
- return null;
2631
- }
2632
- }
2633
-
2634
- /**
2635
- * Wait for the CLI to be ready to receive messages.
2636
- * This waits for:
2637
- * 1. The CLI to produce at least one output (it has started)
2638
- * 2. The CLI to become idle (it's ready for input)
2639
- *
2640
- * This is more reliable than a random sleep because it waits for
2641
- * actual signals from the CLI rather than guessing how long it takes to start.
2642
- *
2643
- * @param timeoutMs Maximum time to wait (default: 30s)
2644
- * @param pollMs Polling interval (default: 100ms)
2645
- * @returns true if CLI is ready, false if timeout
2646
- */
2647
- async waitUntilCliReady(timeoutMs = 30000, pollMs = 100): Promise<boolean> {
2648
- const startTime = Date.now();
2649
- this.log(` Waiting for CLI to be ready (timeout: ${timeoutMs}ms)`);
2650
-
2651
- // In interactive mode, stdout is inherited (not captured), so hasReceivedOutput
2652
- // will never be set. Trust that the process is ready if it's running.
2653
- if (this.isInteractive) {
2654
- this.log(` Interactive mode - trusting process is ready`);
2655
- // Give a brief moment for the CLI to initialize its TUI.
2656
- // 500ms is a conservative estimate based on typical CLI startup times:
2657
- // - Claude CLI: ~200-300ms to show initial prompt
2658
- // - Codex/Gemini: ~300-400ms
2659
- // This delay is only used in interactive mode where we can't detect output.
2660
- // In non-interactive mode, we poll for actual output instead.
2661
- await sleep(500);
2662
- return this.running;
2663
- }
2664
-
2665
- // Phase 1: Wait for first output (CLI has started)
2666
- while (Date.now() - startTime < timeoutMs) {
2667
- if (this.hasReceivedOutput) {
2668
- this.log(` CLI has started producing output`);
2669
- break;
2670
- }
2671
- await sleep(pollMs);
2672
- }
2673
-
2674
- if (!this.hasReceivedOutput) {
2675
- this.log(` Timeout waiting for CLI to produce output`);
2676
- return false;
2677
- }
2678
-
2679
- // Phase 2: Wait for idle state (CLI is ready for input)
2680
- const remainingTime = timeoutMs - (Date.now() - startTime);
2681
- if (remainingTime <= 0) {
2682
- return false;
2683
- }
2684
-
2685
- const idleResult = await this.waitForIdleState(remainingTime, pollMs);
2686
- if (idleResult.isIdle) {
2687
- this.log(` CLI is idle and ready (confidence: ${idleResult.confidence.toFixed(2)})`);
2688
- return true;
2689
- }
2690
-
2691
- this.log(` Timeout waiting for CLI to become idle`);
2692
- return false;
2693
- }
2694
-
2695
- /**
2696
- * Check if the CLI has produced any output yet.
2697
- * Useful for checking if the CLI has started without blocking.
2698
- * In interactive mode, returns true if process is running (output isn't captured).
2699
- */
2700
- hasCliStarted(): boolean {
2701
- // In interactive mode, stdout isn't captured so hasReceivedOutput is never set
2702
- if (this.isInteractive) {
2703
- return this.running;
2704
- }
2705
- return this.hasReceivedOutput;
2706
- }
2707
-
2708
- /**
2709
- * Check if the orchestrator is ready to receive and inject messages.
2710
- * This requires:
2711
- * 1. relay-pty process spawned
2712
- * 2. Socket connected to relay-pty
2713
- * 3. running flag set
2714
- *
2715
- * Use this to verify the agent can actually receive injected messages,
2716
- * not just that the CLI is running.
2717
- */
2718
- isReadyForMessages(): boolean {
2719
- return this.readyForMessages && this.running && this.socketConnected;
2720
- }
2721
-
2722
- /**
2723
- * Wait until the orchestrator is ready to receive and inject messages.
2724
- * This is more comprehensive than waitUntilCliReady because it ensures:
2725
- * 1. CLI is ready (has output and is idle)
2726
- * 2. Orchestrator is ready (socket connected, can inject)
2727
- *
2728
- * @param timeoutMs Maximum time to wait (default: 30s)
2729
- * @param pollMs Polling interval (default: 100ms)
2730
- * @returns true if ready, false if timeout
2731
- */
2732
- async waitUntilReadyForMessages(timeoutMs = 30000, pollMs = 100): Promise<boolean> {
2733
- const startTime = Date.now();
2734
- this.log(` Waiting for orchestrator to be ready for messages (timeout: ${timeoutMs}ms)`);
2735
-
2736
- // First wait for CLI to be ready (output + idle)
2737
- const cliReady = await this.waitUntilCliReady(timeoutMs, pollMs);
2738
- if (!cliReady) {
2739
- this.log(` CLI not ready within timeout`);
2740
- return false;
2741
- }
2742
-
2743
- // Then wait for readyForMessages flag
2744
- const remainingTime = timeoutMs - (Date.now() - startTime);
2745
- if (remainingTime <= 0) {
2746
- this.log(` No time remaining to wait for readyForMessages`);
2747
- return this.isReadyForMessages();
2748
- }
2749
-
2750
- while (Date.now() - startTime < timeoutMs) {
2751
- if (this.isReadyForMessages()) {
2752
- this.log(` Orchestrator is ready for messages`);
2753
- return true;
2754
- }
2755
- await sleep(pollMs);
2756
- }
2757
-
2758
- this.log(` Timeout waiting for orchestrator to be ready for messages`);
2759
- return false;
2760
- }
2761
-
2762
- /**
2763
- * Get raw output buffer
2764
- */
2765
- getRawOutput(): string {
2766
- return this.rawBuffer;
2767
- }
2768
-
2769
- /**
2770
- * Check if backpressure is active
2771
- */
2772
- isBackpressureActive(): boolean {
2773
- return this.backpressureActive;
2774
- }
2775
-
2776
- /**
2777
- * Get the socket path
2778
- */
2779
- getSocketPath(): string {
2780
- return this.socketPath;
2781
- }
2782
-
2783
- /**
2784
- * Get the relay-pty process PID
2785
- */
2786
- get pid(): number | undefined {
2787
- return this.relayPtyProcess?.pid;
2788
- }
2789
-
2790
- /**
2791
- * Get the log file path (not used by relay-pty, returns undefined)
2792
- */
2793
- get logPath(): string | undefined {
2794
- return this._logPath;
2795
- }
2796
-
2797
- /**
2798
- * Kill the process forcefully
2799
- */
2800
- async kill(): Promise<void> {
2801
- this.isGracefulStop = true; // Mark as intentional to prevent crash broadcast
2802
- if (this.socketReconnectTimer) {
2803
- clearTimeout(this.socketReconnectTimer);
2804
- this.socketReconnectTimer = undefined;
2805
- }
2806
- if (this.relayPtyProcess && !this.relayPtyProcess.killed) {
2807
- this.relayPtyProcess.kill('SIGKILL');
2808
- }
2809
- this.running = false;
2810
- this.disconnectSocket();
2811
- this.destroyClient();
2812
- }
2813
-
2814
- /**
2815
- * Get output lines (for compatibility with PtyWrapper)
2816
- * @param limit Maximum number of lines to return
2817
- */
2818
- getOutput(limit?: number): string[] {
2819
- const lines = this.rawBuffer.split('\n');
2820
- if (limit && limit > 0) {
2821
- return lines.slice(-limit);
2822
- }
2823
- return lines;
2824
- }
2825
-
2826
- /**
2827
- * Write data directly to the process stdin
2828
- * @param data Data to write
2829
- */
2830
- async write(data: string | Buffer): Promise<void> {
2831
- if (!this.relayPtyProcess || !this.relayPtyProcess.stdin) {
2832
- throw new Error('Process not running');
2833
- }
2834
- const buffer = typeof data === 'string' ? Buffer.from(data) : data;
2835
- this.relayPtyProcess.stdin.write(buffer);
2836
- }
2837
-
2838
- /**
2839
- * Verify that the CLI shows activity after task injection.
2840
- * Checks output for patterns indicating the task was received and processing started.
2841
- *
2842
- * This catches the race condition where PTY write succeeds but CLI wasn't ready
2843
- * (the T-003 failure scenario where CLI showed bell characters instead of processing).
2844
- *
2845
- * @param outputBefore The output buffer content before injection
2846
- * @returns Promise resolving to true if activity detected, false otherwise
2847
- */
2848
- private async verifyActivityAfterInjection(outputBefore: string): Promise<boolean> {
2849
- const startTime = Date.now();
2850
- const { TIMEOUT_MS, POLL_INTERVAL_MS, TASK_RECEIVED_PATTERNS, THINKING_PATTERNS, TOOL_EXECUTION_PATTERNS } = ACTIVITY_VERIFICATION;
2851
- const trimCountBefore = this.bufferTrimCount;
2852
-
2853
- while (Date.now() - startTime < TIMEOUT_MS) {
2854
- // If buffers were trimmed during verification, treat it as activity.
2855
- // Large output growth triggers trimming, which would otherwise make slice() return
2856
- // an empty string and falsely signal no activity.
2857
- if (this.bufferTrimCount !== trimCountBefore) {
2858
- this.log(` Activity verified: output buffer trimmed during verification (large output)`);
2859
- return true;
2860
- }
2861
-
2862
- // Get new output since injection
2863
- const currentOutput = this.outputBuffer;
2864
- const newOutput = currentOutput.slice(outputBefore.length);
2865
-
2866
- if (newOutput.length > 0) {
2867
- // REJECTION CHECK: Multiple BEL characters (0x07) indicate CLI rejected input
2868
- // The T-003 failure showed CLI producing 1000+ BELs when input was injected
2869
- // while the CLI wasn't ready (still initializing or in wrong mode)
2870
- const belCount = (newOutput.match(/\x07/g) || []).length;
2871
- if (belCount > 10) {
2872
- this.logError(` Input rejected: CLI produced ${belCount} BEL characters`);
2873
- return false; // Don't wait - immediately fail so retry can attempt
2874
- }
2875
-
2876
- // Check for task received patterns (primary verification)
2877
- for (const pattern of TASK_RECEIVED_PATTERNS) {
2878
- if (pattern.test(newOutput)) {
2879
- this.log(` Activity verified: task received pattern matched`);
2880
- return true;
2881
- }
2882
- }
2883
-
2884
- // Check for thinking/processing patterns (secondary verification)
2885
- for (const pattern of THINKING_PATTERNS) {
2886
- if (pattern.test(newOutput)) {
2887
- this.log(` Activity verified: thinking pattern matched`);
2888
- return true;
2889
- }
2890
- }
2891
-
2892
- // Check for tool execution patterns (tertiary verification)
2893
- for (const pattern of TOOL_EXECUTION_PATTERNS) {
2894
- if (pattern.test(newOutput)) {
2895
- this.log(` Activity verified: tool execution pattern matched`);
2896
- return true;
2897
- }
2898
- }
2899
-
2900
- // Fallback: If output grew significantly (>100 meaningful chars), assume activity
2901
- // This catches CLIs with unusual output patterns
2902
- // IMPORTANT: Strip out BEL (0x07) and other control characters - these are rejection
2903
- // signals not activity. The T-003 failure showed CLI producing 1000+ BELs when input
2904
- // was injected before it was ready.
2905
- const meaningfulOutput = newOutput.replace(/[\x00-\x1f]/g, ''); // Strip control chars
2906
- if (meaningfulOutput.length > 100) {
2907
- this.log(` Activity verified: significant output growth (${meaningfulOutput.length} meaningful chars)`);
2908
- return true;
2909
- }
2910
- }
2911
-
2912
- await sleep(POLL_INTERVAL_MS);
2913
- }
2914
-
2915
- // No activity detected within timeout
2916
- this.log(` No activity detected within ${TIMEOUT_MS}ms`);
2917
- return false;
2918
- }
2919
-
2920
- /**
2921
- * Inject a task using the socket-based injection system with activity verification.
2922
- * This is the preferred method for spawned agent task delivery.
2923
- *
2924
- * After socket confirms delivery, verifies the CLI shows activity (task received,
2925
- * thinking indicators, or tool execution). Retries if no activity is detected.
2926
- *
2927
- * @param task The task text to inject
2928
- * @param from The sender name (default: "spawner")
2929
- * @returns Promise resolving to true if task was delivered AND activity verified, false otherwise
2930
- */
2931
- async injectTask(task: string, from = 'spawner'): Promise<boolean> {
2932
- const { MAX_RETRIES, RETRY_DELAY_MS } = ACTIVITY_VERIFICATION;
2933
-
2934
- // Claude Code's TUI needs a stabilization delay after displaying the welcome screen
2935
- // before it's ready to accept stdin input. Without this, input may be silently dropped
2936
- // even though the CLI appears "idle" and doesn't reject with BELs.
2937
- // 1500ms is based on observed behavior - Claude Code typically needs 1-1.5s after
2938
- // its TUI renders before input handlers are fully initialized.
2939
- const STABILIZATION_DELAY_MS = 1500;
2940
- this.log(` Waiting ${STABILIZATION_DELAY_MS}ms for CLI stabilization before task injection`);
2941
- await sleep(STABILIZATION_DELAY_MS);
2942
-
2943
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
2944
- if (attempt > 0) {
2945
- this.log(` Retry ${attempt}/${MAX_RETRIES} - waiting ${RETRY_DELAY_MS}ms before retry`);
2946
- await sleep(RETRY_DELAY_MS);
2947
- }
2948
-
2949
- // Capture output buffer state before injection
2950
- const outputBefore = this.outputBuffer;
2951
-
2952
- // Attempt delivery via socket
2953
- const delivered = await this.performTaskInjection(task, from);
2954
- if (!delivered) {
2955
- this.logError(` Task delivery failed on attempt ${attempt + 1}`);
2956
- continue; // Retry
2957
- }
2958
-
2959
- // Verify CLI shows activity (task received, thinking, or tool execution)
2960
- const activityVerified = await this.verifyActivityAfterInjection(outputBefore);
2961
- if (activityVerified) {
2962
- this.log(` Task delivered and activity verified successfully`);
2963
- return true;
2964
- }
2965
-
2966
- // Delivery succeeded but no activity - CLI might not have been ready
2967
- this.logError(` Task delivered but no activity detected (attempt ${attempt + 1})`);
2968
- }
2969
-
2970
- this.logError(` Task injection failed after ${MAX_RETRIES + 1} attempts - no CLI activity detected`);
2971
- return false;
2972
- }
2973
-
2974
- /**
2975
- * Perform a single task injection attempt (without retry logic).
2976
- * @returns true if the injection was sent successfully, false otherwise
2977
- */
2978
- private async performTaskInjection(task: string, from: string): Promise<boolean> {
2979
- if (!this.socket || !this.socketConnected) {
2980
- this.log(` Socket not connected for task injection, falling back to stdin write`);
2981
- try {
2982
- await this.write(task + '\n');
2983
- return true;
2984
- } catch (err: any) {
2985
- this.logError(` Stdin write fallback failed: ${err.message}`);
2986
- return false;
2987
- }
2988
- }
2989
-
2990
- const messageId = `task-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
2991
- const shortId = messageId.substring(0, 8);
2992
-
2993
- this.log(` Injecting task via socket: ${shortId}`);
2994
-
2995
- // Create request
2996
- const request: InjectRequest = {
2997
- type: 'inject',
2998
- id: messageId,
2999
- from,
3000
- body: task,
3001
- priority: 0, // High priority for initial task
3002
- };
3003
-
3004
- // Send with timeout and get socket confirmation
3005
- return new Promise<boolean>((resolve) => {
3006
- const timeout = setTimeout(() => {
3007
- this.logError(` Task inject timeout for ${shortId} after 30s`);
3008
- this.pendingInjections.delete(messageId);
3009
- resolve(false);
3010
- }, 30000);
3011
-
3012
- this.pendingInjections.set(messageId, {
3013
- resolve,
3014
- reject: () => resolve(false),
3015
- timeout,
3016
- from,
3017
- shortId,
3018
- retryCount: 0,
3019
- originalBody: task,
3020
- });
3021
-
3022
- this.sendSocketRequest(request)
3023
- .then(() => {
3024
- this.log(` Task inject request sent: ${shortId}`);
3025
- })
3026
- .catch((err) => {
3027
- this.logError(` Task inject socket request failed: ${err.message}`);
3028
- clearTimeout(timeout);
3029
- this.pendingInjections.delete(messageId);
3030
- resolve(false);
3031
- });
3032
- });
3033
- }
3034
-
3035
- /**
3036
- * Get the agent ID (from continuity if available)
3037
- */
3038
- getAgentId(): string | undefined {
3039
- return this.agentId;
3040
- }
3041
- }