agent-relay 2.3.2 → 2.3.5

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 (334) hide show
  1. package/README.md +1 -1
  2. package/dist/index.cjs +1 -1
  3. package/dist/src/cli/index.js +124 -7
  4. package/dist/src/cli/index.js.map +1 -1
  5. package/package.json +20 -26
  6. package/packages/acp-bridge/package.json +2 -2
  7. package/packages/bridge/package.json +7 -7
  8. package/packages/config/dist/cloud-config.d.ts +1 -1
  9. package/packages/config/dist/cloud-config.d.ts.map +1 -1
  10. package/packages/config/dist/cloud-config.js.map +1 -1
  11. package/packages/config/dist/schemas.d.ts +5 -5
  12. package/packages/config/dist/schemas.js +1 -1
  13. package/packages/config/dist/schemas.js.map +1 -1
  14. package/packages/config/package.json +2 -2
  15. package/packages/config/src/cloud-config.ts +2 -2
  16. package/packages/config/src/schemas.test.ts +48 -0
  17. package/packages/config/src/schemas.ts +1 -1
  18. package/packages/continuity/package.json +2 -2
  19. package/packages/daemon/package.json +12 -12
  20. package/packages/hooks/package.json +4 -4
  21. package/packages/mcp/package.json +5 -5
  22. package/packages/memory/package.json +2 -2
  23. package/packages/policy/package.json +2 -2
  24. package/packages/protocol/package.json +1 -1
  25. package/packages/resiliency/package.json +1 -1
  26. package/packages/sdk/dist/index.d.ts +1 -29
  27. package/packages/sdk/dist/index.d.ts.map +1 -1
  28. package/packages/sdk/dist/index.js +1 -38
  29. package/packages/sdk/dist/index.js.map +1 -1
  30. package/packages/sdk/package.json +4 -25
  31. package/packages/sdk/src/index.ts +1 -69
  32. package/packages/sdk-py/README.md +56 -0
  33. package/packages/sdk-py/pyproject.toml +23 -0
  34. package/packages/sdk-py/src/agent_relay/__init__.py +27 -0
  35. package/packages/sdk-py/src/agent_relay/builder.py +367 -0
  36. package/packages/sdk-py/src/agent_relay/types.py +92 -0
  37. package/packages/sdk-py/tests/__init__.py +0 -0
  38. package/packages/sdk-py/tests/test_builder.py +101 -0
  39. package/packages/sdk-ts/dist/__tests__/facade.test.d.ts +2 -0
  40. package/packages/sdk-ts/dist/__tests__/facade.test.d.ts.map +1 -0
  41. package/packages/sdk-ts/dist/__tests__/facade.test.js +257 -0
  42. package/packages/sdk-ts/dist/__tests__/facade.test.js.map +1 -0
  43. package/packages/sdk-ts/dist/__tests__/unit.test.d.ts +2 -0
  44. package/packages/sdk-ts/dist/__tests__/unit.test.d.ts.map +1 -0
  45. package/packages/sdk-ts/dist/__tests__/unit.test.js +124 -0
  46. package/packages/sdk-ts/dist/__tests__/unit.test.js.map +1 -0
  47. package/packages/sdk-ts/dist/client.d.ts +2 -0
  48. package/packages/sdk-ts/dist/client.d.ts.map +1 -1
  49. package/packages/sdk-ts/dist/client.js +2 -0
  50. package/packages/sdk-ts/dist/client.js.map +1 -1
  51. package/packages/sdk-ts/dist/index.d.ts +1 -0
  52. package/packages/sdk-ts/dist/index.d.ts.map +1 -1
  53. package/packages/sdk-ts/dist/index.js +1 -0
  54. package/packages/sdk-ts/dist/index.js.map +1 -1
  55. package/packages/sdk-ts/dist/protocol.d.ts +1 -0
  56. package/packages/sdk-ts/dist/protocol.d.ts.map +1 -1
  57. package/packages/sdk-ts/dist/relay.d.ts +44 -0
  58. package/packages/sdk-ts/dist/relay.d.ts.map +1 -1
  59. package/packages/sdk-ts/dist/relay.js +89 -11
  60. package/packages/sdk-ts/dist/relay.js.map +1 -1
  61. package/packages/sdk-ts/dist/relaycast.js +2 -2
  62. package/packages/sdk-ts/dist/relaycast.js.map +1 -1
  63. package/packages/sdk-ts/dist/workflows/barrier.d.ts +72 -0
  64. package/packages/sdk-ts/dist/workflows/barrier.d.ts.map +1 -0
  65. package/packages/sdk-ts/dist/workflows/barrier.js +162 -0
  66. package/packages/sdk-ts/dist/workflows/barrier.js.map +1 -0
  67. package/packages/sdk-ts/dist/workflows/builder.d.ts +101 -0
  68. package/packages/sdk-ts/dist/workflows/builder.d.ts.map +1 -0
  69. package/packages/sdk-ts/dist/workflows/builder.js +179 -0
  70. package/packages/sdk-ts/dist/workflows/builder.js.map +1 -0
  71. package/packages/sdk-ts/dist/workflows/cli.d.ts +10 -0
  72. package/packages/sdk-ts/dist/workflows/cli.d.ts.map +1 -0
  73. package/packages/sdk-ts/dist/workflows/cli.js +82 -0
  74. package/packages/sdk-ts/dist/workflows/cli.js.map +1 -0
  75. package/packages/sdk-ts/dist/workflows/coordinator.d.ts +68 -0
  76. package/packages/sdk-ts/dist/workflows/coordinator.d.ts.map +1 -0
  77. package/packages/sdk-ts/dist/workflows/coordinator.js +353 -0
  78. package/packages/sdk-ts/dist/workflows/coordinator.js.map +1 -0
  79. package/packages/sdk-ts/dist/workflows/index.d.ts +10 -0
  80. package/packages/sdk-ts/dist/workflows/index.d.ts.map +1 -0
  81. package/packages/sdk-ts/dist/workflows/index.js +10 -0
  82. package/packages/sdk-ts/dist/workflows/index.js.map +1 -0
  83. package/packages/sdk-ts/dist/workflows/memory-db.d.ts +17 -0
  84. package/packages/sdk-ts/dist/workflows/memory-db.d.ts.map +1 -0
  85. package/packages/sdk-ts/dist/workflows/memory-db.js +33 -0
  86. package/packages/sdk-ts/dist/workflows/memory-db.js.map +1 -0
  87. package/packages/sdk-ts/dist/workflows/run.d.ts +31 -0
  88. package/packages/sdk-ts/dist/workflows/run.d.ts.map +1 -0
  89. package/packages/sdk-ts/dist/workflows/run.js +24 -0
  90. package/packages/sdk-ts/dist/workflows/run.js.map +1 -0
  91. package/packages/sdk-ts/dist/workflows/runner.d.ts +119 -0
  92. package/packages/sdk-ts/dist/workflows/runner.d.ts.map +1 -0
  93. package/packages/sdk-ts/dist/workflows/runner.js +650 -0
  94. package/packages/sdk-ts/dist/workflows/runner.js.map +1 -0
  95. package/packages/sdk-ts/dist/workflows/state.d.ts +77 -0
  96. package/packages/sdk-ts/dist/workflows/state.d.ts.map +1 -0
  97. package/packages/sdk-ts/dist/workflows/state.js +140 -0
  98. package/packages/sdk-ts/dist/workflows/state.js.map +1 -0
  99. package/packages/sdk-ts/dist/workflows/templates.d.ts +47 -0
  100. package/packages/sdk-ts/dist/workflows/templates.d.ts.map +1 -0
  101. package/packages/sdk-ts/dist/workflows/templates.js +395 -0
  102. package/packages/sdk-ts/dist/workflows/templates.js.map +1 -0
  103. package/packages/sdk-ts/dist/workflows/types.d.ts +126 -0
  104. package/packages/sdk-ts/dist/workflows/types.d.ts.map +1 -0
  105. package/packages/sdk-ts/dist/workflows/types.js +8 -0
  106. package/packages/sdk-ts/dist/workflows/types.js.map +1 -0
  107. package/packages/sdk-ts/package.json +9 -3
  108. package/packages/sdk-ts/src/__tests__/error-scenarios.test.ts +682 -0
  109. package/packages/sdk-ts/src/__tests__/facade.test.ts +296 -0
  110. package/packages/sdk-ts/src/__tests__/swarm-coordinator.test.ts +416 -0
  111. package/packages/sdk-ts/src/__tests__/unit.test.ts +152 -0
  112. package/packages/sdk-ts/src/__tests__/workflow-runner.test.ts +333 -0
  113. package/packages/sdk-ts/src/client.ts +4 -0
  114. package/packages/sdk-ts/src/index.ts +1 -0
  115. package/packages/sdk-ts/src/protocol.ts +1 -1
  116. package/packages/sdk-ts/src/relay.ts +112 -11
  117. package/packages/sdk-ts/src/relaycast.ts +2 -2
  118. package/packages/sdk-ts/src/workflows/README.md +450 -0
  119. package/packages/sdk-ts/src/workflows/barrier.ts +254 -0
  120. package/packages/sdk-ts/src/workflows/builder.ts +241 -0
  121. package/packages/sdk-ts/src/workflows/builtin-templates/bug-fix.yaml +75 -0
  122. package/packages/sdk-ts/src/workflows/builtin-templates/code-review.yaml +82 -0
  123. package/packages/sdk-ts/src/workflows/builtin-templates/documentation.yaml +70 -0
  124. package/packages/sdk-ts/src/workflows/builtin-templates/feature-dev.yaml +76 -0
  125. package/packages/sdk-ts/src/workflows/builtin-templates/refactor.yaml +82 -0
  126. package/packages/sdk-ts/src/workflows/builtin-templates/security-audit.yaml +84 -0
  127. package/packages/sdk-ts/src/workflows/cli.ts +93 -0
  128. package/packages/sdk-ts/src/workflows/coordinator.ts +520 -0
  129. package/packages/sdk-ts/src/workflows/index.ts +9 -0
  130. package/packages/sdk-ts/src/workflows/memory-db.ts +39 -0
  131. package/packages/sdk-ts/src/workflows/run.ts +47 -0
  132. package/packages/sdk-ts/src/workflows/runner.ts +873 -0
  133. package/packages/sdk-ts/src/workflows/schema.json +321 -0
  134. package/packages/sdk-ts/src/workflows/state.ts +279 -0
  135. package/packages/sdk-ts/src/workflows/templates.ts +544 -0
  136. package/packages/sdk-ts/src/workflows/types.ts +178 -0
  137. package/packages/sdk-ts/tsconfig.json +6 -1
  138. package/packages/spawner/package.json +1 -1
  139. package/packages/state/package.json +1 -1
  140. package/packages/storage/package.json +2 -2
  141. package/packages/telemetry/package.json +1 -1
  142. package/packages/trajectory/package.json +2 -2
  143. package/packages/user-directory/package.json +2 -2
  144. package/packages/utils/package.json +3 -3
  145. package/packages/wrapper/package.json +5 -6
  146. package/scripts/postinstall.js +106 -2
  147. package/packages/api-types/.trajectories/active/traj_xbsvuzogscey.json +0 -15
  148. package/packages/api-types/.trajectories/index.json +0 -12
  149. package/packages/api-types/dist/index.d.ts +0 -21
  150. package/packages/api-types/dist/index.d.ts.map +0 -1
  151. package/packages/api-types/dist/index.js +0 -22
  152. package/packages/api-types/dist/index.js.map +0 -1
  153. package/packages/api-types/dist/schemas/agent.d.ts +0 -259
  154. package/packages/api-types/dist/schemas/agent.d.ts.map +0 -1
  155. package/packages/api-types/dist/schemas/agent.js +0 -102
  156. package/packages/api-types/dist/schemas/agent.js.map +0 -1
  157. package/packages/api-types/dist/schemas/api.d.ts +0 -290
  158. package/packages/api-types/dist/schemas/api.d.ts.map +0 -1
  159. package/packages/api-types/dist/schemas/api.js +0 -162
  160. package/packages/api-types/dist/schemas/api.js.map +0 -1
  161. package/packages/api-types/dist/schemas/decision.d.ts +0 -230
  162. package/packages/api-types/dist/schemas/decision.d.ts.map +0 -1
  163. package/packages/api-types/dist/schemas/decision.js +0 -104
  164. package/packages/api-types/dist/schemas/decision.js.map +0 -1
  165. package/packages/api-types/dist/schemas/fleet.d.ts +0 -615
  166. package/packages/api-types/dist/schemas/fleet.d.ts.map +0 -1
  167. package/packages/api-types/dist/schemas/fleet.js +0 -71
  168. package/packages/api-types/dist/schemas/fleet.js.map +0 -1
  169. package/packages/api-types/dist/schemas/history.d.ts +0 -180
  170. package/packages/api-types/dist/schemas/history.d.ts.map +0 -1
  171. package/packages/api-types/dist/schemas/history.js +0 -72
  172. package/packages/api-types/dist/schemas/history.js.map +0 -1
  173. package/packages/api-types/dist/schemas/index.d.ts +0 -14
  174. package/packages/api-types/dist/schemas/index.d.ts.map +0 -1
  175. package/packages/api-types/dist/schemas/index.js +0 -22
  176. package/packages/api-types/dist/schemas/index.js.map +0 -1
  177. package/packages/api-types/dist/schemas/message.d.ts +0 -456
  178. package/packages/api-types/dist/schemas/message.d.ts.map +0 -1
  179. package/packages/api-types/dist/schemas/message.js +0 -88
  180. package/packages/api-types/dist/schemas/message.js.map +0 -1
  181. package/packages/api-types/dist/schemas/session.d.ts +0 -60
  182. package/packages/api-types/dist/schemas/session.d.ts.map +0 -1
  183. package/packages/api-types/dist/schemas/session.js +0 -36
  184. package/packages/api-types/dist/schemas/session.js.map +0 -1
  185. package/packages/api-types/dist/schemas/task.d.ts +0 -111
  186. package/packages/api-types/dist/schemas/task.d.ts.map +0 -1
  187. package/packages/api-types/dist/schemas/task.js +0 -64
  188. package/packages/api-types/dist/schemas/task.js.map +0 -1
  189. package/packages/api-types/package.json +0 -61
  190. package/packages/api-types/scripts/generate-openapi.ts +0 -106
  191. package/packages/api-types/src/index.ts +0 -22
  192. package/packages/api-types/src/schemas/agent.test.ts +0 -164
  193. package/packages/api-types/src/schemas/agent.ts +0 -110
  194. package/packages/api-types/src/schemas/api.test.ts +0 -372
  195. package/packages/api-types/src/schemas/api.ts +0 -194
  196. package/packages/api-types/src/schemas/decision.test.ts +0 -324
  197. package/packages/api-types/src/schemas/decision.ts +0 -136
  198. package/packages/api-types/src/schemas/fleet.test.ts +0 -212
  199. package/packages/api-types/src/schemas/fleet.ts +0 -83
  200. package/packages/api-types/src/schemas/history.test.ts +0 -242
  201. package/packages/api-types/src/schemas/history.ts +0 -84
  202. package/packages/api-types/src/schemas/index.ts +0 -148
  203. package/packages/api-types/src/schemas/message.test.ts +0 -192
  204. package/packages/api-types/src/schemas/message.ts +0 -98
  205. package/packages/api-types/src/schemas/session.test.ts +0 -104
  206. package/packages/api-types/src/schemas/session.ts +0 -40
  207. package/packages/api-types/src/schemas/task.test.ts +0 -192
  208. package/packages/api-types/src/schemas/task.ts +0 -78
  209. package/packages/api-types/tsconfig.json +0 -19
  210. package/packages/api-types/vitest.config.ts +0 -9
  211. package/packages/benchmark/README.md +0 -200
  212. package/packages/benchmark/datasets/coding-tasks.yaml +0 -127
  213. package/packages/benchmark/datasets/coordination-tasks.yaml +0 -122
  214. package/packages/benchmark/datasets/quick-test.yaml +0 -20
  215. package/packages/benchmark/dist/benchmark.d.ts +0 -47
  216. package/packages/benchmark/dist/benchmark.d.ts.map +0 -1
  217. package/packages/benchmark/dist/benchmark.js +0 -224
  218. package/packages/benchmark/dist/benchmark.js.map +0 -1
  219. package/packages/benchmark/dist/cli.d.ts +0 -8
  220. package/packages/benchmark/dist/cli.d.ts.map +0 -1
  221. package/packages/benchmark/dist/cli.js +0 -185
  222. package/packages/benchmark/dist/cli.js.map +0 -1
  223. package/packages/benchmark/dist/harbor.d.ts +0 -53
  224. package/packages/benchmark/dist/harbor.d.ts.map +0 -1
  225. package/packages/benchmark/dist/harbor.js +0 -127
  226. package/packages/benchmark/dist/harbor.js.map +0 -1
  227. package/packages/benchmark/dist/index.d.ts +0 -48
  228. package/packages/benchmark/dist/index.d.ts.map +0 -1
  229. package/packages/benchmark/dist/index.js +0 -50
  230. package/packages/benchmark/dist/index.js.map +0 -1
  231. package/packages/benchmark/dist/runners/base.d.ts +0 -63
  232. package/packages/benchmark/dist/runners/base.d.ts.map +0 -1
  233. package/packages/benchmark/dist/runners/base.js +0 -156
  234. package/packages/benchmark/dist/runners/base.js.map +0 -1
  235. package/packages/benchmark/dist/runners/index.d.ts +0 -10
  236. package/packages/benchmark/dist/runners/index.d.ts.map +0 -1
  237. package/packages/benchmark/dist/runners/index.js +0 -10
  238. package/packages/benchmark/dist/runners/index.js.map +0 -1
  239. package/packages/benchmark/dist/runners/single.d.ts +0 -19
  240. package/packages/benchmark/dist/runners/single.d.ts.map +0 -1
  241. package/packages/benchmark/dist/runners/single.js +0 -111
  242. package/packages/benchmark/dist/runners/single.js.map +0 -1
  243. package/packages/benchmark/dist/runners/subagent.d.ts +0 -32
  244. package/packages/benchmark/dist/runners/subagent.d.ts.map +0 -1
  245. package/packages/benchmark/dist/runners/subagent.js +0 -212
  246. package/packages/benchmark/dist/runners/subagent.js.map +0 -1
  247. package/packages/benchmark/dist/runners/swarm.d.ts +0 -36
  248. package/packages/benchmark/dist/runners/swarm.d.ts.map +0 -1
  249. package/packages/benchmark/dist/runners/swarm.js +0 -273
  250. package/packages/benchmark/dist/runners/swarm.js.map +0 -1
  251. package/packages/benchmark/dist/types.d.ts +0 -178
  252. package/packages/benchmark/dist/types.d.ts.map +0 -1
  253. package/packages/benchmark/dist/types.js +0 -16
  254. package/packages/benchmark/dist/types.js.map +0 -1
  255. package/packages/benchmark/package.json +0 -80
  256. package/packages/benchmark/src/benchmark.ts +0 -298
  257. package/packages/benchmark/src/cli.ts +0 -240
  258. package/packages/benchmark/src/harbor.ts +0 -170
  259. package/packages/benchmark/src/index.ts +0 -73
  260. package/packages/benchmark/src/runners/base.ts +0 -205
  261. package/packages/benchmark/src/runners/index.ts +0 -10
  262. package/packages/benchmark/src/runners/single.ts +0 -121
  263. package/packages/benchmark/src/runners/subagent.ts +0 -240
  264. package/packages/benchmark/src/runners/swarm.ts +0 -326
  265. package/packages/benchmark/src/types.ts +0 -205
  266. package/packages/benchmark/tsconfig.json +0 -20
  267. package/packages/cli-tester/README.md +0 -277
  268. package/packages/cli-tester/dist/index.d.ts +0 -21
  269. package/packages/cli-tester/dist/index.d.ts.map +0 -1
  270. package/packages/cli-tester/dist/index.js +0 -21
  271. package/packages/cli-tester/dist/index.js.map +0 -1
  272. package/packages/cli-tester/dist/utils/credential-check.d.ts +0 -56
  273. package/packages/cli-tester/dist/utils/credential-check.d.ts.map +0 -1
  274. package/packages/cli-tester/dist/utils/credential-check.js +0 -230
  275. package/packages/cli-tester/dist/utils/credential-check.js.map +0 -1
  276. package/packages/cli-tester/dist/utils/socket-client.d.ts +0 -76
  277. package/packages/cli-tester/dist/utils/socket-client.d.ts.map +0 -1
  278. package/packages/cli-tester/dist/utils/socket-client.js +0 -153
  279. package/packages/cli-tester/dist/utils/socket-client.js.map +0 -1
  280. package/packages/cli-tester/docker/Dockerfile +0 -61
  281. package/packages/cli-tester/docker/docker-compose.yml +0 -71
  282. package/packages/cli-tester/docker/entrypoint.sh +0 -58
  283. package/packages/cli-tester/package.json +0 -32
  284. package/packages/cli-tester/scripts/clear-auth.sh +0 -101
  285. package/packages/cli-tester/scripts/inject-message.sh +0 -42
  286. package/packages/cli-tester/scripts/start.sh +0 -71
  287. package/packages/cli-tester/scripts/test-cli.sh +0 -56
  288. package/packages/cli-tester/scripts/test-full-spawn.sh +0 -238
  289. package/packages/cli-tester/scripts/test-registration.sh +0 -182
  290. package/packages/cli-tester/scripts/test-setup-flow.sh +0 -202
  291. package/packages/cli-tester/scripts/test-spawn.sh +0 -140
  292. package/packages/cli-tester/scripts/test-with-daemon.sh +0 -247
  293. package/packages/cli-tester/scripts/verify-auth.sh +0 -112
  294. package/packages/cli-tester/src/index.ts +0 -40
  295. package/packages/cli-tester/src/utils/credential-check.ts +0 -284
  296. package/packages/cli-tester/src/utils/socket-client.ts +0 -211
  297. package/packages/cli-tester/tests/credential-check.test.ts +0 -56
  298. package/packages/cli-tester/tsconfig.json +0 -11
  299. package/packages/sdk/dist/browser-client.d.ts +0 -212
  300. package/packages/sdk/dist/browser-client.d.ts.map +0 -1
  301. package/packages/sdk/dist/browser-client.js +0 -750
  302. package/packages/sdk/dist/browser-client.js.map +0 -1
  303. package/packages/sdk/dist/browser-framing.d.ts +0 -46
  304. package/packages/sdk/dist/browser-framing.d.ts.map +0 -1
  305. package/packages/sdk/dist/browser-framing.js +0 -122
  306. package/packages/sdk/dist/browser-framing.js.map +0 -1
  307. package/packages/sdk/dist/standalone.d.ts +0 -89
  308. package/packages/sdk/dist/standalone.d.ts.map +0 -1
  309. package/packages/sdk/dist/standalone.js +0 -131
  310. package/packages/sdk/dist/standalone.js.map +0 -1
  311. package/packages/sdk/dist/transports/index.d.ts +0 -92
  312. package/packages/sdk/dist/transports/index.d.ts.map +0 -1
  313. package/packages/sdk/dist/transports/index.js +0 -129
  314. package/packages/sdk/dist/transports/index.js.map +0 -1
  315. package/packages/sdk/dist/transports/socket-transport.d.ts +0 -30
  316. package/packages/sdk/dist/transports/socket-transport.d.ts.map +0 -1
  317. package/packages/sdk/dist/transports/socket-transport.js +0 -94
  318. package/packages/sdk/dist/transports/socket-transport.js.map +0 -1
  319. package/packages/sdk/dist/transports/types.d.ts +0 -69
  320. package/packages/sdk/dist/transports/types.d.ts.map +0 -1
  321. package/packages/sdk/dist/transports/types.js +0 -10
  322. package/packages/sdk/dist/transports/types.js.map +0 -1
  323. package/packages/sdk/dist/transports/websocket-transport.d.ts +0 -55
  324. package/packages/sdk/dist/transports/websocket-transport.d.ts.map +0 -1
  325. package/packages/sdk/dist/transports/websocket-transport.js +0 -180
  326. package/packages/sdk/dist/transports/websocket-transport.js.map +0 -1
  327. package/packages/sdk/src/browser-client.ts +0 -985
  328. package/packages/sdk/src/browser-framing.test.ts +0 -115
  329. package/packages/sdk/src/browser-framing.ts +0 -150
  330. package/packages/sdk/src/standalone.ts +0 -183
  331. package/packages/sdk/src/transports/index.ts +0 -197
  332. package/packages/sdk/src/transports/socket-transport.ts +0 -115
  333. package/packages/sdk/src/transports/types.ts +0 -77
  334. package/packages/sdk/src/transports/websocket-transport.ts +0 -245
@@ -0,0 +1,416 @@
1
+ /**
2
+ * SwarmCoordinator integration tests.
3
+ *
4
+ * Tests pattern selection, topology resolution, run lifecycle,
5
+ * and step management with a mocked DbClient.
6
+ */
7
+
8
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
9
+ import { SwarmCoordinator } from '../workflows/coordinator.js';
10
+ import type { DbClient } from '../workflows/coordinator.js';
11
+ import type { RelayYamlConfig, WorkflowRunRow, WorkflowStepRow } from '../workflows/types.js';
12
+
13
+ // ── Helpers ──────────────────────────────────────────────────────────────────
14
+
15
+ function makeDb(): DbClient {
16
+ return {
17
+ query: vi.fn().mockResolvedValue({ rows: [] }),
18
+ };
19
+ }
20
+
21
+ function makeConfig(overrides: Partial<RelayYamlConfig> = {}): RelayYamlConfig {
22
+ return {
23
+ version: '1',
24
+ name: 'test-workflow',
25
+ swarm: { pattern: 'fan-out' },
26
+ agents: [
27
+ { name: 'leader', cli: 'claude', role: 'lead' },
28
+ { name: 'worker-1', cli: 'claude' },
29
+ { name: 'worker-2', cli: 'codex' },
30
+ ],
31
+ ...overrides,
32
+ };
33
+ }
34
+
35
+ function makeRunRow(overrides: Partial<WorkflowRunRow> = {}): WorkflowRunRow {
36
+ const now = new Date().toISOString();
37
+ return {
38
+ id: 'run_test_1',
39
+ workspaceId: 'ws-1',
40
+ workflowName: 'test-workflow',
41
+ pattern: 'fan-out',
42
+ status: 'pending',
43
+ config: makeConfig(),
44
+ startedAt: now,
45
+ createdAt: now,
46
+ updatedAt: now,
47
+ ...overrides,
48
+ };
49
+ }
50
+
51
+ function makeStepRow(overrides: Partial<WorkflowStepRow> = {}): WorkflowStepRow {
52
+ const now = new Date().toISOString();
53
+ return {
54
+ id: 'step_test_1',
55
+ runId: 'run_test_1',
56
+ stepName: 'step-1',
57
+ agentName: 'worker-1',
58
+ status: 'pending',
59
+ task: 'Do something',
60
+ dependsOn: [],
61
+ retryCount: 0,
62
+ createdAt: now,
63
+ updatedAt: now,
64
+ ...overrides,
65
+ };
66
+ }
67
+
68
+ // ── Tests ────────────────────────────────────────────────────────────────────
69
+
70
+ describe('SwarmCoordinator', () => {
71
+ let db: DbClient;
72
+ let coordinator: SwarmCoordinator;
73
+
74
+ beforeEach(() => {
75
+ vi.clearAllMocks();
76
+ db = makeDb();
77
+ coordinator = new SwarmCoordinator(db);
78
+ });
79
+
80
+ // ── Pattern selection ──────────────────────────────────────────────────
81
+
82
+ describe('selectPattern', () => {
83
+ it('should return explicit pattern from config', () => {
84
+ expect(coordinator.selectPattern(makeConfig({ swarm: { pattern: 'pipeline' } }))).toBe('pipeline');
85
+ });
86
+
87
+ it('should auto-select dag when steps have dependencies', () => {
88
+ const config = makeConfig({
89
+ swarm: { pattern: undefined as unknown as string } as any,
90
+ workflows: [
91
+ {
92
+ name: 'wf',
93
+ steps: [
94
+ { name: 's1', agent: 'worker-1', task: 'x' },
95
+ { name: 's2', agent: 'worker-2', task: 'y', dependsOn: ['s1'] },
96
+ ],
97
+ },
98
+ ],
99
+ });
100
+ // With pattern set explicitly, it returns it; with undefined it falls through heuristics
101
+ // Since config.swarm.pattern is undefined (truthy check fails), heuristics kick in
102
+ config.swarm.pattern = '' as any;
103
+ const pattern = coordinator.selectPattern(config);
104
+ expect(pattern).toBe('dag');
105
+ });
106
+
107
+ it('should auto-select consensus when consensusStrategy is set', () => {
108
+ const config = makeConfig({
109
+ swarm: { pattern: '' as any },
110
+ coordination: { consensusStrategy: 'majority' },
111
+ });
112
+ expect(coordinator.selectPattern(config)).toBe('consensus');
113
+ });
114
+ });
115
+
116
+ // ── Topology resolution ────────────────────────────────────────────────
117
+
118
+ describe('resolveTopology', () => {
119
+ it('should build fan-out topology with hub', () => {
120
+ const topology = coordinator.resolveTopology(makeConfig());
121
+ expect(topology.pattern).toBe('fan-out');
122
+ expect(topology.hub).toBe('leader');
123
+ expect(topology.edges.get('leader')).toEqual(['worker-1', 'worker-2']);
124
+ expect(topology.edges.get('worker-1')).toEqual(['leader']);
125
+ });
126
+
127
+ it('should build pipeline topology in step order', () => {
128
+ const config = makeConfig({
129
+ swarm: { pattern: 'pipeline' },
130
+ workflows: [
131
+ {
132
+ name: 'wf',
133
+ steps: [
134
+ { name: 's1', agent: 'worker-1', task: 'step 1' },
135
+ { name: 's2', agent: 'worker-2', task: 'step 2' },
136
+ { name: 's3', agent: 'leader', task: 'step 3' },
137
+ ],
138
+ },
139
+ ],
140
+ });
141
+ const topology = coordinator.resolveTopology(config);
142
+ expect(topology.pattern).toBe('pipeline');
143
+ expect(topology.pipelineOrder).toEqual(['worker-1', 'worker-2', 'leader']);
144
+ expect(topology.edges.get('worker-1')).toEqual(['worker-2']);
145
+ expect(topology.edges.get('leader')).toEqual([]);
146
+ });
147
+
148
+ it('should build hub-spoke topology', () => {
149
+ const config = makeConfig({ swarm: { pattern: 'hub-spoke' } });
150
+ const topology = coordinator.resolveTopology(config);
151
+ expect(topology.hub).toBe('leader');
152
+ expect(topology.edges.get('leader')).toContain('worker-1');
153
+ expect(topology.edges.get('worker-1')).toEqual(['leader']);
154
+ });
155
+
156
+ it('should build mesh topology for consensus', () => {
157
+ const config = makeConfig({ swarm: { pattern: 'consensus' } });
158
+ const topology = coordinator.resolveTopology(config);
159
+ expect(topology.edges.get('leader')).toContain('worker-1');
160
+ expect(topology.edges.get('leader')).toContain('worker-2');
161
+ expect(topology.edges.get('worker-1')).toContain('leader');
162
+ });
163
+
164
+ it('should build DAG topology from step dependencies', () => {
165
+ const config = makeConfig({
166
+ swarm: { pattern: 'dag' },
167
+ workflows: [
168
+ {
169
+ name: 'wf',
170
+ steps: [
171
+ { name: 's1', agent: 'worker-1', task: 'x' },
172
+ { name: 's2', agent: 'worker-2', task: 'y', dependsOn: ['s1'] },
173
+ ],
174
+ },
175
+ ],
176
+ });
177
+ const topology = coordinator.resolveTopology(config);
178
+ expect(topology.pattern).toBe('dag');
179
+ expect(topology.edges.get('worker-1')).toContain('worker-2');
180
+ });
181
+
182
+ it('should build hierarchical topology', () => {
183
+ const config = makeConfig({ swarm: { pattern: 'hierarchical' } });
184
+ const topology = coordinator.resolveTopology(config);
185
+ expect(topology.hub).toBe('leader');
186
+ expect(topology.edges.get('leader')).toContain('worker-1');
187
+ });
188
+
189
+ it('should build cascade topology', () => {
190
+ const config = makeConfig({ swarm: { pattern: 'cascade' } });
191
+ const topology = coordinator.resolveTopology(config);
192
+ expect(topology.pipelineOrder).toEqual(['leader', 'worker-1', 'worker-2']);
193
+ });
194
+ });
195
+
196
+ // ── Run lifecycle ──────────────────────────────────────────────────────
197
+
198
+ describe('createRun', () => {
199
+ it('should insert a run and emit run:created', async () => {
200
+ const run = makeRunRow();
201
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [run] });
202
+
203
+ const spy = vi.fn();
204
+ coordinator.on('run:created', spy);
205
+
206
+ const result = await coordinator.createRun('ws-1', makeConfig());
207
+ expect(result).toEqual(run);
208
+ expect(spy).toHaveBeenCalledWith(run);
209
+ expect(db.query).toHaveBeenCalledOnce();
210
+ });
211
+ });
212
+
213
+ describe('startRun', () => {
214
+ it('should transition pending run to running', async () => {
215
+ const run = makeRunRow({ status: 'running' });
216
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [run] });
217
+
218
+ const spy = vi.fn();
219
+ coordinator.on('run:started', spy);
220
+
221
+ const result = await coordinator.startRun('run_test_1');
222
+ expect(result.status).toBe('running');
223
+ expect(spy).toHaveBeenCalledWith(run);
224
+ });
225
+
226
+ it('should throw when run not found', async () => {
227
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [] });
228
+ await expect(coordinator.startRun('nonexistent')).rejects.toThrow('not found or not in pending state');
229
+ });
230
+ });
231
+
232
+ describe('completeRun', () => {
233
+ it('should transition run to completed and emit event', async () => {
234
+ const run = makeRunRow({ status: 'completed' });
235
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [run] });
236
+
237
+ const spy = vi.fn();
238
+ coordinator.on('run:completed', spy);
239
+
240
+ const result = await coordinator.completeRun('run_test_1', { result: 'ok' });
241
+ expect(result.status).toBe('completed');
242
+ expect(spy).toHaveBeenCalledWith(run);
243
+ });
244
+
245
+ it('should throw when run not found', async () => {
246
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [] });
247
+ await expect(coordinator.completeRun('nonexistent')).rejects.toThrow('not found');
248
+ });
249
+ });
250
+
251
+ describe('failRun', () => {
252
+ it('should transition run to failed with error', async () => {
253
+ const run = makeRunRow({ status: 'failed', error: 'boom' });
254
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [run] });
255
+
256
+ const spy = vi.fn();
257
+ coordinator.on('run:failed', spy);
258
+
259
+ await coordinator.failRun('run_test_1', 'boom');
260
+ expect(spy).toHaveBeenCalledWith(run);
261
+ });
262
+ });
263
+
264
+ describe('cancelRun', () => {
265
+ it('should transition run to cancelled', async () => {
266
+ const run = makeRunRow({ status: 'cancelled' });
267
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [run] });
268
+
269
+ const spy = vi.fn();
270
+ coordinator.on('run:cancelled', spy);
271
+
272
+ const result = await coordinator.cancelRun('run_test_1');
273
+ expect(result.status).toBe('cancelled');
274
+ });
275
+ });
276
+
277
+ // ── Step management ────────────────────────────────────────────────────
278
+
279
+ describe('createSteps', () => {
280
+ it('should create steps from workflow config', async () => {
281
+ const step = makeStepRow();
282
+ vi.mocked(db.query).mockResolvedValue({ rows: [step] });
283
+
284
+ const config = makeConfig({
285
+ workflows: [
286
+ {
287
+ name: 'wf',
288
+ steps: [
289
+ { name: 's1', agent: 'worker-1', task: 'x' },
290
+ { name: 's2', agent: 'worker-2', task: 'y' },
291
+ ],
292
+ },
293
+ ],
294
+ });
295
+
296
+ const steps = await coordinator.createSteps('run_1', config);
297
+ expect(steps).toHaveLength(2);
298
+ expect(db.query).toHaveBeenCalledTimes(2);
299
+ });
300
+ });
301
+
302
+ describe('startStep', () => {
303
+ it('should transition step to running and emit event', async () => {
304
+ const step = makeStepRow({ status: 'running' });
305
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [step] });
306
+
307
+ const spy = vi.fn();
308
+ coordinator.on('step:started', spy);
309
+
310
+ const result = await coordinator.startStep('step_1');
311
+ expect(result.status).toBe('running');
312
+ expect(spy).toHaveBeenCalledWith(step);
313
+ });
314
+
315
+ it('should throw for non-pending step', async () => {
316
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [] });
317
+ await expect(coordinator.startStep('bad')).rejects.toThrow('not found or not in pending state');
318
+ });
319
+ });
320
+
321
+ describe('completeStep', () => {
322
+ it('should transition step to completed with output', async () => {
323
+ const step = makeStepRow({ status: 'completed', output: 'result data' });
324
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [step] });
325
+
326
+ const spy = vi.fn();
327
+ coordinator.on('step:completed', spy);
328
+
329
+ const result = await coordinator.completeStep('step_1', 'result data');
330
+ expect(result.output).toBe('result data');
331
+ expect(spy).toHaveBeenCalledWith(step);
332
+ });
333
+ });
334
+
335
+ describe('failStep', () => {
336
+ it('should transition step to failed with error', async () => {
337
+ const step = makeStepRow({ status: 'failed', error: 'timeout' });
338
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [step] });
339
+
340
+ const spy = vi.fn();
341
+ coordinator.on('step:failed', spy);
342
+
343
+ const result = await coordinator.failStep('step_1', 'timeout');
344
+ expect(result.error).toBe('timeout');
345
+ });
346
+ });
347
+
348
+ describe('skipStep', () => {
349
+ it('should mark step as skipped', async () => {
350
+ const step = makeStepRow({ status: 'skipped' });
351
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [step] });
352
+
353
+ const result = await coordinator.skipStep('step_1');
354
+ expect(result.status).toBe('skipped');
355
+ });
356
+ });
357
+
358
+ // ── Queries ────────────────────────────────────────────────────────────
359
+
360
+ describe('getRun', () => {
361
+ it('should return run or null', async () => {
362
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [] });
363
+ expect(await coordinator.getRun('nonexistent')).toBeNull();
364
+
365
+ const run = makeRunRow();
366
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [run] });
367
+ expect(await coordinator.getRun('run_test_1')).toEqual(run);
368
+ });
369
+ });
370
+
371
+ describe('getReadySteps', () => {
372
+ it('should return pending steps with all dependencies completed', async () => {
373
+ const steps: WorkflowStepRow[] = [
374
+ makeStepRow({ id: 's1', stepName: 'step-1', status: 'completed', dependsOn: [] }),
375
+ makeStepRow({ id: 's2', stepName: 'step-2', status: 'pending', dependsOn: ['step-1'] }),
376
+ makeStepRow({ id: 's3', stepName: 'step-3', status: 'pending', dependsOn: ['step-2'] }),
377
+ ];
378
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: steps });
379
+
380
+ const ready = await coordinator.getReadySteps('run_test_1');
381
+ expect(ready).toHaveLength(1);
382
+ expect(ready[0].stepName).toBe('step-2');
383
+ });
384
+
385
+ it('should return all pending steps with no dependencies', async () => {
386
+ const steps: WorkflowStepRow[] = [
387
+ makeStepRow({ id: 's1', stepName: 'a', status: 'pending', dependsOn: [] }),
388
+ makeStepRow({ id: 's2', stepName: 'b', status: 'pending', dependsOn: [] }),
389
+ ];
390
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: steps });
391
+
392
+ const ready = await coordinator.getReadySteps('run_test_1');
393
+ expect(ready).toHaveLength(2);
394
+ });
395
+ });
396
+
397
+ describe('getRunsByWorkspace', () => {
398
+ it('should query by workspace with optional status filter', async () => {
399
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [] });
400
+ await coordinator.getRunsByWorkspace('ws-1', 'running');
401
+ expect(db.query).toHaveBeenCalledWith(
402
+ expect.stringContaining('status = $2'),
403
+ ['ws-1', 'running'],
404
+ );
405
+ });
406
+
407
+ it('should query without status filter', async () => {
408
+ vi.mocked(db.query).mockResolvedValueOnce({ rows: [] });
409
+ await coordinator.getRunsByWorkspace('ws-1');
410
+ expect(db.query).toHaveBeenCalledWith(
411
+ expect.not.stringContaining('status ='),
412
+ ['ws-1'],
413
+ );
414
+ });
415
+ });
416
+ });
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Unit tests — no broker binary or RELAY_API_KEY required.
3
+ *
4
+ * Run:
5
+ * npm run build && node --test dist/__tests__/unit.test.js
6
+ */
7
+ import assert from "node:assert/strict";
8
+ import { join, sep } from "node:path";
9
+ import { mkdtemp, writeFile, rm } from "node:fs/promises";
10
+ import { tmpdir } from "node:os";
11
+ import test from "node:test";
12
+
13
+ import { AgentRelay, type Agent } from "../relay.js";
14
+ import { getLogs, listLoggedAgents } from "../logs.js";
15
+
16
+ // ── waitForAny ──────────────────────────────────────────────────────────────
17
+
18
+ function makeFakeAgent(
19
+ name: string,
20
+ exitAfterMs?: number,
21
+ ): Agent {
22
+ let resolveExit: ((reason: "exited" | "released") => void) | undefined;
23
+ const exitPromise = new Promise<"exited" | "released">((resolve) => {
24
+ resolveExit = resolve;
25
+ });
26
+
27
+ if (exitAfterMs !== undefined) {
28
+ setTimeout(() => resolveExit?.("exited"), exitAfterMs);
29
+ }
30
+
31
+ return {
32
+ name,
33
+ runtime: "pty",
34
+ channels: ["general"],
35
+ exitCode: undefined,
36
+ exitSignal: undefined,
37
+ async release() {
38
+ resolveExit?.("released");
39
+ },
40
+ waitForExit(timeoutMs?: number) {
41
+ if (timeoutMs === 0) return Promise.resolve("timeout" as const);
42
+ if (timeoutMs !== undefined) {
43
+ return Promise.race([
44
+ exitPromise,
45
+ new Promise<"timeout">((resolve) =>
46
+ setTimeout(() => resolve("timeout"), timeoutMs),
47
+ ),
48
+ ]);
49
+ }
50
+ return exitPromise;
51
+ },
52
+ async sendMessage() {
53
+ return { eventId: "fake", from: name, to: "", text: "" };
54
+ },
55
+ };
56
+ }
57
+
58
+ test("waitForAny: returns first agent to exit", async () => {
59
+ const fast = makeFakeAgent("fast", 50);
60
+ const slow = makeFakeAgent("slow", 5_000);
61
+
62
+ const { agent, result } = await AgentRelay.waitForAny([fast, slow], 3_000);
63
+ assert.equal(agent.name, "fast");
64
+ assert.equal(result, "exited");
65
+ });
66
+
67
+ test("waitForAny: returns timeout when no agent exits", async () => {
68
+ const a = makeFakeAgent("a");
69
+ const b = makeFakeAgent("b");
70
+
71
+ const { result } = await AgentRelay.waitForAny([a, b], 100);
72
+ assert.equal(result, "timeout");
73
+ });
74
+
75
+ test("waitForAny: handles released agent", async () => {
76
+ const agent = makeFakeAgent("releasable");
77
+
78
+ // Release after 50ms
79
+ setTimeout(() => agent.release(), 50);
80
+
81
+ const { agent: resolved, result } = await AgentRelay.waitForAny([agent], 3_000);
82
+ assert.equal(resolved.name, "releasable");
83
+ assert.equal(result, "released");
84
+ });
85
+
86
+ test("waitForAny: throws on empty agents array", async () => {
87
+ await assert.rejects(
88
+ () => AgentRelay.waitForAny([]),
89
+ { message: "waitForAny requires at least one agent" },
90
+ );
91
+ });
92
+
93
+ // ── getLogs ──────────────────────────────────────────────────────────────────
94
+
95
+ test("getLogs: rejects path traversal", async () => {
96
+ const result = await getLogs("../../etc/passwd", {
97
+ logsDir: "/tmp/test-logs",
98
+ });
99
+ assert.equal(result.found, false);
100
+ assert.equal(result.content, "");
101
+ });
102
+
103
+ test("getLogs: returns not found for missing agent", async () => {
104
+ const dir = await mkdtemp(join(tmpdir(), "relay-test-logs-"));
105
+
106
+ try {
107
+ const result = await getLogs("nonexistent", { logsDir: dir });
108
+ assert.equal(result.found, false);
109
+ assert.equal(result.content, "");
110
+ } finally {
111
+ await rm(dir, { recursive: true, force: true });
112
+ }
113
+ });
114
+
115
+ test("getLogs: reads content from log file", async () => {
116
+ const dir = await mkdtemp(join(tmpdir(), "relay-test-logs-"));
117
+
118
+ try {
119
+ const logContent = "line1\nline2\nline3\n";
120
+ await writeFile(join(dir, "TestAgent.log"), logContent);
121
+
122
+ const result = await getLogs("TestAgent", { logsDir: dir, lines: 2 });
123
+ assert.equal(result.found, true);
124
+ assert.equal(result.content, "line2\nline3");
125
+ assert.equal(result.lineCount, 2);
126
+ } finally {
127
+ await rm(dir, { recursive: true, force: true });
128
+ }
129
+ });
130
+
131
+ test("listLoggedAgents: lists agent names from log files", async () => {
132
+ const dir = await mkdtemp(join(tmpdir(), "relay-test-logs-"));
133
+
134
+ try {
135
+ await writeFile(join(dir, "Alice.log"), "hello\n");
136
+ await writeFile(join(dir, "Bob.log"), "world\n");
137
+ await writeFile(join(dir, "not-a-log.txt"), "skip\n");
138
+
139
+ const agents = await listLoggedAgents(dir);
140
+ assert.ok(agents.includes("Alice"));
141
+ assert.ok(agents.includes("Bob"));
142
+ assert.ok(!agents.includes("not-a-log"));
143
+ } finally {
144
+ await rm(dir, { recursive: true, force: true });
145
+ }
146
+ });
147
+
148
+ test("listLoggedAgents: returns empty for missing directory", async () => {
149
+ const agents = await listLoggedAgents("/tmp/definitely-nonexistent-dir");
150
+ assert.deepEqual(agents, []);
151
+ });
152
+