agent-relay 2.0.29 → 2.0.32

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 (894) hide show
  1. package/README.md +19 -0
  2. package/dist/index.cjs +85691 -0
  3. package/dist/src/bridge/index.d.ts.map +1 -0
  4. package/dist/src/bridge/index.js.map +1 -0
  5. package/dist/src/cli/commands/doctor.d.ts +2 -0
  6. package/dist/src/cli/commands/doctor.d.ts.map +1 -0
  7. package/dist/src/cli/commands/doctor.js +451 -0
  8. package/dist/src/cli/commands/doctor.js.map +1 -0
  9. package/dist/src/cli/index.d.ts.map +1 -0
  10. package/dist/src/cli/index.js +29 -1
  11. package/dist/src/cli/index.js.map +1 -0
  12. package/dist/src/config/relay-config.d.ts.map +1 -0
  13. package/dist/src/config/relay-config.js.map +1 -0
  14. package/dist/src/continuity/index.d.ts.map +1 -0
  15. package/dist/src/continuity/index.js.map +1 -0
  16. package/dist/src/daemon/index.d.ts.map +1 -0
  17. package/dist/src/daemon/index.js.map +1 -0
  18. package/dist/src/health-worker-manager.d.ts.map +1 -0
  19. package/dist/src/health-worker-manager.js.map +1 -0
  20. package/dist/src/health-worker.d.ts.map +1 -0
  21. package/dist/src/health-worker.js.map +1 -0
  22. package/dist/src/hooks/index.d.ts.map +1 -0
  23. package/dist/src/hooks/index.js.map +1 -0
  24. package/dist/src/index.d.ts.map +1 -0
  25. package/dist/src/index.js.map +1 -0
  26. package/dist/src/memory/index.d.ts.map +1 -0
  27. package/dist/src/memory/index.js.map +1 -0
  28. package/dist/src/policy/index.d.ts.map +1 -0
  29. package/dist/src/policy/index.js.map +1 -0
  30. package/dist/src/protocol/index.d.ts.map +1 -0
  31. package/dist/src/protocol/index.js.map +1 -0
  32. package/dist/src/resiliency/index.d.ts.map +1 -0
  33. package/dist/src/resiliency/index.js.map +1 -0
  34. package/dist/src/shared/cli-auth-config.d.ts.map +1 -0
  35. package/dist/src/shared/cli-auth-config.js.map +1 -0
  36. package/dist/src/state/index.d.ts.map +1 -0
  37. package/dist/src/state/index.js.map +1 -0
  38. package/dist/src/storage/index.d.ts.map +1 -0
  39. package/dist/src/storage/index.js.map +1 -0
  40. package/dist/src/trajectory/index.d.ts.map +1 -0
  41. package/dist/src/trajectory/index.js.map +1 -0
  42. package/dist/src/utils/index.d.ts.map +1 -0
  43. package/dist/src/utils/index.js.map +1 -0
  44. package/dist/src/wrapper/index.d.ts.map +1 -0
  45. package/dist/src/wrapper/index.js.map +1 -0
  46. package/package.json +83 -20
  47. package/packages/api-types/dist/index.d.ts.map +1 -0
  48. package/packages/api-types/dist/index.js.map +1 -0
  49. package/packages/api-types/dist/schemas/agent.d.ts.map +1 -0
  50. package/packages/api-types/dist/schemas/agent.js.map +1 -0
  51. package/packages/api-types/dist/schemas/api.d.ts.map +1 -0
  52. package/packages/api-types/dist/schemas/api.js.map +1 -0
  53. package/packages/api-types/dist/schemas/decision.d.ts.map +1 -0
  54. package/packages/api-types/dist/schemas/decision.js.map +1 -0
  55. package/packages/api-types/dist/schemas/fleet.d.ts.map +1 -0
  56. package/packages/api-types/dist/schemas/fleet.js.map +1 -0
  57. package/packages/api-types/dist/schemas/history.d.ts.map +1 -0
  58. package/packages/api-types/dist/schemas/history.js.map +1 -0
  59. package/packages/api-types/dist/schemas/index.d.ts.map +1 -0
  60. package/packages/api-types/dist/schemas/index.js.map +1 -0
  61. package/packages/api-types/dist/schemas/message.d.ts.map +1 -0
  62. package/packages/api-types/dist/schemas/message.js.map +1 -0
  63. package/packages/api-types/dist/schemas/session.d.ts.map +1 -0
  64. package/packages/api-types/dist/schemas/session.js.map +1 -0
  65. package/packages/api-types/dist/schemas/task.d.ts.map +1 -0
  66. package/packages/api-types/dist/schemas/task.js.map +1 -0
  67. package/packages/api-types/package.json +1 -1
  68. package/packages/api-types/src/index.ts +22 -0
  69. package/packages/api-types/src/schemas/agent.test.ts +164 -0
  70. package/packages/api-types/src/schemas/agent.ts +110 -0
  71. package/packages/api-types/src/schemas/api.test.ts +372 -0
  72. package/packages/api-types/src/schemas/api.ts +194 -0
  73. package/packages/api-types/src/schemas/decision.test.ts +324 -0
  74. package/packages/api-types/src/schemas/decision.ts +136 -0
  75. package/packages/api-types/src/schemas/fleet.test.ts +212 -0
  76. package/packages/api-types/src/schemas/fleet.ts +83 -0
  77. package/packages/api-types/src/schemas/history.test.ts +242 -0
  78. package/packages/api-types/src/schemas/history.ts +84 -0
  79. package/packages/api-types/src/schemas/index.ts +148 -0
  80. package/packages/api-types/src/schemas/message.test.ts +192 -0
  81. package/packages/api-types/src/schemas/message.ts +98 -0
  82. package/packages/api-types/src/schemas/session.test.ts +104 -0
  83. package/packages/api-types/src/schemas/session.ts +40 -0
  84. package/packages/api-types/src/schemas/task.test.ts +192 -0
  85. package/packages/api-types/src/schemas/task.ts +78 -0
  86. package/packages/api-types/tsconfig.json +19 -0
  87. package/packages/api-types/vitest.config.ts +9 -0
  88. package/packages/benchmark/README.md +200 -0
  89. package/packages/benchmark/datasets/coding-tasks.yaml +127 -0
  90. package/packages/benchmark/datasets/coordination-tasks.yaml +122 -0
  91. package/packages/benchmark/dist/benchmark.d.ts +47 -0
  92. package/packages/benchmark/dist/benchmark.d.ts.map +1 -0
  93. package/packages/benchmark/dist/benchmark.js +224 -0
  94. package/packages/benchmark/dist/benchmark.js.map +1 -0
  95. package/packages/benchmark/dist/cli.d.ts +8 -0
  96. package/packages/benchmark/dist/cli.d.ts.map +1 -0
  97. package/packages/benchmark/dist/cli.js +185 -0
  98. package/packages/benchmark/dist/cli.js.map +1 -0
  99. package/packages/benchmark/dist/harbor.d.ts +53 -0
  100. package/packages/benchmark/dist/harbor.d.ts.map +1 -0
  101. package/packages/benchmark/dist/harbor.js +127 -0
  102. package/packages/benchmark/dist/harbor.js.map +1 -0
  103. package/packages/benchmark/dist/index.d.ts +48 -0
  104. package/packages/benchmark/dist/index.d.ts.map +1 -0
  105. package/packages/benchmark/dist/index.js +50 -0
  106. package/packages/benchmark/dist/index.js.map +1 -0
  107. package/packages/benchmark/dist/runners/base.d.ts +63 -0
  108. package/packages/benchmark/dist/runners/base.d.ts.map +1 -0
  109. package/packages/benchmark/dist/runners/base.js +155 -0
  110. package/packages/benchmark/dist/runners/base.js.map +1 -0
  111. package/packages/benchmark/dist/runners/index.d.ts +10 -0
  112. package/packages/benchmark/dist/runners/index.d.ts.map +1 -0
  113. package/packages/benchmark/dist/runners/index.js +10 -0
  114. package/packages/benchmark/dist/runners/index.js.map +1 -0
  115. package/packages/benchmark/dist/runners/single.d.ts +19 -0
  116. package/packages/benchmark/dist/runners/single.d.ts.map +1 -0
  117. package/packages/benchmark/dist/runners/single.js +111 -0
  118. package/packages/benchmark/dist/runners/single.js.map +1 -0
  119. package/packages/benchmark/dist/runners/subagent.d.ts +32 -0
  120. package/packages/benchmark/dist/runners/subagent.d.ts.map +1 -0
  121. package/packages/benchmark/dist/runners/subagent.js +212 -0
  122. package/packages/benchmark/dist/runners/subagent.js.map +1 -0
  123. package/packages/benchmark/dist/runners/swarm.d.ts +36 -0
  124. package/packages/benchmark/dist/runners/swarm.d.ts.map +1 -0
  125. package/packages/benchmark/dist/runners/swarm.js +273 -0
  126. package/packages/benchmark/dist/runners/swarm.js.map +1 -0
  127. package/packages/benchmark/dist/types.d.ts +178 -0
  128. package/packages/benchmark/dist/types.d.ts.map +1 -0
  129. package/packages/benchmark/dist/types.js +16 -0
  130. package/packages/benchmark/dist/types.js.map +1 -0
  131. package/packages/benchmark/package.json +80 -0
  132. package/packages/benchmark/src/benchmark.ts +298 -0
  133. package/packages/benchmark/src/cli.ts +240 -0
  134. package/packages/benchmark/src/harbor.ts +170 -0
  135. package/packages/benchmark/src/index.ts +73 -0
  136. package/packages/benchmark/src/runners/base.ts +204 -0
  137. package/packages/benchmark/src/runners/index.ts +10 -0
  138. package/packages/benchmark/src/runners/single.ts +121 -0
  139. package/packages/benchmark/src/runners/subagent.ts +240 -0
  140. package/packages/benchmark/src/runners/swarm.ts +326 -0
  141. package/packages/benchmark/src/types.ts +205 -0
  142. package/packages/benchmark/tsconfig.json +20 -0
  143. package/packages/bridge/dist/index.d.ts.map +1 -0
  144. package/packages/bridge/dist/index.js.map +1 -0
  145. package/packages/bridge/dist/multi-project-client.d.ts.map +1 -0
  146. package/packages/bridge/dist/multi-project-client.js.map +1 -0
  147. package/packages/bridge/dist/shadow-cli.d.ts.map +1 -0
  148. package/packages/bridge/dist/shadow-cli.js.map +1 -0
  149. package/packages/bridge/dist/spawner.d.ts.map +1 -0
  150. package/packages/bridge/dist/spawner.js +10 -2
  151. package/packages/bridge/dist/spawner.js.map +1 -0
  152. package/packages/bridge/dist/types.d.ts.map +1 -0
  153. package/packages/bridge/dist/types.js.map +1 -0
  154. package/packages/bridge/dist/utils.d.ts.map +1 -0
  155. package/packages/bridge/dist/utils.js.map +1 -0
  156. package/packages/bridge/package.json +8 -8
  157. package/packages/bridge/src/index.ts +25 -0
  158. package/packages/bridge/src/multi-project-client.test.ts +340 -0
  159. package/packages/bridge/src/multi-project-client.ts +469 -0
  160. package/packages/bridge/src/shadow-cli.ts +95 -0
  161. package/packages/bridge/src/spawner-mcp.test.ts +505 -0
  162. package/packages/bridge/src/spawner.ts +1724 -0
  163. package/packages/bridge/src/types.ts +145 -0
  164. package/packages/bridge/src/utils.test.ts +98 -0
  165. package/packages/bridge/src/utils.ts +67 -0
  166. package/packages/bridge/tsconfig.json +29 -0
  167. package/packages/bridge/vitest.config.ts +9 -0
  168. package/packages/cli-tester/dist/index.d.ts.map +1 -0
  169. package/packages/cli-tester/dist/index.js.map +1 -0
  170. package/packages/cli-tester/dist/utils/credential-check.d.ts.map +1 -0
  171. package/packages/cli-tester/dist/utils/credential-check.js.map +1 -0
  172. package/packages/cli-tester/dist/utils/socket-client.d.ts.map +1 -0
  173. package/packages/cli-tester/dist/utils/socket-client.js.map +1 -0
  174. package/packages/cli-tester/docker/Dockerfile +61 -0
  175. package/packages/cli-tester/docker/docker-compose.yml +71 -0
  176. package/packages/cli-tester/package.json +1 -1
  177. package/packages/cli-tester/src/index.ts +40 -0
  178. package/packages/cli-tester/src/utils/credential-check.ts +284 -0
  179. package/packages/cli-tester/src/utils/socket-client.ts +211 -0
  180. package/packages/cli-tester/tests/credential-check.test.ts +56 -0
  181. package/packages/cli-tester/tsconfig.json +11 -0
  182. package/packages/config/dist/agent-config.d.ts.map +1 -0
  183. package/packages/config/dist/agent-config.js.map +1 -0
  184. package/packages/config/dist/bridge-config.d.ts.map +1 -0
  185. package/packages/config/dist/bridge-config.js.map +1 -0
  186. package/packages/config/dist/bridge-utils.d.ts.map +1 -0
  187. package/packages/config/dist/bridge-utils.js.map +1 -0
  188. package/packages/config/dist/cli-auth-config.d.ts.map +1 -0
  189. package/packages/config/dist/cli-auth-config.js.map +1 -0
  190. package/packages/config/dist/cloud-config.d.ts.map +1 -0
  191. package/packages/config/dist/cloud-config.js.map +1 -0
  192. package/packages/config/dist/index.d.ts.map +1 -0
  193. package/packages/config/dist/index.js.map +1 -0
  194. package/packages/config/dist/project-namespace.d.ts.map +1 -0
  195. package/packages/config/dist/project-namespace.js.map +1 -0
  196. package/packages/config/dist/relay-config.d.ts.map +1 -0
  197. package/packages/config/dist/relay-config.js.map +1 -0
  198. package/packages/config/dist/relay-file-writer.d.ts.map +1 -0
  199. package/packages/config/dist/relay-file-writer.js.map +1 -0
  200. package/packages/config/dist/schemas.d.ts.map +1 -0
  201. package/packages/config/dist/schemas.js.map +1 -0
  202. package/packages/config/dist/shadow-config.d.ts.map +1 -0
  203. package/packages/config/dist/shadow-config.js.map +1 -0
  204. package/packages/config/dist/teams-config.d.ts.map +1 -0
  205. package/packages/config/dist/teams-config.js.map +1 -0
  206. package/packages/config/dist/trajectory-config.d.ts.map +1 -0
  207. package/packages/config/dist/trajectory-config.js.map +1 -0
  208. package/packages/config/package.json +2 -2
  209. package/packages/config/src/agent-config.test.ts +245 -0
  210. package/packages/config/src/agent-config.ts +160 -0
  211. package/packages/config/src/bridge-config.test.ts +132 -0
  212. package/packages/config/src/bridge-config.ts +189 -0
  213. package/packages/config/src/bridge-utils.ts +59 -0
  214. package/packages/config/src/cli-auth-config.ts +548 -0
  215. package/packages/config/src/cloud-config.ts +208 -0
  216. package/packages/config/src/index.ts +12 -0
  217. package/packages/config/src/project-namespace.ts +344 -0
  218. package/packages/config/src/relay-config.test.ts +51 -0
  219. package/packages/config/src/relay-config.ts +36 -0
  220. package/packages/config/src/relay-file-writer.test.ts +351 -0
  221. package/packages/config/src/relay-file-writer.ts +508 -0
  222. package/packages/config/src/schemas.test.ts +59 -0
  223. package/packages/config/src/schemas.ts +201 -0
  224. package/packages/config/src/shadow-config.ts +205 -0
  225. package/packages/config/src/teams-config.ts +135 -0
  226. package/packages/config/src/trajectory-config.ts +222 -0
  227. package/packages/config/tsconfig.json +21 -0
  228. package/packages/config/vitest.config.ts +9 -0
  229. package/packages/continuity/dist/formatter.d.ts.map +1 -0
  230. package/packages/continuity/dist/formatter.js.map +1 -0
  231. package/packages/continuity/dist/handoff-store.d.ts.map +1 -0
  232. package/packages/continuity/dist/handoff-store.js.map +1 -0
  233. package/packages/continuity/dist/index.d.ts.map +1 -0
  234. package/packages/continuity/dist/index.js.map +1 -0
  235. package/packages/continuity/dist/ledger-store.d.ts.map +1 -0
  236. package/packages/continuity/dist/ledger-store.js.map +1 -0
  237. package/packages/continuity/dist/manager.d.ts.map +1 -0
  238. package/packages/continuity/dist/manager.js.map +1 -0
  239. package/packages/continuity/dist/parser.d.ts.map +1 -0
  240. package/packages/continuity/dist/parser.js.map +1 -0
  241. package/packages/continuity/dist/types.d.ts.map +1 -0
  242. package/packages/continuity/dist/types.js.map +1 -0
  243. package/packages/continuity/package.json +1 -1
  244. package/packages/continuity/src/formatter.ts +371 -0
  245. package/packages/continuity/src/handoff-store.ts +523 -0
  246. package/packages/continuity/src/index.ts +9 -0
  247. package/packages/continuity/src/ledger-store.ts +594 -0
  248. package/packages/continuity/src/manager.test.ts +291 -0
  249. package/packages/continuity/src/manager.ts +774 -0
  250. package/packages/continuity/src/parser.test.ts +292 -0
  251. package/packages/continuity/src/parser.ts +680 -0
  252. package/packages/continuity/src/types.ts +211 -0
  253. package/packages/continuity/tsconfig.json +21 -0
  254. package/packages/continuity/vitest.config.ts +9 -0
  255. package/packages/daemon/dist/agent-manager.d.ts.map +1 -0
  256. package/packages/daemon/dist/agent-manager.js.map +1 -0
  257. package/packages/daemon/dist/agent-registry.d.ts.map +1 -0
  258. package/packages/daemon/dist/agent-registry.js.map +1 -0
  259. package/packages/daemon/dist/agent-signing.d.ts.map +1 -0
  260. package/packages/daemon/dist/agent-signing.js.map +1 -0
  261. package/packages/daemon/dist/api.d.ts.map +1 -0
  262. package/packages/daemon/dist/api.js.map +1 -0
  263. package/packages/daemon/dist/auth.d.ts.map +1 -0
  264. package/packages/daemon/dist/auth.js.map +1 -0
  265. package/packages/daemon/dist/channel-membership-store.d.ts.map +1 -0
  266. package/packages/daemon/dist/channel-membership-store.js.map +1 -0
  267. package/packages/daemon/dist/cli-auth.d.ts.map +1 -0
  268. package/packages/daemon/dist/cli-auth.js.map +1 -0
  269. package/packages/daemon/dist/cloud-sync.d.ts.map +1 -0
  270. package/packages/daemon/dist/cloud-sync.js.map +1 -0
  271. package/packages/daemon/dist/connection.d.ts.map +1 -0
  272. package/packages/daemon/dist/connection.js.map +1 -0
  273. package/packages/daemon/dist/consensus-integration.d.ts.map +1 -0
  274. package/packages/daemon/dist/consensus-integration.js.map +1 -0
  275. package/packages/daemon/dist/consensus.d.ts.map +1 -0
  276. package/packages/daemon/dist/consensus.js.map +1 -0
  277. package/packages/daemon/dist/delivery-tracker.d.ts.map +1 -0
  278. package/packages/daemon/dist/delivery-tracker.js.map +1 -0
  279. package/packages/daemon/dist/enhanced-features.d.ts.map +1 -0
  280. package/packages/daemon/dist/enhanced-features.js.map +1 -0
  281. package/packages/daemon/dist/index.d.ts.map +1 -0
  282. package/packages/daemon/dist/index.js.map +1 -0
  283. package/packages/daemon/dist/migrations/index.d.ts.map +1 -0
  284. package/packages/daemon/dist/migrations/index.js.map +1 -0
  285. package/packages/daemon/dist/orchestrator.d.ts.map +1 -0
  286. package/packages/daemon/dist/orchestrator.js.map +1 -0
  287. package/packages/daemon/dist/rate-limiter.d.ts.map +1 -0
  288. package/packages/daemon/dist/rate-limiter.js.map +1 -0
  289. package/packages/daemon/dist/registry.d.ts.map +1 -0
  290. package/packages/daemon/dist/registry.js.map +1 -0
  291. package/packages/daemon/dist/relay-ledger.d.ts.map +1 -0
  292. package/packages/daemon/dist/relay-ledger.js.map +1 -0
  293. package/packages/daemon/dist/relay-watchdog.d.ts.map +1 -0
  294. package/packages/daemon/dist/relay-watchdog.js.map +1 -0
  295. package/packages/daemon/dist/repo-manager.d.ts.map +1 -0
  296. package/packages/daemon/dist/repo-manager.js.map +1 -0
  297. package/packages/daemon/dist/router.d.ts.map +1 -0
  298. package/packages/daemon/dist/router.js.map +1 -0
  299. package/packages/daemon/dist/server.d.ts +1 -0
  300. package/packages/daemon/dist/server.d.ts.map +1 -0
  301. package/packages/daemon/dist/server.js +46 -16
  302. package/packages/daemon/dist/server.js.map +1 -0
  303. package/packages/daemon/dist/spawn-manager.d.ts.map +1 -0
  304. package/packages/daemon/dist/spawn-manager.js.map +1 -0
  305. package/packages/daemon/dist/sync-queue.d.ts.map +1 -0
  306. package/packages/daemon/dist/sync-queue.js.map +1 -0
  307. package/packages/daemon/dist/types.d.ts.map +1 -0
  308. package/packages/daemon/dist/types.js.map +1 -0
  309. package/packages/daemon/dist/workspace-manager.d.ts.map +1 -0
  310. package/packages/daemon/dist/workspace-manager.js.map +1 -0
  311. package/packages/daemon/package.json +12 -12
  312. package/packages/daemon/src/agent-manager.ts +679 -0
  313. package/packages/daemon/src/agent-registry.ts +284 -0
  314. package/packages/daemon/src/agent-signing.ts +707 -0
  315. package/packages/daemon/src/api.ts +1012 -0
  316. package/packages/daemon/src/auth.ts +276 -0
  317. package/packages/daemon/src/channel-membership-store.ts +217 -0
  318. package/packages/daemon/src/cli-auth.ts +906 -0
  319. package/packages/daemon/src/cloud-sync.ts +902 -0
  320. package/packages/daemon/src/connection.ts +534 -0
  321. package/packages/daemon/src/consensus-integration.ts +510 -0
  322. package/packages/daemon/src/consensus.ts +848 -0
  323. package/packages/daemon/src/delivery-tracker.ts +145 -0
  324. package/packages/daemon/src/enhanced-features.ts +390 -0
  325. package/packages/daemon/src/index.ts +52 -0
  326. package/packages/daemon/src/migrations/0001_initial.sql +72 -0
  327. package/packages/daemon/src/migrations/index.test.ts +195 -0
  328. package/packages/daemon/src/migrations/index.ts +286 -0
  329. package/packages/daemon/src/orchestrator.test.ts +231 -0
  330. package/packages/daemon/src/orchestrator.ts +1376 -0
  331. package/packages/daemon/src/rate-limiter.ts +172 -0
  332. package/packages/daemon/src/registry.ts +8 -0
  333. package/packages/daemon/src/relay-ledger.test.ts +358 -0
  334. package/packages/daemon/src/relay-ledger.ts +713 -0
  335. package/packages/daemon/src/relay-watchdog.test.ts +881 -0
  336. package/packages/daemon/src/relay-watchdog.ts +785 -0
  337. package/packages/daemon/src/repo-manager.ts +468 -0
  338. package/packages/daemon/src/router.test.ts +149 -0
  339. package/packages/daemon/src/router.ts +1885 -0
  340. package/packages/daemon/src/server.ts +1871 -0
  341. package/packages/daemon/src/spawn-manager.ts +275 -0
  342. package/packages/daemon/src/sync-queue.ts +477 -0
  343. package/packages/daemon/src/types.ts +158 -0
  344. package/packages/daemon/src/workspace-manager.ts +371 -0
  345. package/packages/daemon/tsconfig.json +21 -0
  346. package/packages/hooks/dist/browser.d.ts.map +1 -0
  347. package/packages/hooks/dist/browser.js.map +1 -0
  348. package/packages/hooks/dist/emitter.d.ts.map +1 -0
  349. package/packages/hooks/dist/emitter.js.map +1 -0
  350. package/packages/hooks/dist/inbox-check/hook.d.ts.map +1 -0
  351. package/packages/hooks/dist/inbox-check/hook.js.map +1 -0
  352. package/packages/hooks/dist/inbox-check/index.d.ts.map +1 -0
  353. package/packages/hooks/dist/inbox-check/index.js.map +1 -0
  354. package/packages/hooks/dist/inbox-check/types.d.ts.map +1 -0
  355. package/packages/hooks/dist/inbox-check/types.js.map +1 -0
  356. package/packages/hooks/dist/inbox-check/utils.d.ts.map +1 -0
  357. package/packages/hooks/dist/inbox-check/utils.js.map +1 -0
  358. package/packages/hooks/dist/index.d.ts.map +1 -0
  359. package/packages/hooks/dist/index.js.map +1 -0
  360. package/packages/hooks/dist/registry.d.ts.map +1 -0
  361. package/packages/hooks/dist/registry.js.map +1 -0
  362. package/packages/hooks/dist/trajectory-hooks.d.ts.map +1 -0
  363. package/packages/hooks/dist/trajectory-hooks.js.map +1 -0
  364. package/packages/hooks/dist/types.d.ts.map +1 -0
  365. package/packages/hooks/dist/types.js.map +1 -0
  366. package/packages/hooks/package.json +4 -4
  367. package/packages/hooks/src/browser.ts +2 -0
  368. package/packages/hooks/src/emitter.ts +84 -0
  369. package/packages/hooks/src/inbox-check/hook.ts +114 -0
  370. package/packages/hooks/src/inbox-check/index.ts +8 -0
  371. package/packages/hooks/src/inbox-check/types.ts +39 -0
  372. package/packages/hooks/src/inbox-check/utils.test.ts +287 -0
  373. package/packages/hooks/src/inbox-check/utils.ts +125 -0
  374. package/packages/hooks/src/index.ts +11 -0
  375. package/packages/hooks/src/registry.ts +614 -0
  376. package/packages/hooks/src/shims.d.ts +3 -0
  377. package/packages/hooks/src/trajectory-hooks.ts +251 -0
  378. package/packages/hooks/src/types.ts +342 -0
  379. package/packages/hooks/tsconfig.json +21 -0
  380. package/packages/hooks/vitest.config.ts +9 -0
  381. package/packages/mcp/dist/bin.d.ts.map +1 -0
  382. package/packages/mcp/dist/bin.js.map +1 -0
  383. package/packages/mcp/dist/client.d.ts +9 -15
  384. package/packages/mcp/dist/client.d.ts.map +1 -0
  385. package/packages/mcp/dist/client.js +42 -74
  386. package/packages/mcp/dist/client.js.map +1 -0
  387. package/packages/mcp/dist/cloud.d.ts.map +1 -0
  388. package/packages/mcp/dist/cloud.js.map +1 -0
  389. package/packages/mcp/dist/errors.d.ts.map +1 -0
  390. package/packages/mcp/dist/errors.js.map +1 -0
  391. package/packages/mcp/dist/file-transport.d.ts.map +1 -0
  392. package/packages/mcp/dist/file-transport.js.map +1 -0
  393. package/packages/mcp/dist/hybrid-client.d.ts.map +1 -0
  394. package/packages/mcp/dist/hybrid-client.js.map +1 -0
  395. package/packages/mcp/dist/index.d.ts.map +1 -0
  396. package/packages/mcp/dist/index.js.map +1 -0
  397. package/packages/mcp/dist/install-cli.d.ts.map +1 -0
  398. package/packages/mcp/dist/install-cli.js.map +1 -0
  399. package/packages/mcp/dist/install.d.ts.map +1 -0
  400. package/packages/mcp/dist/install.js.map +1 -0
  401. package/packages/mcp/dist/prompts/index.d.ts.map +1 -0
  402. package/packages/mcp/dist/prompts/index.js.map +1 -0
  403. package/packages/mcp/dist/prompts/protocol.d.ts.map +1 -0
  404. package/packages/mcp/dist/prompts/protocol.js.map +1 -0
  405. package/packages/mcp/dist/resources/agents.d.ts.map +1 -0
  406. package/packages/mcp/dist/resources/agents.js.map +1 -0
  407. package/packages/mcp/dist/resources/inbox.d.ts.map +1 -0
  408. package/packages/mcp/dist/resources/inbox.js.map +1 -0
  409. package/packages/mcp/dist/resources/index.d.ts.map +1 -0
  410. package/packages/mcp/dist/resources/index.js.map +1 -0
  411. package/packages/mcp/dist/resources/project.d.ts.map +1 -0
  412. package/packages/mcp/dist/resources/project.js.map +1 -0
  413. package/packages/mcp/dist/server.d.ts.map +1 -0
  414. package/packages/mcp/dist/server.js.map +1 -0
  415. package/packages/mcp/dist/simple.d.ts +2 -5
  416. package/packages/mcp/dist/simple.d.ts.map +1 -0
  417. package/packages/mcp/dist/simple.js.map +1 -0
  418. package/packages/mcp/dist/tools/index.d.ts.map +1 -0
  419. package/packages/mcp/dist/tools/index.js.map +1 -0
  420. package/packages/mcp/dist/tools/relay-broadcast.d.ts.map +1 -0
  421. package/packages/mcp/dist/tools/relay-broadcast.js.map +1 -0
  422. package/packages/mcp/dist/tools/relay-channel.d.ts.map +1 -0
  423. package/packages/mcp/dist/tools/relay-channel.js.map +1 -0
  424. package/packages/mcp/dist/tools/relay-connected.d.ts.map +1 -0
  425. package/packages/mcp/dist/tools/relay-connected.js.map +1 -0
  426. package/packages/mcp/dist/tools/relay-consensus.d.ts.map +1 -0
  427. package/packages/mcp/dist/tools/relay-consensus.js.map +1 -0
  428. package/packages/mcp/dist/tools/relay-continuity.d.ts.map +1 -0
  429. package/packages/mcp/dist/tools/relay-continuity.js.map +1 -0
  430. package/packages/mcp/dist/tools/relay-health.d.ts.map +1 -0
  431. package/packages/mcp/dist/tools/relay-health.js.map +1 -0
  432. package/packages/mcp/dist/tools/relay-inbox.d.ts.map +1 -0
  433. package/packages/mcp/dist/tools/relay-inbox.js.map +1 -0
  434. package/packages/mcp/dist/tools/relay-logs.d.ts.map +1 -0
  435. package/packages/mcp/dist/tools/relay-logs.js.map +1 -0
  436. package/packages/mcp/dist/tools/relay-metrics.d.ts.map +1 -0
  437. package/packages/mcp/dist/tools/relay-metrics.js.map +1 -0
  438. package/packages/mcp/dist/tools/relay-release.d.ts.map +1 -0
  439. package/packages/mcp/dist/tools/relay-release.js.map +1 -0
  440. package/packages/mcp/dist/tools/relay-remove-agent.d.ts.map +1 -0
  441. package/packages/mcp/dist/tools/relay-remove-agent.js.map +1 -0
  442. package/packages/mcp/dist/tools/relay-send.d.ts.map +1 -0
  443. package/packages/mcp/dist/tools/relay-send.js +4 -2
  444. package/packages/mcp/dist/tools/relay-send.js.map +1 -0
  445. package/packages/mcp/dist/tools/relay-shadow.d.ts.map +1 -0
  446. package/packages/mcp/dist/tools/relay-shadow.js.map +1 -0
  447. package/packages/mcp/dist/tools/relay-spawn.d.ts.map +1 -0
  448. package/packages/mcp/dist/tools/relay-spawn.js.map +1 -0
  449. package/packages/mcp/dist/tools/relay-status.d.ts.map +1 -0
  450. package/packages/mcp/dist/tools/relay-status.js.map +1 -0
  451. package/packages/mcp/dist/tools/relay-subscribe.d.ts.map +1 -0
  452. package/packages/mcp/dist/tools/relay-subscribe.js.map +1 -0
  453. package/packages/mcp/dist/tools/relay-who.d.ts.map +1 -0
  454. package/packages/mcp/dist/tools/relay-who.js.map +1 -0
  455. package/packages/mcp/package.json +3 -3
  456. package/packages/mcp/src/bin.ts +149 -0
  457. package/packages/mcp/src/client.ts +400 -0
  458. package/packages/mcp/src/cloud.ts +523 -0
  459. package/packages/mcp/src/errors.ts +54 -0
  460. package/packages/mcp/src/file-transport.ts +268 -0
  461. package/packages/mcp/src/hybrid-client.ts +209 -0
  462. package/packages/mcp/src/index.ts +122 -0
  463. package/packages/mcp/src/install-cli.ts +210 -0
  464. package/packages/mcp/src/install.ts +745 -0
  465. package/packages/mcp/src/prompts/index.ts +1 -0
  466. package/packages/mcp/src/prompts/protocol.ts +164 -0
  467. package/packages/mcp/src/resources/agents.ts +21 -0
  468. package/packages/mcp/src/resources/inbox.ts +21 -0
  469. package/packages/mcp/src/resources/index.ts +3 -0
  470. package/packages/mcp/src/resources/project.ts +29 -0
  471. package/packages/mcp/src/server.ts +431 -0
  472. package/packages/mcp/src/simple.ts +214 -0
  473. package/packages/mcp/src/tools/index.ts +133 -0
  474. package/packages/mcp/src/tools/relay-broadcast.ts +32 -0
  475. package/packages/mcp/src/tools/relay-channel.ts +93 -0
  476. package/packages/mcp/src/tools/relay-connected.ts +52 -0
  477. package/packages/mcp/src/tools/relay-consensus.ts +92 -0
  478. package/packages/mcp/src/tools/relay-continuity.ts +127 -0
  479. package/packages/mcp/src/tools/relay-health.ts +148 -0
  480. package/packages/mcp/src/tools/relay-inbox.ts +70 -0
  481. package/packages/mcp/src/tools/relay-logs.ts +106 -0
  482. package/packages/mcp/src/tools/relay-metrics.ts +140 -0
  483. package/packages/mcp/src/tools/relay-release.ts +54 -0
  484. package/packages/mcp/src/tools/relay-remove-agent.ts +58 -0
  485. package/packages/mcp/src/tools/relay-send.ts +84 -0
  486. package/packages/mcp/src/tools/relay-shadow.ts +67 -0
  487. package/packages/mcp/src/tools/relay-spawn.ts +87 -0
  488. package/packages/mcp/src/tools/relay-status.ts +57 -0
  489. package/packages/mcp/src/tools/relay-subscribe.ts +61 -0
  490. package/packages/mcp/src/tools/relay-who.ts +59 -0
  491. package/packages/mcp/tests/client.test.ts +476 -0
  492. package/packages/mcp/tests/discover.test.ts +195 -0
  493. package/packages/mcp/tests/install.test.ts +123 -0
  494. package/packages/mcp/tests/prompts.test.ts +12 -0
  495. package/packages/mcp/tests/resources.test.ts +53 -0
  496. package/packages/mcp/tests/tools.test.ts +1242 -0
  497. package/packages/mcp/tsconfig.json +22 -0
  498. package/packages/mcp/vitest.config.ts +9 -0
  499. package/packages/memory/dist/adapters/index.d.ts.map +1 -0
  500. package/packages/memory/dist/adapters/index.js.map +1 -0
  501. package/packages/memory/dist/adapters/inmemory.d.ts.map +1 -0
  502. package/packages/memory/dist/adapters/inmemory.js.map +1 -0
  503. package/packages/memory/dist/adapters/supermemory.d.ts.map +1 -0
  504. package/packages/memory/dist/adapters/supermemory.js.map +1 -0
  505. package/packages/memory/dist/context-compaction.d.ts.map +1 -0
  506. package/packages/memory/dist/context-compaction.js.map +1 -0
  507. package/packages/memory/dist/factory.d.ts.map +1 -0
  508. package/packages/memory/dist/factory.js.map +1 -0
  509. package/packages/memory/dist/index.d.ts.map +1 -0
  510. package/packages/memory/dist/index.js.map +1 -0
  511. package/packages/memory/dist/memory-hooks.d.ts.map +1 -0
  512. package/packages/memory/dist/memory-hooks.js.map +1 -0
  513. package/packages/memory/dist/service.d.ts.map +1 -0
  514. package/packages/memory/dist/service.js.map +1 -0
  515. package/packages/memory/dist/types.d.ts.map +1 -0
  516. package/packages/memory/dist/types.js.map +1 -0
  517. package/packages/memory/package.json +2 -2
  518. package/packages/memory/src/adapters/index.ts +8 -0
  519. package/packages/memory/src/adapters/inmemory.ts +265 -0
  520. package/packages/memory/src/adapters/supermemory.ts +449 -0
  521. package/packages/memory/src/context-compaction.test.ts +660 -0
  522. package/packages/memory/src/context-compaction.ts +612 -0
  523. package/packages/memory/src/factory.ts +170 -0
  524. package/packages/memory/src/index.ts +33 -0
  525. package/packages/memory/src/memory-hooks.ts +410 -0
  526. package/packages/memory/src/service.ts +194 -0
  527. package/packages/memory/src/types.ts +211 -0
  528. package/packages/memory/tsconfig.json +21 -0
  529. package/packages/memory/vitest.config.ts +9 -0
  530. package/packages/policy/dist/agent-policy.d.ts.map +1 -0
  531. package/packages/policy/dist/agent-policy.js.map +1 -0
  532. package/packages/policy/dist/cloud-policy-fetcher.d.ts.map +1 -0
  533. package/packages/policy/dist/cloud-policy-fetcher.js.map +1 -0
  534. package/packages/policy/dist/index.d.ts.map +1 -0
  535. package/packages/policy/dist/index.js.map +1 -0
  536. package/packages/policy/package.json +2 -2
  537. package/packages/policy/src/agent-policy.ts +866 -0
  538. package/packages/policy/src/cloud-policy-fetcher.ts +78 -0
  539. package/packages/policy/src/index.ts +21 -0
  540. package/packages/policy/tsconfig.json +21 -0
  541. package/packages/policy/vitest.config.ts +9 -0
  542. package/packages/protocol/dist/channels.d.ts.map +1 -0
  543. package/packages/protocol/dist/channels.js.map +1 -0
  544. package/packages/protocol/dist/framing.d.ts.map +1 -0
  545. package/packages/protocol/dist/framing.js.map +1 -0
  546. package/packages/protocol/dist/id-generator.d.ts.map +1 -0
  547. package/packages/protocol/dist/id-generator.js.map +1 -0
  548. package/packages/protocol/dist/index.d.ts.map +1 -0
  549. package/packages/protocol/dist/index.js.map +1 -0
  550. package/packages/protocol/dist/relay-pty-schemas.d.ts +70 -2
  551. package/packages/protocol/dist/relay-pty-schemas.d.ts.map +1 -0
  552. package/packages/protocol/dist/relay-pty-schemas.js.map +1 -0
  553. package/packages/protocol/dist/types.d.ts +8 -0
  554. package/packages/protocol/dist/types.d.ts.map +1 -0
  555. package/packages/protocol/dist/types.js.map +1 -0
  556. package/packages/protocol/package.json +1 -1
  557. package/packages/protocol/src/channels.test.ts +330 -0
  558. package/packages/protocol/src/channels.ts +270 -0
  559. package/packages/protocol/src/framing.test.ts +164 -0
  560. package/packages/protocol/src/framing.ts +242 -0
  561. package/packages/protocol/src/id-generator.ts +69 -0
  562. package/packages/protocol/src/index.ts +4 -0
  563. package/packages/protocol/src/relay-pty-schemas.ts +400 -0
  564. package/packages/protocol/src/types.test.ts +271 -0
  565. package/packages/protocol/src/types.ts +846 -0
  566. package/packages/protocol/tsconfig.json +21 -0
  567. package/packages/protocol/vitest.config.ts +9 -0
  568. package/packages/resiliency/dist/cgroup-manager.d.ts.map +1 -0
  569. package/packages/resiliency/dist/cgroup-manager.js.map +1 -0
  570. package/packages/resiliency/dist/context-persistence.d.ts.map +1 -0
  571. package/packages/resiliency/dist/context-persistence.js.map +1 -0
  572. package/packages/resiliency/dist/crash-insights.d.ts.map +1 -0
  573. package/packages/resiliency/dist/crash-insights.js.map +1 -0
  574. package/packages/resiliency/dist/gossip-health.d.ts.map +1 -0
  575. package/packages/resiliency/dist/gossip-health.js.map +1 -0
  576. package/packages/resiliency/dist/health-monitor.d.ts.map +1 -0
  577. package/packages/resiliency/dist/health-monitor.js.map +1 -0
  578. package/packages/resiliency/dist/index.d.ts.map +1 -0
  579. package/packages/resiliency/dist/index.js.map +1 -0
  580. package/packages/resiliency/dist/leader-watchdog.d.ts.map +1 -0
  581. package/packages/resiliency/dist/leader-watchdog.js.map +1 -0
  582. package/packages/resiliency/dist/logger.d.ts.map +1 -0
  583. package/packages/resiliency/dist/logger.js.map +1 -0
  584. package/packages/resiliency/dist/memory-monitor.d.ts.map +1 -0
  585. package/packages/resiliency/dist/memory-monitor.js.map +1 -0
  586. package/packages/resiliency/dist/metrics.d.ts.map +1 -0
  587. package/packages/resiliency/dist/metrics.js.map +1 -0
  588. package/packages/resiliency/dist/provider-context.d.ts.map +1 -0
  589. package/packages/resiliency/dist/provider-context.js.map +1 -0
  590. package/packages/resiliency/dist/stateless-lead.d.ts.map +1 -0
  591. package/packages/resiliency/dist/stateless-lead.js.map +1 -0
  592. package/packages/resiliency/dist/supervisor.d.ts.map +1 -0
  593. package/packages/resiliency/dist/supervisor.js.map +1 -0
  594. package/packages/resiliency/package.json +1 -1
  595. package/packages/resiliency/src/cgroup-manager.ts +468 -0
  596. package/packages/resiliency/src/context-persistence.ts +538 -0
  597. package/packages/resiliency/src/crash-insights.test.ts +620 -0
  598. package/packages/resiliency/src/crash-insights.ts +660 -0
  599. package/packages/resiliency/src/gossip-health.ts +333 -0
  600. package/packages/resiliency/src/health-monitor.ts +371 -0
  601. package/packages/resiliency/src/index.ts +157 -0
  602. package/packages/resiliency/src/leader-watchdog.ts +260 -0
  603. package/packages/resiliency/src/logger.ts +320 -0
  604. package/packages/resiliency/src/memory-monitor.test.ts +637 -0
  605. package/packages/resiliency/src/memory-monitor.ts +740 -0
  606. package/packages/resiliency/src/metrics.ts +311 -0
  607. package/packages/resiliency/src/provider-context.ts +452 -0
  608. package/packages/resiliency/src/stateless-lead.ts +408 -0
  609. package/packages/resiliency/src/supervisor.ts +578 -0
  610. package/packages/resiliency/tsconfig.json +21 -0
  611. package/packages/resiliency/vitest.config.ts +9 -0
  612. package/packages/sdk/dist/client.d.ts.map +1 -0
  613. package/packages/sdk/dist/client.js.map +1 -0
  614. package/packages/sdk/dist/index.d.ts.map +1 -0
  615. package/packages/sdk/dist/index.js.map +1 -0
  616. package/packages/sdk/dist/logs.d.ts.map +1 -0
  617. package/packages/sdk/dist/logs.js.map +1 -0
  618. package/packages/sdk/dist/protocol/index.d.ts.map +1 -0
  619. package/packages/sdk/dist/protocol/index.js.map +1 -0
  620. package/packages/sdk/dist/standalone.d.ts.map +1 -0
  621. package/packages/sdk/dist/standalone.js.map +1 -0
  622. package/packages/sdk/examples/SWARM_CAPABILITIES.md +498 -0
  623. package/packages/sdk/examples/SWARM_PATTERNS.md +541 -0
  624. package/packages/sdk/package.json +2 -2
  625. package/packages/sdk/src/client.test.ts +568 -0
  626. package/packages/sdk/src/client.ts +1418 -0
  627. package/packages/sdk/src/index.ts +103 -0
  628. package/packages/sdk/src/logs.test.ts +98 -0
  629. package/packages/sdk/src/logs.ts +126 -0
  630. package/packages/sdk/src/protocol/framing.test.ts +164 -0
  631. package/packages/sdk/src/protocol/index.ts +8 -0
  632. package/packages/sdk/src/standalone.ts +176 -0
  633. package/packages/sdk/tsconfig.json +22 -0
  634. package/packages/sdk/vitest.config.ts +9 -0
  635. package/packages/spawner/.trajectories/index.json +5 -0
  636. package/packages/spawner/dist/index.d.ts.map +1 -0
  637. package/packages/spawner/dist/index.js.map +1 -0
  638. package/packages/spawner/dist/types.d.ts.map +1 -0
  639. package/packages/spawner/dist/types.js.map +1 -0
  640. package/packages/spawner/package.json +1 -1
  641. package/packages/spawner/src/index.ts +8 -0
  642. package/packages/spawner/src/types.test.ts +385 -0
  643. package/packages/spawner/src/types.ts +228 -0
  644. package/packages/spawner/tsconfig.json +19 -0
  645. package/packages/spawner/vitest.config.ts +9 -0
  646. package/packages/state/dist/agent-state.d.ts.map +1 -0
  647. package/packages/state/dist/agent-state.js.map +1 -0
  648. package/packages/state/dist/index.d.ts.map +1 -0
  649. package/packages/state/dist/index.js.map +1 -0
  650. package/packages/state/package.json +1 -1
  651. package/packages/state/src/agent-state.test.ts +335 -0
  652. package/packages/state/src/agent-state.ts +153 -0
  653. package/packages/state/src/index.ts +12 -0
  654. package/packages/state/tsconfig.json +21 -0
  655. package/packages/state/vitest.config.ts +9 -0
  656. package/packages/storage/dist/adapter.d.ts +28 -1
  657. package/packages/storage/dist/adapter.d.ts.map +1 -0
  658. package/packages/storage/dist/adapter.js +104 -10
  659. package/packages/storage/dist/adapter.js.map +1 -0
  660. package/packages/storage/dist/batched-sqlite-adapter.d.ts.map +1 -0
  661. package/packages/storage/dist/batched-sqlite-adapter.js.map +1 -0
  662. package/packages/storage/dist/dead-letter-queue.d.ts.map +1 -0
  663. package/packages/storage/dist/dead-letter-queue.js.map +1 -0
  664. package/packages/storage/dist/dlq-adapter.d.ts.map +1 -0
  665. package/packages/storage/dist/dlq-adapter.js.map +1 -0
  666. package/packages/storage/dist/index.d.ts +1 -0
  667. package/packages/storage/dist/index.d.ts.map +1 -0
  668. package/packages/storage/dist/index.js +1 -0
  669. package/packages/storage/dist/index.js.map +1 -0
  670. package/packages/storage/dist/jsonl-adapter.d.ts +77 -0
  671. package/packages/storage/dist/jsonl-adapter.d.ts.map +1 -0
  672. package/packages/storage/dist/jsonl-adapter.js +505 -0
  673. package/packages/storage/dist/jsonl-adapter.js.map +1 -0
  674. package/packages/storage/dist/sqlite-adapter.d.ts +6 -1
  675. package/packages/storage/dist/sqlite-adapter.d.ts.map +1 -0
  676. package/packages/storage/dist/sqlite-adapter.js +47 -0
  677. package/packages/storage/dist/sqlite-adapter.js.map +1 -0
  678. package/packages/storage/package.json +2 -2
  679. package/packages/storage/src/adapter.ts +438 -0
  680. package/packages/storage/src/batched-sqlite-adapter.test.ts +240 -0
  681. package/packages/storage/src/batched-sqlite-adapter.ts +239 -0
  682. package/packages/storage/src/dead-letter-queue.ts +643 -0
  683. package/packages/storage/src/dlq-adapter.test.ts +492 -0
  684. package/packages/storage/src/dlq-adapter.ts +954 -0
  685. package/packages/storage/src/index.ts +6 -0
  686. package/packages/storage/src/jsonl-adapter.test.ts +200 -0
  687. package/packages/storage/src/jsonl-adapter.ts +618 -0
  688. package/packages/storage/src/memory-adapter.test.ts +36 -0
  689. package/packages/storage/src/sqlite-adapter.test.ts +562 -0
  690. package/packages/storage/src/sqlite-adapter.ts +1058 -0
  691. package/packages/storage/tsconfig.json +21 -0
  692. package/packages/storage/vitest.config.ts +9 -0
  693. package/packages/telemetry/dist/client.d.ts.map +1 -0
  694. package/packages/telemetry/dist/client.js.map +1 -0
  695. package/packages/telemetry/dist/config.d.ts.map +1 -0
  696. package/packages/telemetry/dist/config.js.map +1 -0
  697. package/packages/telemetry/dist/events.d.ts.map +1 -0
  698. package/packages/telemetry/dist/events.js.map +1 -0
  699. package/packages/telemetry/dist/index.d.ts.map +1 -0
  700. package/packages/telemetry/dist/index.js.map +1 -0
  701. package/packages/telemetry/dist/machine-id.d.ts.map +1 -0
  702. package/packages/telemetry/dist/machine-id.js.map +1 -0
  703. package/packages/telemetry/dist/posthog-config.d.ts.map +1 -0
  704. package/packages/telemetry/dist/posthog-config.js.map +1 -0
  705. package/packages/telemetry/package.json +1 -1
  706. package/packages/telemetry/src/client.ts +158 -0
  707. package/packages/telemetry/src/config.ts +110 -0
  708. package/packages/telemetry/src/events.ts +137 -0
  709. package/packages/telemetry/src/index.ts +46 -0
  710. package/packages/telemetry/src/machine-id.ts +63 -0
  711. package/packages/telemetry/src/posthog-config.ts +39 -0
  712. package/packages/telemetry/tsconfig.json +21 -0
  713. package/packages/trajectory/dist/index.d.ts.map +1 -0
  714. package/packages/trajectory/dist/index.js.map +1 -0
  715. package/packages/trajectory/dist/integration.d.ts.map +1 -0
  716. package/packages/trajectory/dist/integration.js.map +1 -0
  717. package/packages/trajectory/package.json +2 -2
  718. package/packages/trajectory/src/index.ts +1 -0
  719. package/packages/trajectory/src/integration.ts +1268 -0
  720. package/packages/trajectory/tsconfig.json +21 -0
  721. package/packages/trajectory/vitest.config.ts +9 -0
  722. package/packages/user-directory/dist/index.d.ts.map +1 -0
  723. package/packages/user-directory/dist/index.js.map +1 -0
  724. package/packages/user-directory/dist/user-directory.d.ts.map +1 -0
  725. package/packages/user-directory/dist/user-directory.js.map +1 -0
  726. package/packages/user-directory/package.json +2 -2
  727. package/packages/user-directory/src/index.ts +12 -0
  728. package/packages/user-directory/src/user-directory.ts +393 -0
  729. package/packages/user-directory/tsconfig.json +21 -0
  730. package/packages/user-directory/vitest.config.ts +9 -0
  731. package/packages/utils/dist/cjs/client-helpers.js +127 -0
  732. package/packages/utils/dist/cjs/command-resolver.js +89 -0
  733. package/packages/utils/dist/cjs/error-tracking.js +106 -0
  734. package/packages/utils/dist/cjs/git-remote.js +120 -0
  735. package/packages/utils/dist/cjs/index.js +40 -0
  736. package/packages/utils/dist/cjs/logger.js +105 -0
  737. package/packages/utils/dist/cjs/model-mapping.js +54 -0
  738. package/packages/utils/dist/cjs/name-generator.js +179 -0
  739. package/packages/utils/dist/cjs/package.json +3 -0
  740. package/packages/utils/dist/cjs/precompiled-patterns.js +271 -0
  741. package/packages/utils/dist/cjs/relay-pty-path.js +143 -0
  742. package/packages/utils/dist/cjs/update-checker.js +185 -0
  743. package/packages/utils/dist/client-helpers.d.ts +73 -0
  744. package/packages/utils/dist/client-helpers.d.ts.map +1 -0
  745. package/packages/utils/dist/client-helpers.js +130 -0
  746. package/packages/utils/dist/client-helpers.js.map +1 -0
  747. package/packages/utils/dist/command-resolver.d.ts.map +1 -0
  748. package/packages/utils/dist/command-resolver.js.map +1 -0
  749. package/packages/utils/dist/error-tracking.d.ts.map +1 -0
  750. package/packages/utils/dist/error-tracking.js.map +1 -0
  751. package/packages/utils/dist/git-remote.d.ts.map +1 -0
  752. package/packages/utils/dist/git-remote.js.map +1 -0
  753. package/packages/utils/dist/index.d.ts +1 -0
  754. package/packages/utils/dist/index.d.ts.map +1 -0
  755. package/packages/utils/dist/index.js +1 -0
  756. package/packages/utils/dist/index.js.map +1 -0
  757. package/packages/utils/dist/logger.d.ts.map +1 -0
  758. package/packages/utils/dist/logger.js.map +1 -0
  759. package/packages/utils/dist/model-mapping.d.ts.map +1 -0
  760. package/packages/utils/dist/model-mapping.js.map +1 -0
  761. package/packages/utils/dist/name-generator.d.ts.map +1 -0
  762. package/packages/utils/dist/name-generator.js.map +1 -0
  763. package/packages/utils/dist/precompiled-patterns.d.ts.map +1 -0
  764. package/packages/utils/dist/precompiled-patterns.js.map +1 -0
  765. package/packages/utils/dist/relay-pty-path.d.ts +11 -5
  766. package/packages/utils/dist/relay-pty-path.d.ts.map +1 -0
  767. package/packages/utils/dist/relay-pty-path.js +60 -5
  768. package/packages/utils/dist/relay-pty-path.js.map +1 -0
  769. package/packages/utils/dist/update-checker.d.ts.map +1 -0
  770. package/packages/utils/dist/update-checker.js.map +1 -0
  771. package/packages/utils/package.json +37 -14
  772. package/packages/utils/scripts/build-cjs.mjs +24 -0
  773. package/packages/utils/src/client-helpers.ts +221 -0
  774. package/packages/utils/src/command-resolver.ts +82 -0
  775. package/packages/utils/src/error-tracking.ts +189 -0
  776. package/packages/utils/src/git-remote.ts +143 -0
  777. package/packages/utils/src/index.ts +10 -0
  778. package/packages/utils/src/logger.ts +107 -0
  779. package/packages/utils/src/model-mapping.test.ts +122 -0
  780. package/packages/utils/src/model-mapping.ts +58 -0
  781. package/packages/utils/src/name-generator.test.ts +259 -0
  782. package/packages/utils/src/name-generator.ts +56 -0
  783. package/packages/utils/src/precompiled-patterns.test.ts +452 -0
  784. package/packages/utils/src/precompiled-patterns.ts +395 -0
  785. package/packages/utils/src/relay-pty-path.ts +196 -0
  786. package/packages/utils/src/update-checker.test.ts +260 -0
  787. package/packages/utils/src/update-checker.ts +211 -0
  788. package/packages/utils/tsconfig.json +21 -0
  789. package/packages/utils/vitest.config.ts +9 -0
  790. package/packages/wrapper/dist/__fixtures__/claude-outputs.d.ts.map +1 -0
  791. package/packages/wrapper/dist/__fixtures__/claude-outputs.js.map +1 -0
  792. package/packages/wrapper/dist/__fixtures__/codex-outputs.d.ts.map +1 -0
  793. package/packages/wrapper/dist/__fixtures__/codex-outputs.js.map +1 -0
  794. package/packages/wrapper/dist/__fixtures__/gemini-outputs.d.ts.map +1 -0
  795. package/packages/wrapper/dist/__fixtures__/gemini-outputs.js.map +1 -0
  796. package/packages/wrapper/dist/__fixtures__/index.d.ts.map +1 -0
  797. package/packages/wrapper/dist/__fixtures__/index.js.map +1 -0
  798. package/packages/wrapper/dist/auth-detection.d.ts.map +1 -0
  799. package/packages/wrapper/dist/auth-detection.js.map +1 -0
  800. package/packages/wrapper/dist/base-wrapper.d.ts.map +1 -0
  801. package/packages/wrapper/dist/base-wrapper.js.map +1 -0
  802. package/packages/wrapper/dist/client.d.ts.map +1 -0
  803. package/packages/wrapper/dist/client.js.map +1 -0
  804. package/packages/wrapper/dist/id-generator.d.ts.map +1 -0
  805. package/packages/wrapper/dist/id-generator.js.map +1 -0
  806. package/packages/wrapper/dist/idle-detector.d.ts.map +1 -0
  807. package/packages/wrapper/dist/idle-detector.js.map +1 -0
  808. package/packages/wrapper/dist/inbox.d.ts.map +1 -0
  809. package/packages/wrapper/dist/inbox.js.map +1 -0
  810. package/packages/wrapper/dist/index.d.ts.map +1 -0
  811. package/packages/wrapper/dist/index.js.map +1 -0
  812. package/packages/wrapper/dist/parser.d.ts.map +1 -0
  813. package/packages/wrapper/dist/parser.js.map +1 -0
  814. package/packages/wrapper/dist/prompt-composer.d.ts.map +1 -0
  815. package/packages/wrapper/dist/prompt-composer.js.map +1 -0
  816. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts +10 -0
  817. package/packages/wrapper/dist/relay-pty-orchestrator.d.ts.map +1 -0
  818. package/packages/wrapper/dist/relay-pty-orchestrator.js +69 -0
  819. package/packages/wrapper/dist/relay-pty-orchestrator.js.map +1 -0
  820. package/packages/wrapper/dist/shared.d.ts.map +1 -0
  821. package/packages/wrapper/dist/shared.js.map +1 -0
  822. package/packages/wrapper/dist/stuck-detector.d.ts.map +1 -0
  823. package/packages/wrapper/dist/stuck-detector.js.map +1 -0
  824. package/packages/wrapper/dist/tmux-resolver.d.ts.map +1 -0
  825. package/packages/wrapper/dist/tmux-resolver.js.map +1 -0
  826. package/packages/wrapper/dist/tmux-wrapper.d.ts.map +1 -0
  827. package/packages/wrapper/dist/tmux-wrapper.js.map +1 -0
  828. package/packages/wrapper/dist/trajectory-integration.d.ts.map +1 -0
  829. package/packages/wrapper/dist/trajectory-integration.js.map +1 -0
  830. package/packages/wrapper/dist/wrapper-types.d.ts.map +1 -0
  831. package/packages/wrapper/dist/wrapper-types.js.map +1 -0
  832. package/packages/wrapper/package.json +6 -9
  833. package/packages/wrapper/src/__fixtures__/claude-outputs.ts +471 -0
  834. package/packages/wrapper/src/__fixtures__/codex-outputs.ts +99 -0
  835. package/packages/wrapper/src/__fixtures__/gemini-outputs.ts +151 -0
  836. package/packages/wrapper/src/__fixtures__/index.ts +47 -0
  837. package/packages/wrapper/src/auth-detection.ts +244 -0
  838. package/packages/wrapper/src/base-wrapper.test.ts +589 -0
  839. package/packages/wrapper/src/base-wrapper.ts +810 -0
  840. package/packages/wrapper/src/client.test.ts +262 -0
  841. package/packages/wrapper/src/client.ts +984 -0
  842. package/packages/wrapper/src/id-generator.test.ts +71 -0
  843. package/packages/wrapper/src/id-generator.ts +69 -0
  844. package/packages/wrapper/src/idle-detector.test.ts +418 -0
  845. package/packages/wrapper/src/idle-detector.ts +384 -0
  846. package/packages/wrapper/src/inbox.test.ts +233 -0
  847. package/packages/wrapper/src/inbox.ts +89 -0
  848. package/packages/wrapper/src/index.ts +170 -0
  849. package/packages/wrapper/src/parser.regression.test.ts +251 -0
  850. package/packages/wrapper/src/parser.test.ts +1359 -0
  851. package/packages/wrapper/src/parser.ts +1477 -0
  852. package/packages/wrapper/src/prompt-composer.test.ts +219 -0
  853. package/packages/wrapper/src/prompt-composer.ts +231 -0
  854. package/packages/wrapper/src/relay-pty-orchestrator.test.ts +1204 -0
  855. package/packages/wrapper/src/relay-pty-orchestrator.ts +2626 -0
  856. package/packages/wrapper/src/shared.test.ts +322 -0
  857. package/packages/wrapper/src/shared.ts +495 -0
  858. package/packages/wrapper/src/stuck-detector.test.ts +303 -0
  859. package/packages/wrapper/src/stuck-detector.ts +511 -0
  860. package/packages/wrapper/src/tmux-resolver.test.ts +104 -0
  861. package/packages/wrapper/src/tmux-resolver.ts +207 -0
  862. package/packages/wrapper/src/tmux-wrapper.test.ts +316 -0
  863. package/packages/wrapper/src/tmux-wrapper.ts +2095 -0
  864. package/packages/wrapper/src/trajectory-detection.test.ts +151 -0
  865. package/packages/wrapper/src/trajectory-integration.ts +1261 -0
  866. package/packages/wrapper/src/wrapper-types.ts +45 -0
  867. package/packages/wrapper/tsconfig.json +19 -0
  868. package/packages/wrapper/vitest.config.ts +9 -0
  869. package/scripts/build-cjs.mjs +23 -0
  870. package/scripts/postinstall.js +132 -0
  871. package/.cursor/mcp.json +0 -11
  872. package/.gitattributes +0 -3
  873. package/.gitleaks.toml +0 -26
  874. package/.mcp.json +0 -11
  875. package/.nvmrc +0 -1
  876. package/ARCHITECTURE.md +0 -1245
  877. package/CHANGELOG.md +0 -231
  878. package/TESTING.md +0 -278
  879. package/TRAIL_GIT_AUTH_FIX.md +0 -113
  880. package/scripts/demos/README.md +0 -79
  881. package/scripts/demos/server-capacity.sh +0 -69
  882. package/scripts/demos/sprint-planning.sh +0 -73
  883. package/scripts/hooks/install.sh +0 -16
  884. package/scripts/hooks/pre-commit +0 -60
  885. package/scripts/post-publish-verify/README.md +0 -80
  886. package/scripts/post-publish-verify/run-verify.sh +0 -127
  887. package/scripts/post-publish-verify/verify-install.sh +0 -249
  888. package/scripts/stress-test-orchestrator-integration.mts +0 -1366
  889. package/scripts/stress-test-orchestrator.mjs +0 -584
  890. package/scripts/stress-test-relay-pty.sh +0 -452
  891. package/scripts/test-interactive-terminal.sh +0 -248
  892. package/specs/PRIMITIVES_ROADMAP.md +0 -2154
  893. package/tests/benchmarks/protocol.bench.ts +0 -310
  894. package/turbo.json +0 -37
@@ -0,0 +1,1376 @@
1
+ /**
2
+ * Daemon Orchestrator
3
+ *
4
+ * Manages multiple workspace daemons and provides a unified API for the dashboard.
5
+ * This is the top-level service that runs by default, handling workspace switching
6
+ * and agent management across all connected repositories.
7
+ */
8
+
9
+ import * as http from 'http';
10
+ import * as path from 'path';
11
+ import * as fs from 'fs';
12
+ import { EventEmitter } from 'events';
13
+ import { WebSocketServer, WebSocket } from 'ws';
14
+ import {
15
+ createLogger,
16
+ metrics,
17
+ getSupervisor,
18
+ getMemoryMonitor,
19
+ formatBytes,
20
+ type MemoryAlert,
21
+ type MemorySnapshot,
22
+ } from '@agent-relay/resiliency';
23
+ import { Daemon } from './server.js';
24
+ import { AgentSpawner } from '@agent-relay/bridge';
25
+ import { getProjectPaths } from '@agent-relay/config';
26
+ import { getCloudSync, createCloudPersistenceHandler } from './cloud-sync.js';
27
+ import type {
28
+ Workspace,
29
+ Agent,
30
+ DaemonEvent,
31
+ UserSession,
32
+ ProviderType,
33
+ AddWorkspaceRequest,
34
+ SpawnAgentRequest,
35
+ } from './types.js';
36
+
37
+ const logger = createLogger('orchestrator');
38
+
39
+ function generateId(): string {
40
+ return Math.random().toString(36).substring(2, 15);
41
+ }
42
+
43
+ export interface OrchestratorConfig {
44
+ /** Port for HTTP/WebSocket API */
45
+ port: number;
46
+ /** Host to bind to */
47
+ host: string;
48
+ /** Data directory for persistence */
49
+ dataDir: string;
50
+ /** Auto-start daemons for workspaces */
51
+ autoStartDaemons: boolean;
52
+ }
53
+
54
+ /**
55
+ * Determine the default host binding.
56
+ * - In cloud environments, bind to '::' for IPv6+IPv4 dual-stack (required for Fly.io 6PN)
57
+ * - Locally, bind to localhost for security
58
+ * - Can be overridden with AGENT_RELAY_API_HOST env var
59
+ */
60
+ function getDefaultHost(): string {
61
+ // Explicit override
62
+ if (process.env.AGENT_RELAY_API_HOST) {
63
+ return process.env.AGENT_RELAY_API_HOST;
64
+ }
65
+ // Cloud environment detection - bind to :: for IPv6 + IPv4 dual-stack
66
+ // Fly.io internal network uses IPv6 (fdaa:...), so 0.0.0.0 won't work
67
+ const isCloudEnvironment =
68
+ process.env.FLY_APP_NAME || // Fly.io
69
+ process.env.WORKSPACE_ID || // Agent Relay workspace
70
+ process.env.RELAY_WORKSPACE_ID || // Alternative workspace ID
71
+ process.env.RUNNING_IN_DOCKER === 'true'; // Docker container
72
+ return isCloudEnvironment ? '::' : 'localhost';
73
+ }
74
+
75
+ const DEFAULT_CONFIG: OrchestratorConfig = {
76
+ port: 3456,
77
+ host: getDefaultHost(),
78
+ dataDir: path.join(process.env.HOME || '', '.agent-relay', 'orchestrator'),
79
+ autoStartDaemons: true,
80
+ };
81
+
82
+ interface ManagedWorkspace extends Workspace {
83
+ daemon?: Daemon;
84
+ spawner?: AgentSpawner;
85
+ }
86
+
87
+ interface AgentHealthState {
88
+ key: string;
89
+ workspaceId: string;
90
+ agentName: string;
91
+ pid: number;
92
+ lastHeartbeatAt?: Date;
93
+ lastSampleAt?: Date;
94
+ lastRssBytes?: number;
95
+ lastCpuPercent?: number;
96
+ releasing?: boolean;
97
+ lastCpuAlertAt?: number;
98
+ }
99
+
100
+ const HEARTBEAT_INTERVAL_MS = 10_000;
101
+ const RESOURCE_ALERT_COOLDOWN_MS = 60_000;
102
+ const parsedCpuThreshold = parseFloat(process.env.AGENT_CPU_ALERT_THRESHOLD || '300');
103
+ const CPU_ALERT_THRESHOLD = Number.isFinite(parsedCpuThreshold) ? parsedCpuThreshold : 300;
104
+
105
+ export class Orchestrator extends EventEmitter {
106
+ private config: OrchestratorConfig;
107
+ private workspaces = new Map<string, ManagedWorkspace>();
108
+ private activeWorkspaceId?: string;
109
+ private server?: http.Server;
110
+ private wss?: WebSocketServer;
111
+ private sessions = new Map<WebSocket, UserSession>();
112
+ private supervisor = getSupervisor({
113
+ autoRestart: true,
114
+ maxRestarts: 5,
115
+ contextPersistence: { enabled: true, autoInjectOnRestart: true },
116
+ });
117
+ private workspacesFile: string;
118
+
119
+ // Track alive status for ping/pong keepalive
120
+ private clientAlive = new WeakMap<WebSocket, boolean>();
121
+ private pingInterval?: NodeJS.Timeout;
122
+ private heartbeatInterval?: NodeJS.Timeout;
123
+ private memoryMonitor = getMemoryMonitor({ checkIntervalMs: 10_000 });
124
+ private agentHealth = new Map<string, AgentHealthState>();
125
+
126
+ // Event handler references for cleanup
127
+ private memorySampleHandler?: (event: { name: string; snapshot: MemorySnapshot }) => void;
128
+ private memoryAlertHandler?: (alert: MemoryAlert) => void;
129
+
130
+ constructor(config: Partial<OrchestratorConfig> = {}) {
131
+ super();
132
+ this.config = { ...DEFAULT_CONFIG, ...config };
133
+ this.workspacesFile = path.join(this.config.dataDir, 'workspaces.json');
134
+
135
+ // Ensure data directory exists
136
+ if (!fs.existsSync(this.config.dataDir)) {
137
+ fs.mkdirSync(this.config.dataDir, { recursive: true });
138
+ }
139
+
140
+ // Load existing workspaces
141
+ this.loadWorkspaces();
142
+ }
143
+
144
+ /**
145
+ * Start the orchestrator
146
+ */
147
+ async start(): Promise<void> {
148
+ logger.info('Starting orchestrator', {
149
+ port: this.config.port,
150
+ host: this.config.host,
151
+ });
152
+
153
+ // Start supervisor
154
+ this.supervisor.start();
155
+
156
+ // Auto-start daemons for workspaces
157
+ if (this.config.autoStartDaemons) {
158
+ for (const [id, workspace] of this.workspaces) {
159
+ if (fs.existsSync(workspace.path)) {
160
+ await this.startWorkspaceDaemon(id);
161
+ }
162
+ }
163
+ }
164
+
165
+ // Start HTTP server
166
+ this.server = http.createServer((req, res) => this.handleRequest(req, res));
167
+
168
+ // Setup WebSocket
169
+ this.wss = new WebSocketServer({ server: this.server });
170
+ this.wss.on('connection', (ws, req) => this.handleWebSocket(ws, req));
171
+
172
+ // Setup ping/pong keepalive (30 second interval)
173
+ this.pingInterval = setInterval(() => {
174
+ this.wss?.clients.forEach((ws) => {
175
+ if (this.clientAlive.get(ws) === false) {
176
+ logger.info('WebSocket client unresponsive, closing');
177
+ ws.terminate();
178
+ return;
179
+ }
180
+ this.clientAlive.set(ws, false);
181
+ ws.ping();
182
+ });
183
+ }, 30000);
184
+
185
+ this.startHealthMonitoring();
186
+
187
+ return new Promise((resolve) => {
188
+ this.server!.listen(this.config.port, this.config.host, () => {
189
+ logger.info('Orchestrator started', {
190
+ url: `http://${this.config.host}:${this.config.port}`,
191
+ });
192
+ resolve();
193
+ });
194
+ });
195
+ }
196
+
197
+ /**
198
+ * Stop the orchestrator
199
+ */
200
+ async stop(): Promise<void> {
201
+ logger.info('Stopping orchestrator');
202
+
203
+ // Clear ping interval
204
+ if (this.pingInterval) {
205
+ clearInterval(this.pingInterval);
206
+ this.pingInterval = undefined;
207
+ }
208
+
209
+ if (this.heartbeatInterval) {
210
+ clearInterval(this.heartbeatInterval);
211
+ this.heartbeatInterval = undefined;
212
+ }
213
+
214
+ // Clean up memory monitor event handlers before stopping
215
+ if (this.memorySampleHandler) {
216
+ this.memoryMonitor.off('sample', this.memorySampleHandler);
217
+ this.memorySampleHandler = undefined;
218
+ }
219
+ if (this.memoryAlertHandler) {
220
+ this.memoryMonitor.off('alert', this.memoryAlertHandler);
221
+ this.memoryAlertHandler = undefined;
222
+ }
223
+
224
+ this.memoryMonitor.stop();
225
+
226
+ // Stop all workspace daemons
227
+ for (const [id] of this.workspaces) {
228
+ await this.stopWorkspaceDaemon(id);
229
+ }
230
+
231
+ // Stop supervisor
232
+ this.supervisor.stop();
233
+
234
+ // Close WebSocket connections
235
+ if (this.wss) {
236
+ for (const ws of this.wss.clients) {
237
+ ws.close();
238
+ }
239
+ this.wss.close();
240
+ }
241
+
242
+ // Close HTTP server
243
+ if (this.server) {
244
+ return new Promise((resolve) => {
245
+ this.server!.close(() => {
246
+ logger.info('Orchestrator stopped');
247
+ resolve();
248
+ });
249
+ });
250
+ }
251
+ }
252
+
253
+ // === Workspace Management ===
254
+
255
+ /**
256
+ * Add a workspace
257
+ */
258
+ addWorkspace(request: AddWorkspaceRequest): Workspace {
259
+ const resolvedPath = this.resolvePath(request.path);
260
+
261
+ // Check if already exists
262
+ const existing = this.findWorkspaceByPath(resolvedPath);
263
+ if (existing) {
264
+ return existing;
265
+ }
266
+
267
+ // Validate path exists
268
+ if (!fs.existsSync(resolvedPath)) {
269
+ throw new Error(`Path does not exist: ${resolvedPath}`);
270
+ }
271
+
272
+ const workspace: ManagedWorkspace = {
273
+ id: generateId(),
274
+ name: request.name || path.basename(resolvedPath),
275
+ path: resolvedPath,
276
+ status: 'inactive',
277
+ provider: request.provider || this.detectProvider(resolvedPath),
278
+ createdAt: new Date(),
279
+ lastActiveAt: new Date(),
280
+ ...this.getGitInfo(resolvedPath),
281
+ };
282
+
283
+ this.workspaces.set(workspace.id, workspace);
284
+ this.saveWorkspaces();
285
+
286
+ logger.info('Workspace added', { id: workspace.id, name: workspace.name });
287
+
288
+ this.broadcastEvent({
289
+ type: 'workspace:added',
290
+ workspaceId: workspace.id,
291
+ data: this.toPublicWorkspace(workspace),
292
+ timestamp: new Date(),
293
+ });
294
+
295
+ // Auto-start daemon
296
+ if (this.config.autoStartDaemons) {
297
+ this.startWorkspaceDaemon(workspace.id).catch((err) => {
298
+ logger.error('Failed to start workspace daemon', { id: workspace.id, error: String(err) });
299
+ });
300
+ }
301
+
302
+ return this.toPublicWorkspace(workspace);
303
+ }
304
+
305
+ /**
306
+ * Remove a workspace
307
+ */
308
+ async removeWorkspace(workspaceId: string): Promise<boolean> {
309
+ const workspace = this.workspaces.get(workspaceId);
310
+ if (!workspace) return false;
311
+
312
+ // Stop daemon if running
313
+ await this.stopWorkspaceDaemon(workspaceId);
314
+
315
+ // Clear active if this was active
316
+ if (this.activeWorkspaceId === workspaceId) {
317
+ this.activeWorkspaceId = undefined;
318
+ }
319
+
320
+ this.workspaces.delete(workspaceId);
321
+ this.saveWorkspaces();
322
+
323
+ logger.info('Workspace removed', { id: workspaceId });
324
+
325
+ this.broadcastEvent({
326
+ type: 'workspace:removed',
327
+ workspaceId,
328
+ data: { id: workspaceId },
329
+ timestamp: new Date(),
330
+ });
331
+
332
+ return true;
333
+ }
334
+
335
+ /**
336
+ * Switch to a workspace
337
+ */
338
+ async switchWorkspace(workspaceId: string): Promise<Workspace> {
339
+ const workspace = this.workspaces.get(workspaceId);
340
+ if (!workspace) {
341
+ throw new Error(`Workspace not found: ${workspaceId}`);
342
+ }
343
+
344
+ const previousId = this.activeWorkspaceId;
345
+
346
+ // Update status
347
+ if (previousId && previousId !== workspaceId) {
348
+ const prev = this.workspaces.get(previousId);
349
+ if (prev) {
350
+ prev.status = 'inactive';
351
+ }
352
+ }
353
+
354
+ workspace.status = 'active';
355
+ workspace.lastActiveAt = new Date();
356
+ this.activeWorkspaceId = workspaceId;
357
+
358
+ // Ensure daemon is running
359
+ if (!workspace.daemon?.isRunning) {
360
+ await this.startWorkspaceDaemon(workspaceId);
361
+ }
362
+
363
+ this.saveWorkspaces();
364
+
365
+ logger.info('Switched workspace', { id: workspaceId, name: workspace.name });
366
+
367
+ this.broadcastEvent({
368
+ type: 'workspace:switched',
369
+ workspaceId,
370
+ data: { previousId, currentId: workspaceId },
371
+ timestamp: new Date(),
372
+ });
373
+
374
+ return this.toPublicWorkspace(workspace);
375
+ }
376
+
377
+ /**
378
+ * Get all workspaces
379
+ */
380
+ getWorkspaces(): Workspace[] {
381
+ return Array.from(this.workspaces.values()).map((w) => this.toPublicWorkspace(w));
382
+ }
383
+
384
+ /**
385
+ * Get workspace by ID
386
+ */
387
+ getWorkspace(workspaceId: string): Workspace | undefined {
388
+ const workspace = this.workspaces.get(workspaceId);
389
+ return workspace ? this.toPublicWorkspace(workspace) : undefined;
390
+ }
391
+
392
+ /**
393
+ * Get active workspace
394
+ */
395
+ getActiveWorkspace(): Workspace | undefined {
396
+ if (!this.activeWorkspaceId) return undefined;
397
+ return this.getWorkspace(this.activeWorkspaceId);
398
+ }
399
+
400
+ // === Agent Management ===
401
+
402
+ /**
403
+ * Spawn an agent in a workspace
404
+ */
405
+ async spawnAgent(workspaceId: string, request: SpawnAgentRequest): Promise<Agent> {
406
+ const workspace = this.workspaces.get(workspaceId);
407
+ if (!workspace) {
408
+ throw new Error(`Workspace not found: ${workspaceId}`);
409
+ }
410
+
411
+ // Ensure daemon is running
412
+ if (!workspace.daemon?.isRunning) {
413
+ await this.startWorkspaceDaemon(workspaceId);
414
+ }
415
+
416
+ // Ensure spawner exists
417
+ if (!workspace.spawner) {
418
+ workspace.spawner = new AgentSpawner({
419
+ projectRoot: workspace.path,
420
+ onMarkSpawning: (name) => workspace.daemon?.markSpawning(name),
421
+ onClearSpawning: (name) => workspace.daemon?.clearSpawning(name),
422
+ });
423
+ }
424
+
425
+ const result = await workspace.spawner.spawn({
426
+ name: request.name,
427
+ cli: this.getCliForProvider(request.provider || workspace.provider),
428
+ task: request.task || '',
429
+ });
430
+
431
+ if (!result.success) {
432
+ throw new Error(result.error || 'Failed to spawn agent');
433
+ }
434
+
435
+ const agent: Agent = {
436
+ id: generateId(),
437
+ name: request.name,
438
+ workspaceId,
439
+ provider: request.provider || workspace.provider,
440
+ status: 'running',
441
+ pid: result.pid,
442
+ task: request.task,
443
+ spawnedAt: new Date(),
444
+ restartCount: 0,
445
+ };
446
+
447
+ // Register for health monitoring if we have a PID
448
+ if (result.pid) {
449
+ this.registerAgentHealth(workspaceId, request.name, result.pid);
450
+ } else {
451
+ logger.warn('Agent spawned without PID - health monitoring disabled', {
452
+ workspaceId,
453
+ agentName: request.name,
454
+ });
455
+ }
456
+
457
+ logger.info('Agent spawned', { id: agent.id, name: agent.name, workspaceId, pid: result.pid });
458
+
459
+ this.broadcastEvent({
460
+ type: 'agent:spawned',
461
+ workspaceId,
462
+ agentId: agent.id,
463
+ data: agent,
464
+ timestamp: new Date(),
465
+ });
466
+
467
+ return agent;
468
+ }
469
+
470
+ /**
471
+ * Stop an agent
472
+ */
473
+ async stopAgent(workspaceId: string, agentName: string): Promise<boolean> {
474
+ const workspace = this.workspaces.get(workspaceId);
475
+ if (!workspace?.spawner) return false;
476
+
477
+ // Mark as releasing BEFORE stopping to prevent crash announcement
478
+ this.markAgentReleasing(workspaceId, agentName);
479
+
480
+ try {
481
+ const released = await workspace.spawner.release(agentName);
482
+
483
+ if (released) {
484
+ // Unregister from health monitoring after successful release
485
+ this.unregisterAgentHealth(workspaceId, agentName);
486
+
487
+ this.broadcastEvent({
488
+ type: 'agent:stopped',
489
+ workspaceId,
490
+ data: { name: agentName },
491
+ timestamp: new Date(),
492
+ });
493
+
494
+ logger.info('Agent stopped gracefully', { workspaceId, agentName });
495
+ } else {
496
+ // Release failed - clear the releasing flag
497
+ const health = this.getAgentHealth(workspaceId, agentName);
498
+ if (health) {
499
+ health.releasing = false;
500
+ }
501
+ }
502
+
503
+ return released;
504
+ } catch (err) {
505
+ // Release threw an exception - clean up health tracking to avoid stuck state
506
+ this.unregisterAgentHealth(workspaceId, agentName);
507
+ logger.error('Agent release failed with exception', {
508
+ workspaceId,
509
+ agentName,
510
+ error: String(err),
511
+ });
512
+ throw err;
513
+ }
514
+ }
515
+
516
+ /**
517
+ * Get agents in a workspace
518
+ */
519
+ getAgents(workspaceId: string): Agent[] {
520
+ const workspace = this.workspaces.get(workspaceId);
521
+ if (!workspace?.spawner) return [];
522
+
523
+ return workspace.spawner.getActiveWorkers().map((w) => {
524
+ // Get health data for this agent
525
+ const health = this.getAgentHealth(workspaceId, w.name);
526
+
527
+ return {
528
+ id: w.name,
529
+ name: w.name,
530
+ workspaceId,
531
+ provider: this.detectProviderFromCli(w.cli),
532
+ status: 'running' as const,
533
+ pid: w.pid,
534
+ task: w.task,
535
+ spawnedAt: new Date(w.spawnedAt),
536
+ lastHealthCheck: health?.lastHeartbeatAt,
537
+ rssBytes: health?.lastRssBytes,
538
+ cpuPercent: health?.lastCpuPercent,
539
+ restartCount: 0,
540
+ };
541
+ });
542
+ }
543
+
544
+ // === Private Methods ===
545
+
546
+ /**
547
+ * Start daemon for a workspace
548
+ */
549
+ private async startWorkspaceDaemon(workspaceId: string): Promise<void> {
550
+ const workspace = this.workspaces.get(workspaceId);
551
+ if (!workspace) return;
552
+
553
+ if (workspace.daemon?.isRunning) return;
554
+
555
+ try {
556
+ const paths = getProjectPaths(workspace.path);
557
+
558
+ workspace.daemon = new Daemon({
559
+ socketPath: paths.socketPath,
560
+ teamDir: paths.teamDir,
561
+ });
562
+
563
+ await workspace.daemon.start();
564
+ workspace.status = 'active';
565
+
566
+ // Create spawner
567
+ workspace.spawner = new AgentSpawner({
568
+ projectRoot: workspace.path,
569
+ onMarkSpawning: (name) => workspace.daemon?.markSpawning(name),
570
+ onClearSpawning: (name) => workspace.daemon?.clearSpawning(name),
571
+ });
572
+
573
+ // Set up cloud persistence for session tracking (if cloud sync is enabled)
574
+ const cloudSync = getCloudSync();
575
+ if (cloudSync.isConnected()) {
576
+ const persistenceHandler = createCloudPersistenceHandler(cloudSync, workspace.cloudId);
577
+ workspace.spawner.setCloudPersistence(persistenceHandler);
578
+ logger.info('Cloud persistence enabled for workspace', { id: workspaceId });
579
+ }
580
+
581
+ // Set up agent death notifications
582
+ workspace.spawner.setOnAgentDeath((info) => {
583
+ // Broadcast to dashboard via WebSocket
584
+ this.broadcastEvent({
585
+ type: 'agent:crashed',
586
+ workspaceId,
587
+ data: {
588
+ name: info.name,
589
+ exitCode: info.exitCode,
590
+ continuityAgentId: info.agentId,
591
+ resumeInstructions: info.resumeInstructions,
592
+ },
593
+ timestamp: new Date(),
594
+ });
595
+
596
+ // Broadcast to all connected agents via relay
597
+ const message = info.agentId
598
+ ? `AGENT DIED: "${info.name}" has crashed (exit code: ${info.exitCode}). Agent ID: ${info.agentId}. ${info.resumeInstructions}`
599
+ : `AGENT DIED: "${info.name}" has crashed (exit code: ${info.exitCode}).`;
600
+
601
+ workspace.daemon?.broadcastSystemMessage(message, {
602
+ agentName: info.name,
603
+ exitCode: info.exitCode,
604
+ agentId: info.agentId,
605
+ resumeInstructions: info.resumeInstructions,
606
+ });
607
+
608
+ logger.warn('Agent died', {
609
+ name: info.name,
610
+ exitCode: info.exitCode,
611
+ agentId: info.agentId,
612
+ });
613
+ });
614
+
615
+ logger.info('Workspace daemon started', { id: workspaceId, socket: paths.socketPath });
616
+ } catch (err) {
617
+ workspace.status = 'error';
618
+ logger.error('Failed to start workspace daemon', { id: workspaceId, error: String(err) });
619
+ throw err;
620
+ }
621
+ }
622
+
623
+ /**
624
+ * Stop daemon for a workspace
625
+ */
626
+ private async stopWorkspaceDaemon(workspaceId: string): Promise<void> {
627
+ const workspace = this.workspaces.get(workspaceId);
628
+ if (!workspace) return;
629
+
630
+ // Mark all agents as releasing to prevent crash announcements
631
+ const workspaceHealth = this.getWorkspaceAgentHealth(workspaceId);
632
+ for (const health of workspaceHealth) {
633
+ this.markAgentReleasing(workspaceId, health.agentName);
634
+ }
635
+
636
+ // Release all agents first
637
+ if (workspace.spawner) {
638
+ await workspace.spawner.releaseAll();
639
+ }
640
+
641
+ // Clean up health monitoring for all agents in this workspace
642
+ for (const health of workspaceHealth) {
643
+ this.unregisterAgentHealth(workspaceId, health.agentName);
644
+ }
645
+
646
+ // Stop daemon
647
+ if (workspace.daemon) {
648
+ await workspace.daemon.stop();
649
+ workspace.daemon = undefined;
650
+ }
651
+
652
+ workspace.spawner = undefined;
653
+ workspace.status = 'inactive';
654
+
655
+ logger.info('Workspace daemon stopped', { id: workspaceId });
656
+ }
657
+
658
+ /**
659
+ * Handle HTTP request
660
+ */
661
+ private async handleRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
662
+ // CORS
663
+ res.setHeader('Access-Control-Allow-Origin', '*');
664
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
665
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
666
+
667
+ if (req.method === 'OPTIONS') {
668
+ res.writeHead(204);
669
+ res.end();
670
+ return;
671
+ }
672
+
673
+ const url = new URL(req.url || '/', `http://${req.headers.host}`);
674
+ const pathname = url.pathname;
675
+ const method = req.method || 'GET';
676
+
677
+ try {
678
+ let response: { status: number; body: unknown };
679
+
680
+ // Health check
681
+ if (pathname === '/' && method === 'GET') {
682
+ response = { status: 200, body: { status: 'ok', version: '1.0.0' } };
683
+ }
684
+ // Metrics
685
+ else if (pathname === '/metrics' && method === 'GET') {
686
+ res.setHeader('Content-Type', 'text/plain');
687
+ res.writeHead(200);
688
+ res.end(metrics.toPrometheus());
689
+ return;
690
+ }
691
+ // List workspaces
692
+ else if (pathname === '/workspaces' && method === 'GET') {
693
+ response = {
694
+ status: 200,
695
+ body: {
696
+ workspaces: this.getWorkspaces(),
697
+ activeWorkspaceId: this.activeWorkspaceId,
698
+ },
699
+ };
700
+ }
701
+ // Add workspace
702
+ else if (pathname === '/workspaces' && method === 'POST') {
703
+ const body = await this.parseBody(req);
704
+ const workspace = this.addWorkspace(body as AddWorkspaceRequest);
705
+ response = { status: 201, body: workspace };
706
+ }
707
+ // Get workspace
708
+ else if (pathname.match(/^\/workspaces\/[^/]+$/) && method === 'GET') {
709
+ const id = pathname.split('/')[2];
710
+ const workspace = this.getWorkspace(id);
711
+ response = workspace
712
+ ? { status: 200, body: workspace }
713
+ : { status: 404, body: { error: 'Not found' } };
714
+ }
715
+ // Delete workspace
716
+ else if (pathname.match(/^\/workspaces\/[^/]+$/) && method === 'DELETE') {
717
+ const id = pathname.split('/')[2];
718
+ const removed = await this.removeWorkspace(id);
719
+ response = removed
720
+ ? { status: 204, body: null }
721
+ : { status: 404, body: { error: 'Not found' } };
722
+ }
723
+ // Switch workspace
724
+ else if (pathname.match(/^\/workspaces\/[^/]+\/switch$/) && method === 'POST') {
725
+ const id = pathname.split('/')[2];
726
+ const workspace = await this.switchWorkspace(id);
727
+ response = { status: 200, body: workspace };
728
+ }
729
+ // List agents in workspace
730
+ else if (pathname.match(/^\/workspaces\/[^/]+\/agents$/) && method === 'GET') {
731
+ const id = pathname.split('/')[2];
732
+ const agents = this.getAgents(id);
733
+ response = { status: 200, body: { agents, workspaceId: id } };
734
+ }
735
+ // Spawn agent
736
+ else if (pathname.match(/^\/workspaces\/[^/]+\/agents$/) && method === 'POST') {
737
+ const id = pathname.split('/')[2];
738
+ const body = await this.parseBody(req);
739
+ const agent = await this.spawnAgent(id, body as SpawnAgentRequest);
740
+ response = { status: 201, body: agent };
741
+ }
742
+ // Stop agent
743
+ else if (pathname.match(/^\/workspaces\/[^/]+\/agents\/[^/]+$/) && method === 'DELETE') {
744
+ const parts = pathname.split('/');
745
+ const workspaceId = parts[2];
746
+ const agentName = parts[4];
747
+ const stopped = await this.stopAgent(workspaceId, agentName);
748
+ response = stopped
749
+ ? { status: 204, body: null }
750
+ : { status: 404, body: { error: 'Not found' } };
751
+ }
752
+ // Not found
753
+ else {
754
+ response = { status: 404, body: { error: 'Not found' } };
755
+ }
756
+
757
+ res.setHeader('Content-Type', 'application/json');
758
+ res.writeHead(response.status);
759
+ res.end(response.body ? JSON.stringify(response.body) : '');
760
+ } catch (err) {
761
+ logger.error('Request error', { error: String(err) });
762
+ res.setHeader('Content-Type', 'application/json');
763
+ res.writeHead(500);
764
+ res.end(JSON.stringify({ error: String(err) }));
765
+ }
766
+ }
767
+
768
+ /**
769
+ * Handle WebSocket connection
770
+ */
771
+ private handleWebSocket(ws: WebSocket, _req: http.IncomingMessage): void {
772
+ logger.info('WebSocket client connected');
773
+
774
+ // Mark client as alive for ping/pong keepalive
775
+ this.clientAlive.set(ws, true);
776
+
777
+ // Handle pong responses
778
+ ws.on('pong', () => {
779
+ this.clientAlive.set(ws, true);
780
+ });
781
+
782
+ const session: UserSession = {
783
+ userId: 'anonymous',
784
+ githubUsername: 'anonymous',
785
+ connectedAt: new Date(),
786
+ activeWorkspaceId: this.activeWorkspaceId,
787
+ };
788
+ this.sessions.set(ws, session);
789
+
790
+ // Send initial state
791
+ this.sendToClient(ws, {
792
+ type: 'init',
793
+ data: {
794
+ workspaces: this.getWorkspaces(),
795
+ activeWorkspaceId: this.activeWorkspaceId,
796
+ agents: this.activeWorkspaceId ? this.getAgents(this.activeWorkspaceId) : [],
797
+ },
798
+ });
799
+
800
+ ws.on('message', (data) => {
801
+ try {
802
+ const msg = JSON.parse(data.toString());
803
+ this.handleWebSocketMessage(ws, session, msg);
804
+ } catch (err) {
805
+ logger.error('WebSocket message error', { error: String(err) });
806
+ }
807
+ });
808
+
809
+ ws.on('close', () => {
810
+ this.sessions.delete(ws);
811
+ logger.info('WebSocket client disconnected');
812
+ });
813
+ }
814
+
815
+ /**
816
+ * Handle WebSocket message
817
+ */
818
+ private handleWebSocketMessage(
819
+ ws: WebSocket,
820
+ session: UserSession,
821
+ msg: { type: string; data?: unknown }
822
+ ): void {
823
+ switch (msg.type) {
824
+ case 'switch_workspace':
825
+ if (typeof msg.data === 'string') {
826
+ this.switchWorkspace(msg.data)
827
+ .then((workspace) => {
828
+ session.activeWorkspaceId = workspace.id;
829
+ })
830
+ .catch((err) => {
831
+ this.sendToClient(ws, { type: 'error', data: String(err) });
832
+ });
833
+ }
834
+ break;
835
+ case 'ping':
836
+ this.sendToClient(ws, { type: 'pong' });
837
+ break;
838
+ }
839
+ }
840
+
841
+ /**
842
+ * Send to WebSocket client
843
+ */
844
+ private sendToClient(ws: WebSocket, msg: unknown): void {
845
+ if (ws.readyState === WebSocket.OPEN) {
846
+ ws.send(JSON.stringify(msg));
847
+ }
848
+ }
849
+
850
+ /**
851
+ * Broadcast event to all clients
852
+ */
853
+ private broadcastEvent(event: DaemonEvent): void {
854
+ if (!this.wss) return;
855
+ const msg = JSON.stringify({ type: 'event', data: event });
856
+ for (const ws of this.wss.clients) {
857
+ if (ws.readyState === WebSocket.OPEN) {
858
+ ws.send(msg);
859
+ }
860
+ }
861
+ }
862
+
863
+ /**
864
+ * Parse request body
865
+ */
866
+ private parseBody(req: http.IncomingMessage): Promise<unknown> {
867
+ return new Promise((resolve, reject) => {
868
+ let data = '';
869
+ req.on('data', (chunk) => (data += chunk));
870
+ req.on('end', () => {
871
+ try {
872
+ resolve(data ? JSON.parse(data) : {});
873
+ } catch {
874
+ reject(new Error('Invalid JSON'));
875
+ }
876
+ });
877
+ });
878
+ }
879
+
880
+ /**
881
+ * Load workspaces from disk
882
+ */
883
+ private loadWorkspaces(): void {
884
+ if (!fs.existsSync(this.workspacesFile)) return;
885
+ try {
886
+ const data = JSON.parse(fs.readFileSync(this.workspacesFile, 'utf8'));
887
+ for (const w of data.workspaces || []) {
888
+ this.workspaces.set(w.id, {
889
+ ...w,
890
+ createdAt: new Date(w.createdAt),
891
+ lastActiveAt: new Date(w.lastActiveAt),
892
+ status: 'inactive',
893
+ });
894
+ }
895
+ this.activeWorkspaceId = data.activeWorkspaceId;
896
+ logger.info('Loaded workspaces', { count: this.workspaces.size });
897
+ } catch (err) {
898
+ logger.error('Failed to load workspaces', { error: String(err) });
899
+ }
900
+ }
901
+
902
+ /**
903
+ * Save workspaces to disk
904
+ */
905
+ private saveWorkspaces(): void {
906
+ try {
907
+ const data = {
908
+ workspaces: Array.from(this.workspaces.values()).map((w) => this.toPublicWorkspace(w)),
909
+ activeWorkspaceId: this.activeWorkspaceId,
910
+ };
911
+ fs.writeFileSync(this.workspacesFile, JSON.stringify(data, null, 2));
912
+ } catch (err) {
913
+ logger.error('Failed to save workspaces', { error: String(err) });
914
+ }
915
+ }
916
+
917
+ /**
918
+ * Find workspace by path
919
+ */
920
+ private findWorkspaceByPath(path: string): Workspace | undefined {
921
+ const resolved = this.resolvePath(path);
922
+ const workspace = Array.from(this.workspaces.values()).find((w) => w.path === resolved);
923
+ return workspace ? this.toPublicWorkspace(workspace) : undefined;
924
+ }
925
+
926
+ /**
927
+ * Resolve path
928
+ */
929
+ private resolvePath(p: string): string {
930
+ if (p.startsWith('~')) {
931
+ p = path.join(process.env.HOME || '', p.slice(1));
932
+ }
933
+ return path.resolve(p);
934
+ }
935
+
936
+ /**
937
+ * Detect provider from workspace
938
+ */
939
+ private detectProvider(workspacePath: string): ProviderType {
940
+ if (
941
+ fs.existsSync(path.join(workspacePath, 'CLAUDE.md')) ||
942
+ fs.existsSync(path.join(workspacePath, '.claude'))
943
+ ) {
944
+ return 'claude';
945
+ }
946
+ if (fs.existsSync(path.join(workspacePath, '.codex'))) {
947
+ return 'codex';
948
+ }
949
+ if (fs.existsSync(path.join(workspacePath, '.gemini'))) {
950
+ return 'gemini';
951
+ }
952
+ return 'generic';
953
+ }
954
+
955
+ /**
956
+ * Detect provider from CLI command
957
+ */
958
+ private detectProviderFromCli(cli: string): ProviderType {
959
+ if (cli.includes('claude')) return 'claude';
960
+ if (cli.includes('codex')) return 'codex';
961
+ if (cli.includes('gemini')) return 'gemini';
962
+ return 'generic';
963
+ }
964
+
965
+ /**
966
+ * Get CLI command for provider
967
+ */
968
+ private getCliForProvider(provider: ProviderType): string {
969
+ switch (provider) {
970
+ case 'claude':
971
+ return 'claude';
972
+ case 'codex':
973
+ return 'codex';
974
+ case 'gemini':
975
+ return 'gemini';
976
+ default:
977
+ return 'claude';
978
+ }
979
+ }
980
+
981
+ /**
982
+ * Get git info
983
+ */
984
+ private getGitInfo(workspacePath: string): { gitRemote?: string; gitBranch?: string } {
985
+ try {
986
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
987
+ const { execSync } = require('child_process');
988
+ const branch = execSync('git branch --show-current', {
989
+ cwd: workspacePath,
990
+ encoding: 'utf8',
991
+ stdio: ['pipe', 'pipe', 'pipe'],
992
+ }).trim();
993
+ let remote: string | undefined;
994
+ try {
995
+ remote = execSync('git remote get-url origin', {
996
+ cwd: workspacePath,
997
+ encoding: 'utf8',
998
+ stdio: ['pipe', 'pipe', 'pipe'],
999
+ }).trim();
1000
+ } catch {
1001
+ // No remote
1002
+ }
1003
+ return { gitRemote: remote, gitBranch: branch };
1004
+ } catch {
1005
+ return {};
1006
+ }
1007
+ }
1008
+
1009
+ /**
1010
+ * Convert to public workspace (without internal references)
1011
+ */
1012
+ private toPublicWorkspace(w: ManagedWorkspace): Workspace {
1013
+ return {
1014
+ id: w.id,
1015
+ name: w.name,
1016
+ path: w.path,
1017
+ status: w.status,
1018
+ provider: w.provider,
1019
+ createdAt: w.createdAt,
1020
+ lastActiveAt: w.lastActiveAt,
1021
+ cloudId: w.cloudId,
1022
+ customDomain: w.customDomain,
1023
+ gitRemote: w.gitRemote,
1024
+ gitBranch: w.gitBranch,
1025
+ };
1026
+ }
1027
+
1028
+ // === Health Monitoring ===
1029
+
1030
+ /**
1031
+ * Start agent health monitoring.
1032
+ * Monitors PIDs for liveness and tracks memory/CPU usage.
1033
+ */
1034
+ private startHealthMonitoring(): void {
1035
+ // Start the memory monitor
1036
+ this.memoryMonitor.start();
1037
+
1038
+ // Listen for memory samples to update health state
1039
+ // Store handler reference for cleanup
1040
+ this.memorySampleHandler = (event: { name: string; snapshot: MemorySnapshot }) => {
1041
+ const health = this.agentHealth.get(event.name);
1042
+ if (health) {
1043
+ health.lastSampleAt = new Date();
1044
+ health.lastRssBytes = event.snapshot.rssBytes;
1045
+ health.lastCpuPercent = event.snapshot.cpuPercent;
1046
+
1047
+ // Check for high CPU usage and broadcast alert
1048
+ if (event.snapshot.cpuPercent >= CPU_ALERT_THRESHOLD) {
1049
+ this.broadcastResourceAlert(health, 'cpu', event.snapshot.cpuPercent);
1050
+ }
1051
+ }
1052
+ };
1053
+ this.memoryMonitor.on('sample', this.memorySampleHandler);
1054
+
1055
+ // Listen for memory alerts and broadcast to agents
1056
+ // Store handler reference for cleanup
1057
+ this.memoryAlertHandler = (alert: MemoryAlert) => {
1058
+ const health = this.agentHealth.get(alert.agentName);
1059
+ if (health && alert.type !== 'recovered') {
1060
+ this.broadcastResourceAlert(health, 'memory', alert.currentRss, alert);
1061
+ }
1062
+ };
1063
+ this.memoryMonitor.on('alert', this.memoryAlertHandler);
1064
+
1065
+ // Start heartbeat interval to check PIDs are alive
1066
+ this.heartbeatInterval = setInterval(() => {
1067
+ this.checkAgentHeartbeats();
1068
+ }, HEARTBEAT_INTERVAL_MS);
1069
+
1070
+ logger.info('Health monitoring started', {
1071
+ heartbeatIntervalMs: HEARTBEAT_INTERVAL_MS,
1072
+ cpuAlertThreshold: CPU_ALERT_THRESHOLD,
1073
+ });
1074
+ }
1075
+
1076
+ /**
1077
+ * Check all registered agents' PIDs are still alive.
1078
+ * If a PID has died unexpectedly, broadcast a crash notification.
1079
+ */
1080
+ private checkAgentHeartbeats(): void {
1081
+ // Collect crashed agents first to avoid modifying map during iteration
1082
+ const crashedAgents: AgentHealthState[] = [];
1083
+
1084
+ for (const [key, health] of this.agentHealth) {
1085
+ const isAlive = this.isProcessAlive(health.pid);
1086
+
1087
+ if (isAlive) {
1088
+ // Only update heartbeat timestamp for alive processes
1089
+ health.lastHeartbeatAt = new Date();
1090
+ } else if (!health.releasing) {
1091
+ // Agent died unexpectedly - mark for crash handling
1092
+ // Immediately remove from map to prevent duplicate handling on next interval
1093
+ this.agentHealth.delete(key);
1094
+ crashedAgents.push(health);
1095
+ }
1096
+ // If !isAlive && health.releasing, agent is being gracefully stopped - skip
1097
+ }
1098
+
1099
+ // Now handle crashes outside the iteration
1100
+ for (const health of crashedAgents) {
1101
+ logger.warn('Agent heartbeat failed - process died', {
1102
+ workspaceId: health.workspaceId,
1103
+ agentName: health.agentName,
1104
+ pid: health.pid,
1105
+ });
1106
+
1107
+ this.handleAgentCrash(health);
1108
+ }
1109
+ }
1110
+
1111
+ /**
1112
+ * Check if a process is alive by sending signal 0.
1113
+ */
1114
+ private isProcessAlive(pid: number): boolean {
1115
+ try {
1116
+ process.kill(pid, 0);
1117
+ return true;
1118
+ } catch {
1119
+ return false;
1120
+ }
1121
+ }
1122
+
1123
+ /**
1124
+ * Handle an agent crash - unregister and broadcast to other agents.
1125
+ * Note: Agent is already removed from agentHealth map before this is called.
1126
+ */
1127
+ private handleAgentCrash(health: AgentHealthState): void {
1128
+ const workspace = this.workspaces.get(health.workspaceId);
1129
+
1130
+ // Get crash context from memory monitor for analysis
1131
+ const crashContext = this.memoryMonitor.getCrashContext(health.agentName);
1132
+
1133
+ // Unregister from memory monitor (agent already removed from agentHealth map)
1134
+ this.memoryMonitor.unregister(health.agentName);
1135
+
1136
+ // Broadcast crash to dashboard via WebSocket
1137
+ this.broadcastEvent({
1138
+ type: 'agent:crashed',
1139
+ workspaceId: health.workspaceId,
1140
+ data: {
1141
+ name: health.agentName,
1142
+ pid: health.pid,
1143
+ crashContext: {
1144
+ likelyCause: crashContext.likelyCause,
1145
+ peakMemory: crashContext.peakMemory,
1146
+ averageMemory: crashContext.averageMemory,
1147
+ memoryTrend: crashContext.memoryTrend,
1148
+ analysisNotes: crashContext.analysisNotes,
1149
+ },
1150
+ },
1151
+ timestamp: new Date(),
1152
+ });
1153
+
1154
+ // Broadcast to all connected agents in the workspace via relay
1155
+ const message = crashContext.likelyCause !== 'unknown'
1156
+ ? `AGENT CRASHED: "${health.agentName}" has died unexpectedly (PID: ${health.pid}). Likely cause: ${crashContext.likelyCause}. ${crashContext.analysisNotes.slice(0, 2).join('. ')}`
1157
+ : `AGENT CRASHED: "${health.agentName}" has died unexpectedly (PID: ${health.pid}).`;
1158
+
1159
+ workspace?.daemon?.broadcastSystemMessage(message, {
1160
+ agentName: health.agentName,
1161
+ pid: health.pid,
1162
+ likelyCause: crashContext.likelyCause,
1163
+ crashType: 'heartbeat_failure',
1164
+ });
1165
+
1166
+ // Remove the stale agent from the router so connected-agents.json is accurate
1167
+ workspace?.daemon?.removeStaleAgent(health.agentName);
1168
+
1169
+ logger.error('Agent crashed', {
1170
+ workspaceId: health.workspaceId,
1171
+ agentName: health.agentName,
1172
+ pid: health.pid,
1173
+ likelyCause: crashContext.likelyCause,
1174
+ });
1175
+ }
1176
+
1177
+ /**
1178
+ * Broadcast a resource alert (memory or CPU) to agents.
1179
+ */
1180
+ private broadcastResourceAlert(
1181
+ health: AgentHealthState,
1182
+ resourceType: 'memory' | 'cpu',
1183
+ currentValue: number,
1184
+ memoryAlert?: MemoryAlert
1185
+ ): void {
1186
+ // CPU alert cooldown to avoid spamming
1187
+ if (resourceType === 'cpu') {
1188
+ const now = Date.now();
1189
+ if (health.lastCpuAlertAt && now - health.lastCpuAlertAt < RESOURCE_ALERT_COOLDOWN_MS) {
1190
+ return; // Still in cooldown
1191
+ }
1192
+ health.lastCpuAlertAt = now;
1193
+ }
1194
+
1195
+ const workspace = this.workspaces.get(health.workspaceId);
1196
+
1197
+ // Broadcast to dashboard
1198
+ this.broadcastEvent({
1199
+ type: 'agent:resource-alert',
1200
+ workspaceId: health.workspaceId,
1201
+ agentId: health.agentName,
1202
+ data: {
1203
+ name: health.agentName,
1204
+ resourceType,
1205
+ currentValue,
1206
+ alertLevel: memoryAlert?.type ?? 'high_cpu',
1207
+ message: memoryAlert?.message ??
1208
+ `Agent "${health.agentName}" is running at ${currentValue.toFixed(1)}% CPU`,
1209
+ recommendation: memoryAlert?.recommendation ??
1210
+ 'Consider reducing workload or checking for runaway processes',
1211
+ },
1212
+ timestamp: new Date(),
1213
+ });
1214
+
1215
+ // Broadcast to agents
1216
+ const message = resourceType === 'memory'
1217
+ ? `RESOURCE ALERT: "${health.agentName}" memory usage is ${memoryAlert?.type ?? 'high'} (${formatBytes(currentValue)}). ${memoryAlert?.recommendation ?? ''}`
1218
+ : `RESOURCE ALERT: "${health.agentName}" is running at ${currentValue.toFixed(1)}% CPU. Consider reducing workload.`;
1219
+
1220
+ workspace?.daemon?.broadcastSystemMessage(message, {
1221
+ agentName: health.agentName,
1222
+ resourceType,
1223
+ alertLevel: memoryAlert?.type ?? 'high_cpu',
1224
+ });
1225
+
1226
+ logger.warn('Resource alert', {
1227
+ workspaceId: health.workspaceId,
1228
+ agentName: health.agentName,
1229
+ resourceType,
1230
+ currentValue: resourceType === 'memory' ? formatBytes(currentValue) : `${currentValue.toFixed(1)}%`,
1231
+ alertLevel: memoryAlert?.type ?? 'high_cpu',
1232
+ });
1233
+ }
1234
+
1235
+ /**
1236
+ * Register an agent for health monitoring.
1237
+ */
1238
+ private registerAgentHealth(workspaceId: string, agentName: string, pid: number): void {
1239
+ const key = `${workspaceId}:${agentName}`;
1240
+
1241
+ // Guard against double-registration - update PID instead
1242
+ if (this.agentHealth.has(key)) {
1243
+ logger.warn('Agent already registered for health monitoring, updating PID', {
1244
+ workspaceId,
1245
+ agentName,
1246
+ newPid: pid,
1247
+ });
1248
+ this.updateAgentHealthPid(workspaceId, agentName, pid);
1249
+ return;
1250
+ }
1251
+
1252
+ this.agentHealth.set(key, {
1253
+ key,
1254
+ workspaceId,
1255
+ agentName,
1256
+ pid,
1257
+ lastHeartbeatAt: new Date(),
1258
+ });
1259
+
1260
+ // Register with memory monitor
1261
+ this.memoryMonitor.register(agentName, pid);
1262
+
1263
+ logger.info('Agent registered for health monitoring', {
1264
+ workspaceId,
1265
+ agentName,
1266
+ pid,
1267
+ });
1268
+ }
1269
+
1270
+ /**
1271
+ * Update PID for an agent (after restart).
1272
+ *
1273
+ * This method is intended for agent restart scenarios where the agent process
1274
+ * is restarted with a new PID but should maintain continuity in health tracking.
1275
+ * Currently unused but reserved for future auto-restart functionality.
1276
+ *
1277
+ * @param workspaceId - The workspace ID
1278
+ * @param agentName - The agent name
1279
+ * @param newPid - The new process ID after restart
1280
+ */
1281
+ private updateAgentHealthPid(workspaceId: string, agentName: string, newPid: number): void {
1282
+ const key = `${workspaceId}:${agentName}`;
1283
+ const health = this.agentHealth.get(key);
1284
+
1285
+ if (health) {
1286
+ health.pid = newPid;
1287
+ health.releasing = false;
1288
+ health.lastHeartbeatAt = new Date();
1289
+ this.memoryMonitor.updatePid(agentName, newPid);
1290
+
1291
+ logger.info('Agent health PID updated', {
1292
+ workspaceId,
1293
+ agentName,
1294
+ newPid,
1295
+ });
1296
+ } else {
1297
+ // Register new
1298
+ this.registerAgentHealth(workspaceId, agentName, newPid);
1299
+ }
1300
+ }
1301
+
1302
+ /**
1303
+ * Mark an agent as releasing (to avoid crash announcement).
1304
+ */
1305
+ private markAgentReleasing(workspaceId: string, agentName: string): void {
1306
+ const key = `${workspaceId}:${agentName}`;
1307
+ const health = this.agentHealth.get(key);
1308
+
1309
+ if (health) {
1310
+ health.releasing = true;
1311
+ logger.debug('Agent marked as releasing', { workspaceId, agentName });
1312
+ }
1313
+ }
1314
+
1315
+ /**
1316
+ * Unregister an agent from health monitoring.
1317
+ */
1318
+ private unregisterAgentHealth(workspaceId: string, agentName: string): void {
1319
+ const key = `${workspaceId}:${agentName}`;
1320
+ this.agentHealth.delete(key);
1321
+ this.memoryMonitor.unregister(agentName);
1322
+
1323
+ logger.debug('Agent unregistered from health monitoring', {
1324
+ workspaceId,
1325
+ agentName,
1326
+ });
1327
+ }
1328
+
1329
+ /**
1330
+ * Get health state for an agent.
1331
+ */
1332
+ private getAgentHealth(workspaceId: string, agentName: string): AgentHealthState | undefined {
1333
+ return this.agentHealth.get(`${workspaceId}:${agentName}`);
1334
+ }
1335
+
1336
+ /**
1337
+ * Get health states for all agents in a workspace.
1338
+ */
1339
+ private getWorkspaceAgentHealth(workspaceId: string): AgentHealthState[] {
1340
+ return Array.from(this.agentHealth.values()).filter((h) => h.workspaceId === workspaceId);
1341
+ }
1342
+ }
1343
+
1344
+ let orchestratorInstance: Orchestrator | undefined;
1345
+
1346
+ /**
1347
+ * Start the orchestrator
1348
+ */
1349
+ export async function startOrchestrator(
1350
+ config: Partial<OrchestratorConfig> = {}
1351
+ ): Promise<Orchestrator> {
1352
+ if (orchestratorInstance) {
1353
+ return orchestratorInstance;
1354
+ }
1355
+
1356
+ orchestratorInstance = new Orchestrator(config);
1357
+ await orchestratorInstance.start();
1358
+ return orchestratorInstance;
1359
+ }
1360
+
1361
+ /**
1362
+ * Stop the orchestrator
1363
+ */
1364
+ export async function stopOrchestrator(): Promise<void> {
1365
+ if (orchestratorInstance) {
1366
+ await orchestratorInstance.stop();
1367
+ orchestratorInstance = undefined;
1368
+ }
1369
+ }
1370
+
1371
+ /**
1372
+ * Get orchestrator instance
1373
+ */
1374
+ export function getOrchestrator(): Orchestrator | undefined {
1375
+ return orchestratorInstance;
1376
+ }