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 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/workflows/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,650 @@
1
+ /**
2
+ * WorkflowRunner — parses relay.yaml, validates config, resolves templates,
3
+ * executes steps (sequential/parallel/DAG), runs verification checks,
4
+ * persists state to DB, and supports pause/resume/abort with retries.
5
+ */
6
+ import { randomBytes } from 'node:crypto';
7
+ import { existsSync } from 'node:fs';
8
+ import { readFile } from 'node:fs/promises';
9
+ import path from 'node:path';
10
+ import { parse as parseYaml } from 'yaml';
11
+ import { InMemoryWorkflowDb } from './memory-db.js';
12
+ // ── AgentRelay SDK imports ──────────────────────────────────────────────────
13
+ // Import from sub-paths to avoid pulling in the full @relaycast/sdk dependency.
14
+ import { AgentRelay } from '../relay.js';
15
+ // ── WorkflowRunner ──────────────────────────────────────────────────────────
16
+ export class WorkflowRunner {
17
+ db;
18
+ workspaceId;
19
+ relayOptions;
20
+ cwd;
21
+ summaryDir;
22
+ relay;
23
+ abortController;
24
+ paused = false;
25
+ pauseResolver;
26
+ listeners = [];
27
+ constructor(options = {}) {
28
+ this.db = options.db ?? new InMemoryWorkflowDb();
29
+ this.workspaceId = options.workspaceId ?? 'local';
30
+ this.relayOptions = options.relay ?? {};
31
+ this.cwd = options.cwd ?? process.cwd();
32
+ this.summaryDir = options.summaryDir ?? path.join(this.cwd, '.relay', 'summaries');
33
+ }
34
+ // ── Event subscription ──────────────────────────────────────────────────
35
+ on(listener) {
36
+ this.listeners.push(listener);
37
+ return () => {
38
+ this.listeners = this.listeners.filter((l) => l !== listener);
39
+ };
40
+ }
41
+ emit(event) {
42
+ for (const listener of this.listeners) {
43
+ listener(event);
44
+ }
45
+ }
46
+ // ── Parsing & validation ────────────────────────────────────────────────
47
+ /** Parse a relay.yaml file from disk. */
48
+ async parseYamlFile(filePath) {
49
+ const absPath = path.resolve(this.cwd, filePath);
50
+ const raw = await readFile(absPath, 'utf-8');
51
+ return this.parseYamlString(raw, absPath);
52
+ }
53
+ /** Parse a relay.yaml string. */
54
+ parseYamlString(raw, source = '<string>') {
55
+ const parsed = parseYaml(raw);
56
+ this.validateConfig(parsed, source);
57
+ return parsed;
58
+ }
59
+ /** Validate a config object against the RelayYamlConfig shape. */
60
+ validateConfig(config, source = '<config>') {
61
+ if (typeof config !== 'object' || config === null) {
62
+ throw new Error(`${source}: config must be a non-null object`);
63
+ }
64
+ const c = config;
65
+ if (typeof c.version !== 'string') {
66
+ throw new Error(`${source}: missing required field "version"`);
67
+ }
68
+ if (typeof c.name !== 'string') {
69
+ throw new Error(`${source}: missing required field "name"`);
70
+ }
71
+ if (typeof c.swarm !== 'object' || c.swarm === null) {
72
+ throw new Error(`${source}: missing required field "swarm"`);
73
+ }
74
+ const swarm = c.swarm;
75
+ if (typeof swarm.pattern !== 'string') {
76
+ throw new Error(`${source}: missing required field "swarm.pattern"`);
77
+ }
78
+ if (!Array.isArray(c.agents) || c.agents.length === 0) {
79
+ throw new Error(`${source}: "agents" must be a non-empty array`);
80
+ }
81
+ for (const agent of c.agents) {
82
+ if (typeof agent !== 'object' || agent === null) {
83
+ throw new Error(`${source}: each agent must be an object`);
84
+ }
85
+ const a = agent;
86
+ if (typeof a.name !== 'string') {
87
+ throw new Error(`${source}: each agent must have a string "name"`);
88
+ }
89
+ if (typeof a.cli !== 'string') {
90
+ throw new Error(`${source}: each agent must have a string "cli"`);
91
+ }
92
+ }
93
+ if (c.workflows !== undefined) {
94
+ if (!Array.isArray(c.workflows)) {
95
+ throw new Error(`${source}: "workflows" must be an array`);
96
+ }
97
+ for (const wf of c.workflows) {
98
+ this.validateWorkflow(wf, source);
99
+ }
100
+ }
101
+ }
102
+ validateWorkflow(wf, source) {
103
+ if (typeof wf !== 'object' || wf === null) {
104
+ throw new Error(`${source}: each workflow must be an object`);
105
+ }
106
+ const w = wf;
107
+ if (typeof w.name !== 'string') {
108
+ throw new Error(`${source}: each workflow must have a string "name"`);
109
+ }
110
+ if (!Array.isArray(w.steps) || w.steps.length === 0) {
111
+ throw new Error(`${source}: workflow "${w.name}" must have a non-empty "steps" array`);
112
+ }
113
+ for (const step of w.steps) {
114
+ if (typeof step !== 'object' || step === null) {
115
+ throw new Error(`${source}: each step must be an object`);
116
+ }
117
+ const s = step;
118
+ if (typeof s.name !== 'string' || typeof s.agent !== 'string' || typeof s.task !== 'string') {
119
+ throw new Error(`${source}: each step must have "name", "agent", and "task" string fields`);
120
+ }
121
+ }
122
+ // Validate DAG: check for unknown dependencies and cycles
123
+ const stepNames = new Set(w.steps.map((s) => s.name));
124
+ for (const step of w.steps) {
125
+ if (step.dependsOn) {
126
+ for (const dep of step.dependsOn) {
127
+ if (!stepNames.has(dep)) {
128
+ throw new Error(`${source}: step "${step.name}" depends on unknown step "${dep}"`);
129
+ }
130
+ }
131
+ }
132
+ }
133
+ this.detectCycles(w.steps, source, w.name);
134
+ }
135
+ detectCycles(steps, source, workflowName) {
136
+ const adj = new Map();
137
+ for (const step of steps) {
138
+ adj.set(step.name, step.dependsOn ?? []);
139
+ }
140
+ const visited = new Set();
141
+ const inStack = new Set();
142
+ const dfs = (node) => {
143
+ if (inStack.has(node)) {
144
+ throw new Error(`${source}: workflow "${workflowName}" contains a dependency cycle involving "${node}"`);
145
+ }
146
+ if (visited.has(node))
147
+ return;
148
+ inStack.add(node);
149
+ for (const dep of adj.get(node) ?? []) {
150
+ dfs(dep);
151
+ }
152
+ inStack.delete(node);
153
+ visited.add(node);
154
+ };
155
+ for (const step of steps) {
156
+ dfs(step.name);
157
+ }
158
+ }
159
+ // ── Template variable resolution ────────────────────────────────────────
160
+ /** Resolve {{variable}} placeholders in all task strings. */
161
+ resolveVariables(config, vars) {
162
+ const resolved = structuredClone(config);
163
+ for (const agent of resolved.agents) {
164
+ if (agent.task) {
165
+ agent.task = this.interpolate(agent.task, vars);
166
+ }
167
+ }
168
+ if (resolved.workflows) {
169
+ for (const wf of resolved.workflows) {
170
+ for (const step of wf.steps) {
171
+ step.task = this.interpolate(step.task, vars);
172
+ }
173
+ }
174
+ }
175
+ return resolved;
176
+ }
177
+ interpolate(template, vars) {
178
+ return template.replace(/\{\{([\w][\w.\-]*)\}\}/g, (_match, key) => {
179
+ // Skip step-output placeholders — they are resolved at execution time by interpolateStepTask()
180
+ if (key.startsWith('steps.')) {
181
+ return _match;
182
+ }
183
+ // Resolve dot-path variables like steps.plan.output
184
+ const value = this.resolveDotPath(key, vars);
185
+ if (value === undefined) {
186
+ throw new Error(`Unresolved variable: {{${key}}}`);
187
+ }
188
+ return String(value);
189
+ });
190
+ }
191
+ resolveDotPath(key, vars) {
192
+ // Simple key — direct lookup
193
+ if (!key.includes('.')) {
194
+ return vars[key];
195
+ }
196
+ // Dot-path — walk into nested context
197
+ const parts = key.split('.');
198
+ let current = vars;
199
+ for (const part of parts) {
200
+ if (current === null || current === undefined || typeof current !== 'object') {
201
+ return undefined;
202
+ }
203
+ current = current[part];
204
+ }
205
+ if (current === undefined || current === null) {
206
+ return undefined;
207
+ }
208
+ if (typeof current === 'string' || typeof current === 'number' || typeof current === 'boolean') {
209
+ return current;
210
+ }
211
+ return String(current);
212
+ }
213
+ /** Build a nested context from completed step outputs for {{steps.X.output}} resolution. */
214
+ buildStepOutputContext(stepStates) {
215
+ const steps = {};
216
+ for (const [name, state] of stepStates) {
217
+ if (state.row.status === 'completed' && state.row.output !== undefined) {
218
+ steps[name] = { output: state.row.output };
219
+ }
220
+ }
221
+ return { steps };
222
+ }
223
+ /** Interpolate step-output variables, silently skipping unresolved ones (they may be user vars). */
224
+ interpolateStepTask(template, context) {
225
+ return template.replace(/\{\{(steps\.[\w\-]+\.output)\}\}/g, (_match, key) => {
226
+ const value = this.resolveDotPath(key, context);
227
+ if (value === undefined) {
228
+ // Leave unresolved — may not be an error if the template doesn't depend on prior steps
229
+ return _match;
230
+ }
231
+ return String(value);
232
+ });
233
+ }
234
+ // ── Execution ───────────────────────────────────────────────────────────
235
+ /** Execute a named workflow from a validated config. */
236
+ async execute(config, workflowName, vars) {
237
+ const resolved = vars ? this.resolveVariables(config, vars) : config;
238
+ const workflows = resolved.workflows ?? [];
239
+ const workflow = workflowName
240
+ ? workflows.find((w) => w.name === workflowName)
241
+ : workflows[0];
242
+ if (!workflow) {
243
+ throw new Error(workflowName
244
+ ? `Workflow "${workflowName}" not found in config`
245
+ : 'No workflows defined in config');
246
+ }
247
+ const runId = this.generateId();
248
+ const now = new Date().toISOString();
249
+ const run = {
250
+ id: runId,
251
+ workspaceId: this.workspaceId,
252
+ workflowName: workflow.name,
253
+ pattern: resolved.swarm.pattern,
254
+ status: 'pending',
255
+ config: resolved,
256
+ startedAt: now,
257
+ createdAt: now,
258
+ updatedAt: now,
259
+ };
260
+ await this.db.insertRun(run);
261
+ // Build step rows
262
+ const stepStates = new Map();
263
+ for (const step of workflow.steps) {
264
+ const stepRow = {
265
+ id: this.generateId(),
266
+ runId,
267
+ stepName: step.name,
268
+ agentName: step.agent,
269
+ status: 'pending',
270
+ task: step.task,
271
+ dependsOn: step.dependsOn ?? [],
272
+ retryCount: 0,
273
+ createdAt: now,
274
+ updatedAt: now,
275
+ };
276
+ await this.db.insertStep(stepRow);
277
+ stepStates.set(step.name, { row: stepRow });
278
+ }
279
+ // Start execution
280
+ this.abortController = new AbortController();
281
+ this.paused = false;
282
+ try {
283
+ await this.updateRunStatus(runId, 'running');
284
+ this.emit({ type: 'run:started', runId });
285
+ this.relay = new AgentRelay({
286
+ ...this.relayOptions,
287
+ channels: [resolved.swarm.channel ?? 'general'],
288
+ });
289
+ const agentMap = new Map();
290
+ for (const agent of resolved.agents) {
291
+ agentMap.set(agent.name, agent);
292
+ }
293
+ await this.executeSteps(workflow, stepStates, agentMap, resolved.errorHandling, runId);
294
+ // Check if all steps completed
295
+ const allCompleted = [...stepStates.values()].every((s) => s.row.status === 'completed' || s.row.status === 'skipped');
296
+ if (allCompleted) {
297
+ await this.updateRunStatus(runId, 'completed');
298
+ this.emit({ type: 'run:completed', runId });
299
+ }
300
+ else {
301
+ const failedStep = [...stepStates.values()].find((s) => s.row.status === 'failed');
302
+ const errorMsg = failedStep?.row.error ?? 'One or more steps failed';
303
+ await this.updateRunStatus(runId, 'failed', errorMsg);
304
+ this.emit({ type: 'run:failed', runId, error: errorMsg });
305
+ }
306
+ }
307
+ catch (err) {
308
+ const errorMsg = err instanceof Error ? err.message : String(err);
309
+ const status = this.abortController?.signal.aborted ? 'cancelled' : 'failed';
310
+ await this.updateRunStatus(runId, status, errorMsg);
311
+ if (status === 'cancelled') {
312
+ this.emit({ type: 'run:cancelled', runId });
313
+ }
314
+ else {
315
+ this.emit({ type: 'run:failed', runId, error: errorMsg });
316
+ }
317
+ }
318
+ finally {
319
+ await this.relay?.shutdown();
320
+ this.relay = undefined;
321
+ this.abortController = undefined;
322
+ }
323
+ const finalRun = await this.db.getRun(runId);
324
+ return finalRun ?? run;
325
+ }
326
+ /** Resume a previously paused or partially completed run. */
327
+ async resume(runId, vars) {
328
+ const run = await this.db.getRun(runId);
329
+ if (!run) {
330
+ throw new Error(`Run "${runId}" not found`);
331
+ }
332
+ if (run.status !== 'running' && run.status !== 'failed') {
333
+ throw new Error(`Run "${runId}" is in status "${run.status}" and cannot be resumed`);
334
+ }
335
+ const config = vars ? this.resolveVariables(run.config, vars) : run.config;
336
+ const workflows = config.workflows ?? [];
337
+ const workflow = workflows.find((w) => w.name === run.workflowName);
338
+ if (!workflow) {
339
+ throw new Error(`Workflow "${run.workflowName}" not found in stored config`);
340
+ }
341
+ const existingSteps = await this.db.getStepsByRunId(runId);
342
+ const stepStates = new Map();
343
+ for (const stepRow of existingSteps) {
344
+ stepStates.set(stepRow.stepName, { row: stepRow });
345
+ }
346
+ // Reset failed steps to pending for retry
347
+ for (const [, state] of stepStates) {
348
+ if (state.row.status === 'failed') {
349
+ state.row.status = 'pending';
350
+ state.row.error = undefined;
351
+ await this.db.updateStep(state.row.id, {
352
+ status: 'pending',
353
+ error: undefined,
354
+ updatedAt: new Date().toISOString(),
355
+ });
356
+ }
357
+ }
358
+ this.abortController = new AbortController();
359
+ this.paused = false;
360
+ try {
361
+ await this.updateRunStatus(runId, 'running');
362
+ this.relay = new AgentRelay({
363
+ ...this.relayOptions,
364
+ channels: [config.swarm.channel ?? 'general'],
365
+ });
366
+ const agentMap = new Map();
367
+ for (const agent of config.agents) {
368
+ agentMap.set(agent.name, agent);
369
+ }
370
+ await this.executeSteps(workflow, stepStates, agentMap, config.errorHandling, runId);
371
+ const allCompleted = [...stepStates.values()].every((s) => s.row.status === 'completed' || s.row.status === 'skipped');
372
+ if (allCompleted) {
373
+ await this.updateRunStatus(runId, 'completed');
374
+ this.emit({ type: 'run:completed', runId });
375
+ }
376
+ else {
377
+ const failedStep = [...stepStates.values()].find((s) => s.row.status === 'failed');
378
+ const errorMsg = failedStep?.row.error ?? 'One or more steps failed';
379
+ await this.updateRunStatus(runId, 'failed', errorMsg);
380
+ this.emit({ type: 'run:failed', runId, error: errorMsg });
381
+ }
382
+ }
383
+ catch (err) {
384
+ const errorMsg = err instanceof Error ? err.message : String(err);
385
+ await this.updateRunStatus(runId, 'failed', errorMsg);
386
+ this.emit({ type: 'run:failed', runId, error: errorMsg });
387
+ }
388
+ finally {
389
+ await this.relay?.shutdown();
390
+ this.relay = undefined;
391
+ this.abortController = undefined;
392
+ }
393
+ const finalRun = await this.db.getRun(runId);
394
+ return finalRun ?? run;
395
+ }
396
+ /** Pause execution. Currently-running steps will finish but no new steps start. */
397
+ pause() {
398
+ this.paused = true;
399
+ }
400
+ /** Resume after a pause(). */
401
+ unpause() {
402
+ this.paused = false;
403
+ this.pauseResolver?.();
404
+ this.pauseResolver = undefined;
405
+ }
406
+ /** Abort the current run. Running agents are released. */
407
+ abort() {
408
+ // Unblock waitIfPaused() so the run loop can exit
409
+ this.pauseResolver?.();
410
+ this.pauseResolver = undefined;
411
+ this.abortController?.abort();
412
+ }
413
+ // ── Step execution engine ─────────────────────────────────────────────
414
+ async executeSteps(workflow, stepStates, agentMap, errorHandling, runId) {
415
+ const rawStrategy = errorHandling?.strategy ?? workflow.onError ?? 'fail-fast';
416
+ // Map shorthand onError values to canonical strategy names.
417
+ // 'retry' maps to 'fail-fast' so downstream steps are properly skipped after retries exhaust.
418
+ const strategy = rawStrategy === 'fail' ? 'fail-fast'
419
+ : rawStrategy === 'skip' ? 'continue'
420
+ : rawStrategy === 'retry' ? 'fail-fast'
421
+ : rawStrategy;
422
+ // DAG-based execution: repeatedly find ready steps and run them in parallel
423
+ while (true) {
424
+ this.checkAborted();
425
+ await this.waitIfPaused();
426
+ const readySteps = this.findReadySteps(workflow.steps, stepStates);
427
+ if (readySteps.length === 0) {
428
+ // No steps ready — either all done or blocked
429
+ break;
430
+ }
431
+ const results = await Promise.allSettled(readySteps.map((step) => this.executeStep(step, stepStates, agentMap, errorHandling, runId)));
432
+ for (let i = 0; i < results.length; i++) {
433
+ const result = results[i];
434
+ const step = readySteps[i];
435
+ if (result.status === 'rejected') {
436
+ const error = result.reason instanceof Error ? result.reason.message : String(result.reason);
437
+ const state = stepStates.get(step.name);
438
+ if (state && state.row.status !== 'failed') {
439
+ await this.markStepFailed(state, error, runId);
440
+ }
441
+ if (strategy === 'fail-fast') {
442
+ // Mark all pending downstream steps as skipped
443
+ await this.markDownstreamSkipped(step.name, workflow.steps, stepStates, runId);
444
+ throw new Error(`Step "${step.name}" failed: ${error}`);
445
+ }
446
+ if (strategy === 'continue') {
447
+ await this.markDownstreamSkipped(step.name, workflow.steps, stepStates, runId);
448
+ }
449
+ }
450
+ }
451
+ }
452
+ }
453
+ findReadySteps(steps, stepStates) {
454
+ return steps.filter((step) => {
455
+ const state = stepStates.get(step.name);
456
+ if (!state || state.row.status !== 'pending')
457
+ return false;
458
+ const deps = step.dependsOn ?? [];
459
+ return deps.every((dep) => {
460
+ const depState = stepStates.get(dep);
461
+ return depState && (depState.row.status === 'completed' || depState.row.status === 'skipped');
462
+ });
463
+ });
464
+ }
465
+ async executeStep(step, stepStates, agentMap, errorHandling, runId) {
466
+ const state = stepStates.get(step.name);
467
+ if (!state)
468
+ throw new Error(`Step state not found: ${step.name}`);
469
+ const agentDef = agentMap.get(step.agent);
470
+ if (!agentDef) {
471
+ throw new Error(`Agent "${step.agent}" not found in config`);
472
+ }
473
+ const maxRetries = step.retries ?? agentDef.constraints?.retries ?? errorHandling?.maxRetries ?? 0;
474
+ const retryDelay = errorHandling?.retryDelayMs ?? 1000;
475
+ const timeoutMs = step.timeoutMs ?? agentDef.constraints?.timeoutMs;
476
+ let lastError;
477
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
478
+ this.checkAborted();
479
+ if (attempt > 0) {
480
+ this.emit({ type: 'step:retrying', runId, stepName: step.name, attempt });
481
+ state.row.retryCount = attempt;
482
+ await this.db.updateStep(state.row.id, {
483
+ retryCount: attempt,
484
+ updatedAt: new Date().toISOString(),
485
+ });
486
+ await this.delay(retryDelay);
487
+ }
488
+ try {
489
+ // Mark step as running
490
+ state.row.status = 'running';
491
+ state.row.startedAt = new Date().toISOString();
492
+ await this.db.updateStep(state.row.id, {
493
+ status: 'running',
494
+ startedAt: state.row.startedAt,
495
+ updatedAt: new Date().toISOString(),
496
+ });
497
+ this.emit({ type: 'step:started', runId, stepName: step.name });
498
+ // Resolve step-output variables (e.g. {{steps.plan.output}}) at execution time
499
+ const stepOutputContext = this.buildStepOutputContext(stepStates);
500
+ const resolvedTask = this.interpolateStepTask(step.task, stepOutputContext);
501
+ // Spawn agent via AgentRelay
502
+ const resolvedStep = { ...step, task: resolvedTask };
503
+ const output = await this.spawnAndWait(agentDef, resolvedStep, timeoutMs);
504
+ // Run verification if configured
505
+ if (step.verification) {
506
+ this.runVerification(step.verification, output, step.name);
507
+ }
508
+ // Mark completed
509
+ state.row.status = 'completed';
510
+ state.row.output = output;
511
+ state.row.completedAt = new Date().toISOString();
512
+ await this.db.updateStep(state.row.id, {
513
+ status: 'completed',
514
+ output,
515
+ completedAt: state.row.completedAt,
516
+ updatedAt: new Date().toISOString(),
517
+ });
518
+ this.emit({ type: 'step:completed', runId, stepName: step.name, output });
519
+ return;
520
+ }
521
+ catch (err) {
522
+ lastError = err instanceof Error ? err.message : String(err);
523
+ }
524
+ }
525
+ // All retries exhausted — mark failed and throw so callers can apply error strategy
526
+ await this.markStepFailed(state, lastError ?? 'Unknown error', runId);
527
+ throw new Error(`Step "${step.name}" failed after ${maxRetries} retries: ${lastError ?? 'Unknown error'}`);
528
+ }
529
+ async spawnAndWait(agentDef, step, timeoutMs) {
530
+ if (!this.relay) {
531
+ throw new Error('AgentRelay not initialized');
532
+ }
533
+ const agent = await this.relay.spawnPty({
534
+ name: `${step.name}-${this.generateShortId()}`,
535
+ cli: agentDef.cli,
536
+ args: agentDef.constraints?.model ? ['--model', agentDef.constraints.model] : [],
537
+ channels: agentDef.channels,
538
+ });
539
+ // Send the task as a message to the agent
540
+ const system = this.relay.human({ name: 'WorkflowRunner' });
541
+ await system.sendMessage({ to: agent.name, text: step.task });
542
+ // Wait for agent to exit
543
+ const exitResult = await agent.waitForExit(timeoutMs);
544
+ if (exitResult === 'timeout') {
545
+ await agent.release();
546
+ throw new Error(`Step "${step.name}" timed out after ${timeoutMs}ms`);
547
+ }
548
+ // Read output from summary file if it exists
549
+ const summaryPath = path.join(this.summaryDir, `${step.name}.md`);
550
+ if (existsSync(summaryPath)) {
551
+ return await readFile(summaryPath, 'utf-8');
552
+ }
553
+ return `Agent exited (${exitResult})`;
554
+ }
555
+ // ── Verification ────────────────────────────────────────────────────────
556
+ runVerification(check, output, stepName) {
557
+ switch (check.type) {
558
+ case 'output_contains':
559
+ if (!output.includes(check.value)) {
560
+ throw new Error(`Verification failed for "${stepName}": output does not contain "${check.value}"`);
561
+ }
562
+ break;
563
+ case 'exit_code':
564
+ // exit_code verification is implicitly satisfied if the agent exited successfully
565
+ break;
566
+ case 'file_exists':
567
+ if (!existsSync(path.resolve(this.cwd, check.value))) {
568
+ throw new Error(`Verification failed for "${stepName}": file "${check.value}" does not exist`);
569
+ }
570
+ break;
571
+ case 'custom':
572
+ // Custom verifications are evaluated by callers; no-op here
573
+ break;
574
+ }
575
+ }
576
+ // ── State helpers ─────────────────────────────────────────────────────
577
+ async updateRunStatus(runId, status, error) {
578
+ const patch = {
579
+ status,
580
+ updatedAt: new Date().toISOString(),
581
+ };
582
+ if (status === 'completed' || status === 'failed' || status === 'cancelled') {
583
+ patch.completedAt = new Date().toISOString();
584
+ }
585
+ if (error) {
586
+ patch.error = error;
587
+ }
588
+ await this.db.updateRun(runId, patch);
589
+ }
590
+ async markStepFailed(state, error, runId) {
591
+ state.row.status = 'failed';
592
+ state.row.error = error;
593
+ state.row.completedAt = new Date().toISOString();
594
+ await this.db.updateStep(state.row.id, {
595
+ status: 'failed',
596
+ error,
597
+ completedAt: state.row.completedAt,
598
+ updatedAt: new Date().toISOString(),
599
+ });
600
+ this.emit({ type: 'step:failed', runId, stepName: state.row.stepName, error });
601
+ }
602
+ async markDownstreamSkipped(failedStepName, allSteps, stepStates, runId) {
603
+ const queue = [failedStepName];
604
+ const visited = new Set();
605
+ while (queue.length > 0) {
606
+ const current = queue.shift();
607
+ if (visited.has(current))
608
+ continue;
609
+ visited.add(current);
610
+ for (const step of allSteps) {
611
+ if (step.dependsOn?.includes(current)) {
612
+ const state = stepStates.get(step.name);
613
+ if (state && state.row.status === 'pending') {
614
+ state.row.status = 'skipped';
615
+ await this.db.updateStep(state.row.id, {
616
+ status: 'skipped',
617
+ updatedAt: new Date().toISOString(),
618
+ });
619
+ this.emit({ type: 'step:skipped', runId, stepName: step.name });
620
+ queue.push(step.name);
621
+ }
622
+ }
623
+ }
624
+ }
625
+ }
626
+ // ── Control flow helpers ──────────────────────────────────────────────
627
+ checkAborted() {
628
+ if (this.abortController?.signal.aborted) {
629
+ throw new Error('Workflow aborted');
630
+ }
631
+ }
632
+ async waitIfPaused() {
633
+ if (!this.paused)
634
+ return;
635
+ await new Promise((resolve) => {
636
+ this.pauseResolver = resolve;
637
+ });
638
+ }
639
+ delay(ms) {
640
+ return new Promise((resolve) => setTimeout(resolve, ms));
641
+ }
642
+ // ── ID generation ─────────────────────────────────────────────────────
643
+ generateId() {
644
+ return randomBytes(12).toString('hex');
645
+ }
646
+ generateShortId() {
647
+ return randomBytes(4).toString('hex');
648
+ }
649
+ }
650
+ //# sourceMappingURL=runner.js.map