@shipfox/api-workflows 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (661) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/.turbo/turbo-type$colon$emit.log +1 -0
  3. package/.turbo/turbo-type.log +1 -0
  4. package/CHANGELOG.md +311 -0
  5. package/LICENSE +21 -0
  6. package/dist/core/agent-tool-capability-warning.d.ts +7 -0
  7. package/dist/core/agent-tool-capability-warning.d.ts.map +1 -0
  8. package/dist/core/agent-tool-capability-warning.js +149 -0
  9. package/dist/core/agent-tool-capability-warning.js.map +1 -0
  10. package/dist/core/agent-tools.d.ts +51 -0
  11. package/dist/core/agent-tools.d.ts.map +1 -0
  12. package/dist/core/agent-tools.js +296 -0
  13. package/dist/core/agent-tools.js.map +1 -0
  14. package/dist/core/checkout.d.ts +29 -0
  15. package/dist/core/checkout.d.ts.map +1 -0
  16. package/dist/core/checkout.js +42 -0
  17. package/dist/core/checkout.js.map +1 -0
  18. package/dist/core/condition-trace.d.ts +13 -0
  19. package/dist/core/condition-trace.d.ts.map +1 -0
  20. package/dist/core/condition-trace.js +51 -0
  21. package/dist/core/condition-trace.js.map +1 -0
  22. package/dist/core/entities/index.d.ts +5 -0
  23. package/dist/core/entities/index.d.ts.map +1 -0
  24. package/dist/core/entities/index.js +3 -0
  25. package/dist/core/entities/index.js.map +1 -0
  26. package/dist/core/entities/job-execution.d.ts +30 -0
  27. package/dist/core/entities/job-execution.d.ts.map +1 -0
  28. package/dist/core/entities/job-execution.js +3 -0
  29. package/dist/core/entities/job-execution.js.map +1 -0
  30. package/dist/core/entities/job-listener-event.d.ts +15 -0
  31. package/dist/core/entities/job-listener-event.d.ts.map +1 -0
  32. package/dist/core/entities/job-listener-event.js +3 -0
  33. package/dist/core/entities/job-listener-event.js.map +1 -0
  34. package/dist/core/entities/job.d.ts +54 -0
  35. package/dist/core/entities/job.d.ts.map +1 -0
  36. package/dist/core/entities/job.js +29 -0
  37. package/dist/core/entities/job.js.map +1 -0
  38. package/dist/core/entities/step.d.ts +86 -0
  39. package/dist/core/entities/step.d.ts.map +1 -0
  40. package/dist/core/entities/step.js +12 -0
  41. package/dist/core/entities/step.js.map +1 -0
  42. package/dist/core/entities/workflow-run-attempt.d.ts +20 -0
  43. package/dist/core/entities/workflow-run-attempt.d.ts.map +1 -0
  44. package/dist/core/entities/workflow-run-attempt.js +3 -0
  45. package/dist/core/entities/workflow-run-attempt.js.map +1 -0
  46. package/dist/core/entities/workflow-run.d.ts +66 -0
  47. package/dist/core/entities/workflow-run.d.ts.map +1 -0
  48. package/dist/core/entities/workflow-run.js +10 -0
  49. package/dist/core/entities/workflow-run.js.map +1 -0
  50. package/dist/core/errors.d.ts +85 -0
  51. package/dist/core/errors.d.ts.map +1 -0
  52. package/dist/core/errors.js +134 -0
  53. package/dist/core/errors.js.map +1 -0
  54. package/dist/core/index.d.ts +14 -0
  55. package/dist/core/index.d.ts.map +1 -0
  56. package/dist/core/index.js +9 -0
  57. package/dist/core/index.js.map +1 -0
  58. package/dist/core/job-execution-outcome.d.ts +29 -0
  59. package/dist/core/job-execution-outcome.d.ts.map +1 -0
  60. package/dist/core/job-execution-outcome.js +31 -0
  61. package/dist/core/job-execution-outcome.js.map +1 -0
  62. package/dist/core/job-execution.d.ts +37 -0
  63. package/dist/core/job-execution.d.ts.map +1 -0
  64. package/dist/core/job-execution.js +425 -0
  65. package/dist/core/job-execution.js.map +1 -0
  66. package/dist/core/job-transition/decide-job-activation.d.ts +29 -0
  67. package/dist/core/job-transition/decide-job-activation.d.ts.map +1 -0
  68. package/dist/core/job-transition/decide-job-activation.js +51 -0
  69. package/dist/core/job-transition/decide-job-activation.js.map +1 -0
  70. package/dist/core/job-transition/derive-job-execution-outputs.d.ts +18 -0
  71. package/dist/core/job-transition/derive-job-execution-outputs.d.ts.map +1 -0
  72. package/dist/core/job-transition/derive-job-execution-outputs.js +23 -0
  73. package/dist/core/job-transition/derive-job-execution-outputs.js.map +1 -0
  74. package/dist/core/job-transition/derive-job-success.d.ts +16 -0
  75. package/dist/core/job-transition/derive-job-success.d.ts.map +1 -0
  76. package/dist/core/job-transition/derive-job-success.js +47 -0
  77. package/dist/core/job-transition/derive-job-success.js.map +1 -0
  78. package/dist/core/job-transition/index.d.ts +5 -0
  79. package/dist/core/job-transition/index.d.ts.map +1 -0
  80. package/dist/core/job-transition/index.js +6 -0
  81. package/dist/core/job-transition/index.js.map +1 -0
  82. package/dist/core/job-transition/runtime-completion-status-for-job.d.ts +4 -0
  83. package/dist/core/job-transition/runtime-completion-status-for-job.d.ts.map +1 -0
  84. package/dist/core/job-transition/runtime-completion-status-for-job.js +8 -0
  85. package/dist/core/job-transition/runtime-completion-status-for-job.js.map +1 -0
  86. package/dist/core/listener-execution-materialization.d.ts +30 -0
  87. package/dist/core/listener-execution-materialization.d.ts.map +1 -0
  88. package/dist/core/listener-execution-materialization.js +87 -0
  89. package/dist/core/listener-execution-materialization.js.map +1 -0
  90. package/dist/core/run-workflow.d.ts +11 -0
  91. package/dist/core/run-workflow.d.ts.map +1 -0
  92. package/dist/core/run-workflow.js +28 -0
  93. package/dist/core/run-workflow.js.map +1 -0
  94. package/dist/core/source-control.d.ts +5 -0
  95. package/dist/core/source-control.d.ts.map +1 -0
  96. package/dist/core/source-control.js +19 -0
  97. package/dist/core/source-control.js.map +1 -0
  98. package/dist/core/step-config/agent.d.ts +49 -0
  99. package/dist/core/step-config/agent.d.ts.map +1 -0
  100. package/dist/core/step-config/agent.js +337 -0
  101. package/dist/core/step-config/agent.js.map +1 -0
  102. package/dist/core/step-config/assemble-run-context.d.ts +94 -0
  103. package/dist/core/step-config/assemble-run-context.d.ts.map +1 -0
  104. package/dist/core/step-config/assemble-run-context.js +393 -0
  105. package/dist/core/step-config/assemble-run-context.js.map +1 -0
  106. package/dist/core/step-config/complete-step-dispatch-config.d.ts +13 -0
  107. package/dist/core/step-config/complete-step-dispatch-config.d.ts.map +1 -0
  108. package/dist/core/step-config/complete-step-dispatch-config.js +38 -0
  109. package/dist/core/step-config/complete-step-dispatch-config.js.map +1 -0
  110. package/dist/core/step-config/fields.d.ts +38 -0
  111. package/dist/core/step-config/fields.d.ts.map +1 -0
  112. package/dist/core/step-config/fields.js +72 -0
  113. package/dist/core/step-config/fields.js.map +1 -0
  114. package/dist/core/step-config/index.d.ts +8 -0
  115. package/dist/core/step-config/index.d.ts.map +1 -0
  116. package/dist/core/step-config/index.js +7 -0
  117. package/dist/core/step-config/index.js.map +1 -0
  118. package/dist/core/step-config/materialize-job-execution-steps.d.ts +35 -0
  119. package/dist/core/step-config/materialize-job-execution-steps.d.ts.map +1 -0
  120. package/dist/core/step-config/materialize-job-execution-steps.js +92 -0
  121. package/dist/core/step-config/materialize-job-execution-steps.js.map +1 -0
  122. package/dist/core/step-config/materialize-workflow-model.d.ts +42 -0
  123. package/dist/core/step-config/materialize-workflow-model.d.ts.map +1 -0
  124. package/dist/core/step-config/materialize-workflow-model.js +96 -0
  125. package/dist/core/step-config/materialize-workflow-model.js.map +1 -0
  126. package/dist/core/step-config/resolve-job-execution-name.d.ts +18 -0
  127. package/dist/core/step-config/resolve-job-execution-name.d.ts.map +1 -0
  128. package/dist/core/step-config/resolve-job-execution-name.js +36 -0
  129. package/dist/core/step-config/resolve-job-execution-name.js.map +1 -0
  130. package/dist/core/step-config/resolve-step-config.d.ts +33 -0
  131. package/dist/core/step-config/resolve-step-config.d.ts.map +1 -0
  132. package/dist/core/step-config/resolve-step-config.js +164 -0
  133. package/dist/core/step-config/resolve-step-config.js.map +1 -0
  134. package/dist/core/step-config/run.d.ts +39 -0
  135. package/dist/core/step-config/run.d.ts.map +1 -0
  136. package/dist/core/step-config/run.js +360 -0
  137. package/dist/core/step-config/run.js.map +1 -0
  138. package/dist/core/step-config/workflow-evaluation-context.d.ts +6 -0
  139. package/dist/core/step-config/workflow-evaluation-context.d.ts.map +1 -0
  140. package/dist/core/step-config/workflow-evaluation-context.js +3 -0
  141. package/dist/core/step-config/workflow-evaluation-context.js.map +1 -0
  142. package/dist/core/step-transition/apply-step-transition.d.ts +26 -0
  143. package/dist/core/step-transition/apply-step-transition.d.ts.map +1 -0
  144. package/dist/core/step-transition/apply-step-transition.js +141 -0
  145. package/dist/core/step-transition/apply-step-transition.js.map +1 -0
  146. package/dist/core/step-transition/decide-step-transition.d.ts +71 -0
  147. package/dist/core/step-transition/decide-step-transition.d.ts.map +1 -0
  148. package/dist/core/step-transition/decide-step-transition.js +110 -0
  149. package/dist/core/step-transition/decide-step-transition.js.map +1 -0
  150. package/dist/core/step-transition/evaluate-gate.d.ts +28 -0
  151. package/dist/core/step-transition/evaluate-gate.d.ts.map +1 -0
  152. package/dist/core/step-transition/evaluate-gate.js +159 -0
  153. package/dist/core/step-transition/evaluate-gate.js.map +1 -0
  154. package/dist/core/step-transition/read-step-outputs.d.ts +3 -0
  155. package/dist/core/step-transition/read-step-outputs.d.ts.map +1 -0
  156. package/dist/core/step-transition/read-step-outputs.js +24 -0
  157. package/dist/core/step-transition/read-step-outputs.js.map +1 -0
  158. package/dist/core/workflow-run-creation.d.ts +43 -0
  159. package/dist/core/workflow-run-creation.d.ts.map +1 -0
  160. package/dist/core/workflow-run-creation.js +80 -0
  161. package/dist/core/workflow-run-creation.js.map +1 -0
  162. package/dist/core/workflow-scheduling/index.d.ts +5 -0
  163. package/dist/core/workflow-scheduling/index.d.ts.map +1 -0
  164. package/dist/core/workflow-scheduling/index.js +4 -0
  165. package/dist/core/workflow-scheduling/index.js.map +1 -0
  166. package/dist/core/workflow-scheduling/run-progress.d.ts +20 -0
  167. package/dist/core/workflow-scheduling/run-progress.d.ts.map +1 -0
  168. package/dist/core/workflow-scheduling/run-progress.js +40 -0
  169. package/dist/core/workflow-scheduling/run-progress.js.map +1 -0
  170. package/dist/core/workflow-scheduling/runtime-dag.d.ts +10 -0
  171. package/dist/core/workflow-scheduling/runtime-dag.d.ts.map +1 -0
  172. package/dist/core/workflow-scheduling/runtime-dag.js +3 -0
  173. package/dist/core/workflow-scheduling/runtime-dag.js.map +1 -0
  174. package/dist/core/workflow-scheduling/runtime-scheduling-command.d.ts +16 -0
  175. package/dist/core/workflow-scheduling/runtime-scheduling-command.d.ts.map +1 -0
  176. package/dist/core/workflow-scheduling/runtime-scheduling-command.js +3 -0
  177. package/dist/core/workflow-scheduling/runtime-scheduling-command.js.map +1 -0
  178. package/dist/core/workflow-scheduling/schedule-runtime-dag.d.ts +9 -0
  179. package/dist/core/workflow-scheduling/schedule-runtime-dag.d.ts.map +1 -0
  180. package/dist/core/workflow-scheduling/schedule-runtime-dag.js +72 -0
  181. package/dist/core/workflow-scheduling/schedule-runtime-dag.js.map +1 -0
  182. package/dist/db/db.d.ts +4959 -0
  183. package/dist/db/db.d.ts.map +1 -0
  184. package/dist/db/db.js +37 -0
  185. package/dist/db/db.js.map +1 -0
  186. package/dist/db/index.d.ts +9 -0
  187. package/dist/db/index.d.ts.map +1 -0
  188. package/dist/db/index.js +10 -0
  189. package/dist/db/index.js.map +1 -0
  190. package/dist/db/job-listener-events.d.ts +18 -0
  191. package/dist/db/job-listener-events.d.ts.map +1 -0
  192. package/dist/db/job-listener-events.js +59 -0
  193. package/dist/db/job-listener-events.js.map +1 -0
  194. package/dist/db/job-listeners.d.ts +55 -0
  195. package/dist/db/job-listeners.d.ts.map +1 -0
  196. package/dist/db/job-listeners.js +358 -0
  197. package/dist/db/job-listeners.js.map +1 -0
  198. package/dist/db/outbox-writes.d.ts +12 -0
  199. package/dist/db/outbox-writes.d.ts.map +1 -0
  200. package/dist/db/outbox-writes.js +20 -0
  201. package/dist/db/outbox-writes.js.map +1 -0
  202. package/dist/db/runner-lease-table.d.ts +469 -0
  203. package/dist/db/runner-lease-table.d.ts.map +1 -0
  204. package/dist/db/runner-lease-table.js +42 -0
  205. package/dist/db/runner-lease-table.js.map +1 -0
  206. package/dist/db/schema/common.d.ts +2 -0
  207. package/dist/db/schema/common.d.ts.map +1 -0
  208. package/dist/db/schema/common.js +4 -0
  209. package/dist/db/schema/common.js.map +1 -0
  210. package/dist/db/schema/job-executions.d.ts +311 -0
  211. package/dist/db/schema/job-executions.d.ts.map +1 -0
  212. package/dist/db/schema/job-executions.js +76 -0
  213. package/dist/db/schema/job-executions.js.map +1 -0
  214. package/dist/db/schema/job-listener-events.d.ts +200 -0
  215. package/dist/db/schema/job-listener-events.d.ts.map +1 -0
  216. package/dist/db/schema/job-listener-events.js +50 -0
  217. package/dist/db/schema/job-listener-events.js.map +1 -0
  218. package/dist/db/schema/jobs.d.ts +542 -0
  219. package/dist/db/schema/jobs.d.ts.map +1 -0
  220. package/dist/db/schema/jobs.js +121 -0
  221. package/dist/db/schema/jobs.js.map +1 -0
  222. package/dist/db/schema/outbox.d.ts +195 -0
  223. package/dist/db/schema/outbox.d.ts.map +1 -0
  224. package/dist/db/schema/outbox.js +5 -0
  225. package/dist/db/schema/outbox.js.map +1 -0
  226. package/dist/db/schema/step-attempts.d.ts +330 -0
  227. package/dist/db/schema/step-attempts.d.ts.map +1 -0
  228. package/dist/db/schema/step-attempts.js +80 -0
  229. package/dist/db/schema/step-attempts.js.map +1 -0
  230. package/dist/db/schema/steps.d.ts +352 -0
  231. package/dist/db/schema/steps.d.ts.map +1 -0
  232. package/dist/db/schema/steps.js +80 -0
  233. package/dist/db/schema/steps.js.map +1 -0
  234. package/dist/db/schema/workflow-run-attempts.d.ts +239 -0
  235. package/dist/db/schema/workflow-run-attempts.d.ts.map +1 -0
  236. package/dist/db/schema/workflow-run-attempts.js +53 -0
  237. package/dist/db/schema/workflow-run-attempts.js.map +1 -0
  238. package/dist/db/schema/workflow-runs.d.ts +360 -0
  239. package/dist/db/schema/workflow-runs.d.ts.map +1 -0
  240. package/dist/db/schema/workflow-runs.js +85 -0
  241. package/dist/db/schema/workflow-runs.js.map +1 -0
  242. package/dist/db/workflow-runs/job-executions.d.ts +49 -0
  243. package/dist/db/workflow-runs/job-executions.d.ts.map +1 -0
  244. package/dist/db/workflow-runs/job-executions.js +271 -0
  245. package/dist/db/workflow-runs/job-executions.js.map +1 -0
  246. package/dist/db/workflow-runs/jobs.d.ts +60 -0
  247. package/dist/db/workflow-runs/jobs.d.ts.map +1 -0
  248. package/dist/db/workflow-runs/jobs.js +288 -0
  249. package/dist/db/workflow-runs/jobs.js.map +1 -0
  250. package/dist/db/workflow-runs/outbox.d.ts +20 -0
  251. package/dist/db/workflow-runs/outbox.d.ts.map +1 -0
  252. package/dist/db/workflow-runs/outbox.js +68 -0
  253. package/dist/db/workflow-runs/outbox.js.map +1 -0
  254. package/dist/db/workflow-runs/queries.d.ts +71 -0
  255. package/dist/db/workflow-runs/queries.d.ts.map +1 -0
  256. package/dist/db/workflow-runs/queries.js +253 -0
  257. package/dist/db/workflow-runs/queries.js.map +1 -0
  258. package/dist/db/workflow-runs/run-create.d.ts +32 -0
  259. package/dist/db/workflow-runs/run-create.d.ts.map +1 -0
  260. package/dist/db/workflow-runs/run-create.js +288 -0
  261. package/dist/db/workflow-runs/run-create.js.map +1 -0
  262. package/dist/db/workflow-runs/run-graph.d.ts +27 -0
  263. package/dist/db/workflow-runs/run-graph.d.ts.map +1 -0
  264. package/dist/db/workflow-runs/run-graph.js +63 -0
  265. package/dist/db/workflow-runs/run-graph.js.map +1 -0
  266. package/dist/db/workflow-runs/run-rerun.d.ts +8 -0
  267. package/dist/db/workflow-runs/run-rerun.d.ts.map +1 -0
  268. package/dist/db/workflow-runs/run-rerun.js +207 -0
  269. package/dist/db/workflow-runs/run-rerun.js.map +1 -0
  270. package/dist/db/workflow-runs/run-status.d.ts +24 -0
  271. package/dist/db/workflow-runs/run-status.d.ts.map +1 -0
  272. package/dist/db/workflow-runs/run-status.js +249 -0
  273. package/dist/db/workflow-runs/run-status.js.map +1 -0
  274. package/dist/db/workflow-runs/runs.d.ts +7 -0
  275. package/dist/db/workflow-runs/runs.d.ts.map +1 -0
  276. package/dist/db/workflow-runs/runs.js +5 -0
  277. package/dist/db/workflow-runs/runs.js.map +1 -0
  278. package/dist/db/workflow-runs/shared.d.ts +24 -0
  279. package/dist/db/workflow-runs/shared.d.ts.map +1 -0
  280. package/dist/db/workflow-runs/shared.js +50 -0
  281. package/dist/db/workflow-runs/shared.js.map +1 -0
  282. package/dist/db/workflow-runs/steps.d.ts +83 -0
  283. package/dist/db/workflow-runs/steps.d.ts.map +1 -0
  284. package/dist/db/workflow-runs/steps.js +246 -0
  285. package/dist/db/workflow-runs/steps.js.map +1 -0
  286. package/dist/db/workflow-runs.d.ts +12 -0
  287. package/dist/db/workflow-runs.d.ts.map +1 -0
  288. package/dist/db/workflow-runs.js +8 -0
  289. package/dist/db/workflow-runs.js.map +1 -0
  290. package/dist/index.d.ts +10 -0
  291. package/dist/index.d.ts.map +1 -0
  292. package/dist/index.js +54 -0
  293. package/dist/index.js.map +1 -0
  294. package/dist/metrics/index.d.ts +2 -0
  295. package/dist/metrics/index.d.ts.map +1 -0
  296. package/dist/metrics/index.js +3 -0
  297. package/dist/metrics/index.js.map +1 -0
  298. package/dist/metrics/instance.d.ts +20 -0
  299. package/dist/metrics/instance.d.ts.map +1 -0
  300. package/dist/metrics/instance.js +127 -0
  301. package/dist/metrics/instance.js.map +1 -0
  302. package/dist/metrics/service.d.ts +2 -0
  303. package/dist/metrics/service.d.ts.map +1 -0
  304. package/dist/metrics/service.js +30 -0
  305. package/dist/metrics/service.js.map +1 -0
  306. package/dist/presentation/dto/checkout-token.d.ts +6 -0
  307. package/dist/presentation/dto/checkout-token.d.ts.map +1 -0
  308. package/dist/presentation/dto/checkout-token.js +74 -0
  309. package/dist/presentation/dto/checkout-token.js.map +1 -0
  310. package/dist/presentation/dto/index.d.ts +4 -0
  311. package/dist/presentation/dto/index.d.ts.map +1 -0
  312. package/dist/presentation/dto/index.js +5 -0
  313. package/dist/presentation/dto/index.js.map +1 -0
  314. package/dist/presentation/dto/job.d.ts +6 -0
  315. package/dist/presentation/dto/job.d.ts.map +1 -0
  316. package/dist/presentation/dto/job.js +59 -0
  317. package/dist/presentation/dto/job.js.map +1 -0
  318. package/dist/presentation/dto/step.d.ts +6 -0
  319. package/dist/presentation/dto/step.d.ts.map +1 -0
  320. package/dist/presentation/dto/step.js +162 -0
  321. package/dist/presentation/dto/step.js.map +1 -0
  322. package/dist/presentation/dto/workflow-run.d.ts +6 -0
  323. package/dist/presentation/dto/workflow-run.d.ts.map +1 -0
  324. package/dist/presentation/dto/workflow-run.js +35 -0
  325. package/dist/presentation/dto/workflow-run.js.map +1 -0
  326. package/dist/presentation/index.d.ts +3 -0
  327. package/dist/presentation/index.d.ts.map +1 -0
  328. package/dist/presentation/index.js +4 -0
  329. package/dist/presentation/index.js.map +1 -0
  330. package/dist/presentation/routes/agent-runtime-config.d.ts +2 -0
  331. package/dist/presentation/routes/agent-runtime-config.d.ts.map +1 -0
  332. package/dist/presentation/routes/agent-runtime-config.js +71 -0
  333. package/dist/presentation/routes/agent-runtime-config.js.map +1 -0
  334. package/dist/presentation/routes/cancel-run.d.ts +2 -0
  335. package/dist/presentation/routes/cancel-run.d.ts.map +1 -0
  336. package/dist/presentation/routes/cancel-run.js +46 -0
  337. package/dist/presentation/routes/cancel-run.js.map +1 -0
  338. package/dist/presentation/routes/checkout-token.d.ts +2 -0
  339. package/dist/presentation/routes/checkout-token.d.ts.map +1 -0
  340. package/dist/presentation/routes/checkout-token.js +64 -0
  341. package/dist/presentation/routes/checkout-token.js.map +1 -0
  342. package/dist/presentation/routes/get-run-aggregates.d.ts +2 -0
  343. package/dist/presentation/routes/get-run-aggregates.d.ts.map +1 -0
  344. package/dist/presentation/routes/get-run-aggregates.js +60 -0
  345. package/dist/presentation/routes/get-run-aggregates.js.map +1 -0
  346. package/dist/presentation/routes/get-run.d.ts +2 -0
  347. package/dist/presentation/routes/get-run.d.ts.map +1 -0
  348. package/dist/presentation/routes/get-run.js +60 -0
  349. package/dist/presentation/routes/get-run.js.map +1 -0
  350. package/dist/presentation/routes/get-step-secrets.d.ts +2 -0
  351. package/dist/presentation/routes/get-step-secrets.d.ts.map +1 -0
  352. package/dist/presentation/routes/get-step-secrets.js +115 -0
  353. package/dist/presentation/routes/get-step-secrets.js.map +1 -0
  354. package/dist/presentation/routes/index.d.ts +4 -0
  355. package/dist/presentation/routes/index.d.ts.map +1 -0
  356. package/dist/presentation/routes/index.js +41 -0
  357. package/dist/presentation/routes/index.js.map +1 -0
  358. package/dist/presentation/routes/leased-step.d.ts +14 -0
  359. package/dist/presentation/routes/leased-step.d.ts.map +1 -0
  360. package/dist/presentation/routes/leased-step.js +50 -0
  361. package/dist/presentation/routes/leased-step.js.map +1 -0
  362. package/dist/presentation/routes/list-run-attempts.d.ts +2 -0
  363. package/dist/presentation/routes/list-run-attempts.d.ts.map +1 -0
  364. package/dist/presentation/routes/list-run-attempts.js +35 -0
  365. package/dist/presentation/routes/list-run-attempts.js.map +1 -0
  366. package/dist/presentation/routes/list-runs.d.ts +2 -0
  367. package/dist/presentation/routes/list-runs.d.ts.map +1 -0
  368. package/dist/presentation/routes/list-runs.js +70 -0
  369. package/dist/presentation/routes/list-runs.js.map +1 -0
  370. package/dist/presentation/routes/next-step.d.ts +2 -0
  371. package/dist/presentation/routes/next-step.d.ts.map +1 -0
  372. package/dist/presentation/routes/next-step.js +65 -0
  373. package/dist/presentation/routes/next-step.js.map +1 -0
  374. package/dist/presentation/routes/report-step.d.ts +2 -0
  375. package/dist/presentation/routes/report-step.d.ts.map +1 -0
  376. package/dist/presentation/routes/report-step.js +73 -0
  377. package/dist/presentation/routes/report-step.js.map +1 -0
  378. package/dist/presentation/routes/require-accessible-run.d.ts +7 -0
  379. package/dist/presentation/routes/require-accessible-run.d.ts.map +1 -0
  380. package/dist/presentation/routes/require-accessible-run.js +25 -0
  381. package/dist/presentation/routes/require-accessible-run.js.map +1 -0
  382. package/dist/presentation/routes/rerun-run.d.ts +2 -0
  383. package/dist/presentation/routes/rerun-run.d.ts.map +1 -0
  384. package/dist/presentation/routes/rerun-run.js +56 -0
  385. package/dist/presentation/routes/rerun-run.js.map +1 -0
  386. package/dist/presentation/subscribers/index.d.ts +8 -0
  387. package/dist/presentation/subscribers/index.d.ts.map +1 -0
  388. package/dist/presentation/subscribers/index.js +9 -0
  389. package/dist/presentation/subscribers/index.js.map +1 -0
  390. package/dist/presentation/subscribers/on-job-event-delivered.d.ts +3 -0
  391. package/dist/presentation/subscribers/on-job-event-delivered.d.ts.map +1 -0
  392. package/dist/presentation/subscribers/on-job-event-delivered.js +24 -0
  393. package/dist/presentation/subscribers/on-job-event-delivered.js.map +1 -0
  394. package/dist/presentation/subscribers/on-job-steps-settled.d.ts +3 -0
  395. package/dist/presentation/subscribers/on-job-steps-settled.d.ts.map +1 -0
  396. package/dist/presentation/subscribers/on-job-steps-settled.js +36 -0
  397. package/dist/presentation/subscribers/on-job-steps-settled.js.map +1 -0
  398. package/dist/presentation/subscribers/on-runner-job-claimed.d.ts +3 -0
  399. package/dist/presentation/subscribers/on-runner-job-claimed.d.ts.map +1 -0
  400. package/dist/presentation/subscribers/on-runner-job-claimed.js +20 -0
  401. package/dist/presentation/subscribers/on-runner-job-claimed.js.map +1 -0
  402. package/dist/presentation/subscribers/on-runner-job-lease-expired.d.ts +3 -0
  403. package/dist/presentation/subscribers/on-runner-job-lease-expired.d.ts.map +1 -0
  404. package/dist/presentation/subscribers/on-runner-job-lease-expired.js +35 -0
  405. package/dist/presentation/subscribers/on-runner-job-lease-expired.js.map +1 -0
  406. package/dist/presentation/subscribers/on-runner-job-queued.d.ts +3 -0
  407. package/dist/presentation/subscribers/on-runner-job-queued.d.ts.map +1 -0
  408. package/dist/presentation/subscribers/on-runner-job-queued.js +20 -0
  409. package/dist/presentation/subscribers/on-runner-job-queued.js.map +1 -0
  410. package/dist/presentation/subscribers/on-workflow-run-attempt-created.d.ts +3 -0
  411. package/dist/presentation/subscribers/on-workflow-run-attempt-created.d.ts.map +1 -0
  412. package/dist/presentation/subscribers/on-workflow-run-attempt-created.js +35 -0
  413. package/dist/presentation/subscribers/on-workflow-run-attempt-created.js.map +1 -0
  414. package/dist/presentation/subscribers/on-workflow-run-cancelled.d.ts +3 -0
  415. package/dist/presentation/subscribers/on-workflow-run-cancelled.d.ts.map +1 -0
  416. package/dist/presentation/subscribers/on-workflow-run-cancelled.js +25 -0
  417. package/dist/presentation/subscribers/on-workflow-run-cancelled.js.map +1 -0
  418. package/dist/temporal/activities/index.d.ts +23 -0
  419. package/dist/temporal/activities/index.d.ts.map +1 -0
  420. package/dist/temporal/activities/index.js +26 -0
  421. package/dist/temporal/activities/index.js.map +1 -0
  422. package/dist/temporal/activities/orchestration-activities.d.ts +130 -0
  423. package/dist/temporal/activities/orchestration-activities.d.ts.map +1 -0
  424. package/dist/temporal/activities/orchestration-activities.js +188 -0
  425. package/dist/temporal/activities/orchestration-activities.js.map +1 -0
  426. package/dist/temporal/constants.d.ts +7 -0
  427. package/dist/temporal/constants.d.ts.map +1 -0
  428. package/dist/temporal/constants.js +8 -0
  429. package/dist/temporal/constants.js.map +1 -0
  430. package/dist/temporal/index.d.ts +3 -0
  431. package/dist/temporal/index.d.ts.map +1 -0
  432. package/dist/temporal/index.js +4 -0
  433. package/dist/temporal/index.js.map +1 -0
  434. package/dist/temporal/workflow-not-found.d.ts +2 -0
  435. package/dist/temporal/workflow-not-found.d.ts.map +1 -0
  436. package/dist/temporal/workflow-not-found.js +10 -0
  437. package/dist/temporal/workflow-not-found.js.map +1 -0
  438. package/dist/temporal/workflows/deadline.d.ts +3 -0
  439. package/dist/temporal/workflows/deadline.d.ts.map +1 -0
  440. package/dist/temporal/workflows/deadline.js +8 -0
  441. package/dist/temporal/workflows/deadline.js.map +1 -0
  442. package/dist/temporal/workflows/index.d.ts +4 -0
  443. package/dist/temporal/workflows/index.d.ts.map +1 -0
  444. package/dist/temporal/workflows/index.js +5 -0
  445. package/dist/temporal/workflows/index.js.map +1 -0
  446. package/dist/temporal/workflows/job-execution-orchestration.d.ts +27 -0
  447. package/dist/temporal/workflows/job-execution-orchestration.d.ts.map +1 -0
  448. package/dist/temporal/workflows/job-execution-orchestration.js +265 -0
  449. package/dist/temporal/workflows/job-execution-orchestration.js.map +1 -0
  450. package/dist/temporal/workflows/job-listener-orchestration.d.ts +40 -0
  451. package/dist/temporal/workflows/job-listener-orchestration.d.ts.map +1 -0
  452. package/dist/temporal/workflows/job-listener-orchestration.js +332 -0
  453. package/dist/temporal/workflows/job-listener-orchestration.js.map +1 -0
  454. package/dist/temporal/workflows/run-orchestration.d.ts +8 -0
  455. package/dist/temporal/workflows/run-orchestration.d.ts.map +1 -0
  456. package/dist/temporal/workflows/run-orchestration.js +243 -0
  457. package/dist/temporal/workflows/run-orchestration.js.map +1 -0
  458. package/dist/temporal/workflows/test-env.d.ts +114 -0
  459. package/dist/temporal/workflows/test-env.d.ts.map +1 -0
  460. package/dist/temporal/workflows/test-env.js +323 -0
  461. package/dist/temporal/workflows/test-env.js.map +1 -0
  462. package/dist/tsconfig.test.tsbuildinfo +1 -0
  463. package/drizzle/0000_initial.sql +211 -0
  464. package/drizzle/0001_agent_tool_materialization.sql +1 -0
  465. package/drizzle/meta/0000_snapshot.json +1613 -0
  466. package/drizzle/meta/_journal.json +20 -0
  467. package/drizzle.config.ts +7 -0
  468. package/package.json +91 -0
  469. package/src/core/README.md +79 -0
  470. package/src/core/agent-tool-capability-warning.test.ts +280 -0
  471. package/src/core/agent-tool-capability-warning.ts +200 -0
  472. package/src/core/agent-tools.ts +422 -0
  473. package/src/core/checkout.test.ts +112 -0
  474. package/src/core/checkout.ts +63 -0
  475. package/src/core/condition-trace.ts +64 -0
  476. package/src/core/entities/index.ts +9 -0
  477. package/src/core/entities/job-execution.ts +32 -0
  478. package/src/core/entities/job-listener-event.ts +15 -0
  479. package/src/core/entities/job.ts +91 -0
  480. package/src/core/entities/step.ts +126 -0
  481. package/src/core/entities/workflow-run-attempt.ts +21 -0
  482. package/src/core/entities/workflow-run.ts +94 -0
  483. package/src/core/errors.test.ts +45 -0
  484. package/src/core/errors.ts +209 -0
  485. package/src/core/index.ts +54 -0
  486. package/src/core/job-execution-outcome.ts +64 -0
  487. package/src/core/job-execution.test.ts +1560 -0
  488. package/src/core/job-execution.ts +581 -0
  489. package/src/core/job-transition/decide-job-activation.test.ts +196 -0
  490. package/src/core/job-transition/decide-job-activation.ts +79 -0
  491. package/src/core/job-transition/derive-job-execution-outputs.ts +41 -0
  492. package/src/core/job-transition/derive-job-success.test.ts +133 -0
  493. package/src/core/job-transition/derive-job-success.ts +67 -0
  494. package/src/core/job-transition/index.ts +11 -0
  495. package/src/core/job-transition/runtime-completion-status-for-job.ts +14 -0
  496. package/src/core/listener-execution-materialization.test.ts +49 -0
  497. package/src/core/listener-execution-materialization.ts +162 -0
  498. package/src/core/run-workflow.test.ts +229 -0
  499. package/src/core/run-workflow.ts +41 -0
  500. package/src/core/source-control.test.ts +17 -0
  501. package/src/core/source-control.ts +22 -0
  502. package/src/core/step-config/agent.ts +459 -0
  503. package/src/core/step-config/assemble-run-context.test.ts +1021 -0
  504. package/src/core/step-config/assemble-run-context.ts +535 -0
  505. package/src/core/step-config/complete-step-dispatch-config.test.ts +354 -0
  506. package/src/core/step-config/complete-step-dispatch-config.ts +40 -0
  507. package/src/core/step-config/fields.ts +111 -0
  508. package/src/core/step-config/index.ts +41 -0
  509. package/src/core/step-config/materialize-job-execution-steps.test.ts +494 -0
  510. package/src/core/step-config/materialize-job-execution-steps.ts +136 -0
  511. package/src/core/step-config/materialize-workflow-model.test.ts +1214 -0
  512. package/src/core/step-config/materialize-workflow-model.ts +140 -0
  513. package/src/core/step-config/resolve-job-execution-name.test.ts +94 -0
  514. package/src/core/step-config/resolve-job-execution-name.ts +51 -0
  515. package/src/core/step-config/resolve-step-config.ts +199 -0
  516. package/src/core/step-config/run.ts +467 -0
  517. package/src/core/step-config/workflow-evaluation-context.ts +6 -0
  518. package/src/core/step-transition/apply-step-transition.ts +163 -0
  519. package/src/core/step-transition/decide-step-transition.test.ts +307 -0
  520. package/src/core/step-transition/decide-step-transition.ts +200 -0
  521. package/src/core/step-transition/evaluate-gate.test.ts +317 -0
  522. package/src/core/step-transition/evaluate-gate.ts +168 -0
  523. package/src/core/step-transition/read-step-outputs.ts +27 -0
  524. package/src/core/workflow-run-creation.test.ts +155 -0
  525. package/src/core/workflow-run-creation.ts +131 -0
  526. package/src/core/workflow-scheduling/index.ts +15 -0
  527. package/src/core/workflow-scheduling/run-progress.test.ts +46 -0
  528. package/src/core/workflow-scheduling/run-progress.ts +68 -0
  529. package/src/core/workflow-scheduling/runtime-dag.ts +10 -0
  530. package/src/core/workflow-scheduling/runtime-scheduling-command.ts +20 -0
  531. package/src/core/workflow-scheduling/schedule-runtime-dag.test.ts +197 -0
  532. package/src/core/workflow-scheduling/schedule-runtime-dag.ts +115 -0
  533. package/src/db/db.ts +40 -0
  534. package/src/db/index.ts +86 -0
  535. package/src/db/job-listener-events.test.ts +113 -0
  536. package/src/db/job-listener-events.ts +73 -0
  537. package/src/db/job-listeners.test.ts +865 -0
  538. package/src/db/job-listeners.ts +564 -0
  539. package/src/db/outbox-writes.ts +40 -0
  540. package/src/db/rerun-listener.test.ts +64 -0
  541. package/src/db/run-timeout.test.ts +102 -0
  542. package/src/db/runner-lease-table.ts +39 -0
  543. package/src/db/schema/common.ts +3 -0
  544. package/src/db/schema/job-executions.ts +85 -0
  545. package/src/db/schema/job-listener-events.ts +58 -0
  546. package/src/db/schema/jobs.ts +136 -0
  547. package/src/db/schema/outbox.ts +4 -0
  548. package/src/db/schema/step-attempts.ts +99 -0
  549. package/src/db/schema/steps.ts +99 -0
  550. package/src/db/schema/workflow-run-attempts.ts +59 -0
  551. package/src/db/schema/workflow-runs.ts +112 -0
  552. package/src/db/workflow-runs/job-executions.test.ts +99 -0
  553. package/src/db/workflow-runs/job-executions.ts +421 -0
  554. package/src/db/workflow-runs/job-status.test.ts +532 -0
  555. package/src/db/workflow-runs/jobs.test.ts +194 -0
  556. package/src/db/workflow-runs/jobs.ts +418 -0
  557. package/src/db/workflow-runs/outbox.ts +109 -0
  558. package/src/db/workflow-runs/queries.test.ts +256 -0
  559. package/src/db/workflow-runs/queries.ts +437 -0
  560. package/src/db/workflow-runs/run-create.test.ts +1281 -0
  561. package/src/db/workflow-runs/run-create.ts +373 -0
  562. package/src/db/workflow-runs/run-graph.ts +95 -0
  563. package/src/db/workflow-runs/run-rerun.test.ts +625 -0
  564. package/src/db/workflow-runs/run-rerun.ts +266 -0
  565. package/src/db/workflow-runs/run-status.test.ts +425 -0
  566. package/src/db/workflow-runs/run-status.ts +391 -0
  567. package/src/db/workflow-runs/runs.ts +17 -0
  568. package/src/db/workflow-runs/shared.ts +84 -0
  569. package/src/db/workflow-runs/steps.test.ts +191 -0
  570. package/src/db/workflow-runs/steps.ts +476 -0
  571. package/src/db/workflow-runs.ts +111 -0
  572. package/src/index.ts +99 -0
  573. package/src/metrics/index.ts +1 -0
  574. package/src/metrics/instance.ts +160 -0
  575. package/src/metrics/service.ts +30 -0
  576. package/src/presentation/dto/checkout-token.test.ts +107 -0
  577. package/src/presentation/dto/checkout-token.ts +85 -0
  578. package/src/presentation/dto/index.ts +3 -0
  579. package/src/presentation/dto/job.test.ts +108 -0
  580. package/src/presentation/dto/job.ts +64 -0
  581. package/src/presentation/dto/step.test.ts +307 -0
  582. package/src/presentation/dto/step.ts +145 -0
  583. package/src/presentation/dto/workflow-run.ts +38 -0
  584. package/src/presentation/index.ts +10 -0
  585. package/src/presentation/routes/agent-runtime-config.test.ts +478 -0
  586. package/src/presentation/routes/agent-runtime-config.ts +81 -0
  587. package/src/presentation/routes/cancel-run.test.ts +156 -0
  588. package/src/presentation/routes/cancel-run.ts +37 -0
  589. package/src/presentation/routes/checkout-token.test.ts +366 -0
  590. package/src/presentation/routes/checkout-token.ts +61 -0
  591. package/src/presentation/routes/get-run-aggregates.test.ts +114 -0
  592. package/src/presentation/routes/get-run-aggregates.ts +69 -0
  593. package/src/presentation/routes/get-run.test.ts +604 -0
  594. package/src/presentation/routes/get-run.ts +66 -0
  595. package/src/presentation/routes/get-step-secrets.test.ts +260 -0
  596. package/src/presentation/routes/get-step-secrets.ts +117 -0
  597. package/src/presentation/routes/index.test.ts +71 -0
  598. package/src/presentation/routes/index.ts +42 -0
  599. package/src/presentation/routes/leased-step.ts +54 -0
  600. package/src/presentation/routes/list-run-attempts.test.ts +163 -0
  601. package/src/presentation/routes/list-run-attempts.ts +27 -0
  602. package/src/presentation/routes/list-runs.test.ts +244 -0
  603. package/src/presentation/routes/list-runs.ts +83 -0
  604. package/src/presentation/routes/next-step.test.ts +366 -0
  605. package/src/presentation/routes/next-step.ts +62 -0
  606. package/src/presentation/routes/report-step.test.ts +374 -0
  607. package/src/presentation/routes/report-step.ts +61 -0
  608. package/src/presentation/routes/require-accessible-run.ts +27 -0
  609. package/src/presentation/routes/rerun-run.test.ts +202 -0
  610. package/src/presentation/routes/rerun-run.ts +48 -0
  611. package/src/presentation/subscribers/index.ts +7 -0
  612. package/src/presentation/subscribers/on-job-event-delivered.test.ts +71 -0
  613. package/src/presentation/subscribers/on-job-event-delivered.ts +30 -0
  614. package/src/presentation/subscribers/on-job-steps-settled.test.ts +75 -0
  615. package/src/presentation/subscribers/on-job-steps-settled.ts +42 -0
  616. package/src/presentation/subscribers/on-runner-job-claimed.test.ts +57 -0
  617. package/src/presentation/subscribers/on-runner-job-claimed.ts +23 -0
  618. package/src/presentation/subscribers/on-runner-job-lease-expired.test.ts +73 -0
  619. package/src/presentation/subscribers/on-runner-job-lease-expired.ts +36 -0
  620. package/src/presentation/subscribers/on-runner-job-queued.test.ts +57 -0
  621. package/src/presentation/subscribers/on-runner-job-queued.ts +23 -0
  622. package/src/presentation/subscribers/on-workflow-run-attempt-created.test.ts +69 -0
  623. package/src/presentation/subscribers/on-workflow-run-attempt-created.ts +40 -0
  624. package/src/presentation/subscribers/on-workflow-run-cancelled.test.ts +59 -0
  625. package/src/presentation/subscribers/on-workflow-run-cancelled.ts +29 -0
  626. package/src/temporal/activities/index.ts +45 -0
  627. package/src/temporal/activities/orchestration-activities.test.ts +115 -0
  628. package/src/temporal/activities/orchestration-activities.ts +305 -0
  629. package/src/temporal/constants.ts +6 -0
  630. package/src/temporal/index.ts +6 -0
  631. package/src/temporal/workflow-not-found.ts +9 -0
  632. package/src/temporal/workflows/deadline.ts +7 -0
  633. package/src/temporal/workflows/index.ts +11 -0
  634. package/src/temporal/workflows/job-execution-orchestration-timeout.test.ts +165 -0
  635. package/src/temporal/workflows/job-execution-orchestration.test.ts +311 -0
  636. package/src/temporal/workflows/job-execution-orchestration.ts +314 -0
  637. package/src/temporal/workflows/job-listener-orchestration-continuation.test.ts +93 -0
  638. package/src/temporal/workflows/job-listener-orchestration.test.ts +406 -0
  639. package/src/temporal/workflows/job-listener-orchestration.ts +490 -0
  640. package/src/temporal/workflows/run-orchestration.test.ts +409 -0
  641. package/src/temporal/workflows/run-orchestration.ts +283 -0
  642. package/src/temporal/workflows/test-env.ts +409 -0
  643. package/test/env.ts +11 -0
  644. package/test/factories/job.ts +83 -0
  645. package/test/factories/project.ts +16 -0
  646. package/test/factories/workflow-model.test.ts +26 -0
  647. package/test/factories/workflow-model.ts +268 -0
  648. package/test/factories/workflow-run.ts +58 -0
  649. package/test/fixtures/active-lease-token.ts +85 -0
  650. package/test/fixtures/job-with-steps.ts +42 -0
  651. package/test/fixtures/lease-token.ts +44 -0
  652. package/test/fixtures/strip-setup-step.ts +23 -0
  653. package/test/globalSetup.ts +54 -0
  654. package/test/helpers/workflow-runs.ts +210 -0
  655. package/test/index.ts +3 -0
  656. package/test/setup.ts +17 -0
  657. package/tsconfig.build.json +9 -0
  658. package/tsconfig.build.tsbuildinfo +1 -0
  659. package/tsconfig.json +3 -0
  660. package/tsconfig.test.json +8 -0
  661. package/vitest.config.ts +12 -0
@@ -0,0 +1,141 @@
1
+ import { applyStepResult, finishStepAttempt, getStepsByJobExecutionIdForUpdate, rewindStepsToPending, settleJobFailed, writeJobStepsSettledOutbox, writeStepRestartEnqueuedOutbox } from '#db/workflow-runs.js';
2
+ import { deriveCompletion, isTerminal } from './decide-step-transition.js';
3
+ // Durable side of the decision: writes the attempt + projection for a transition,
4
+ // then derives job completion from the post-apply projection and enqueues the
5
+ // completion event in the same transaction. Only called for a running target, so
6
+ // every path here is an actual state change (idempotent no-ops are handled by the
7
+ // caller before deciding).
8
+ export async function applyStepTransition(decision, ctx, tx) {
9
+ switch(decision.kind){
10
+ case 'complete-step':
11
+ case 'complete-job':
12
+ {
13
+ // A passing gate makes a step succeed even if the raw command status was
14
+ // 'failed', so the projection error is cleared regardless of the report.
15
+ await finishStepAttempt({
16
+ stepId: decision.stepId,
17
+ attempt: decision.attempt,
18
+ status: 'succeeded',
19
+ output: ctx.result.output ?? null,
20
+ response: ctx.result.response ?? null,
21
+ exitCode: ctx.result.exitCode ?? null,
22
+ logOutcome: ctx.logOutcome,
23
+ gateResult: ctx.gateResult ?? null
24
+ }, tx);
25
+ await applyStepResult({
26
+ jobExecutionId: ctx.jobExecutionId,
27
+ stepId: decision.stepId,
28
+ status: 'succeeded',
29
+ error: null
30
+ }, tx);
31
+ break;
32
+ }
33
+ case 'fail-job':
34
+ case 'fail-job-restart-exhausted':
35
+ {
36
+ await finishStepAttempt({
37
+ stepId: decision.failedStepId,
38
+ attempt: decision.attempt,
39
+ status: 'failed',
40
+ output: ctx.result.output ?? null,
41
+ response: ctx.result.response ?? null,
42
+ error: decision.failureError,
43
+ exitCode: ctx.result.exitCode ?? null,
44
+ logOutcome: ctx.logOutcome,
45
+ gateResult: ctx.gateResult ?? null
46
+ }, tx);
47
+ const status = await settleJobFailed(tx, {
48
+ jobId: ctx.jobId,
49
+ jobExecutionId: ctx.jobExecutionId,
50
+ failedStepId: decision.failedStepId,
51
+ error: decision.failureError ?? {
52
+ message: 'Step failed'
53
+ }
54
+ });
55
+ if (status !== null) {
56
+ return {
57
+ outcome: {
58
+ jobFinished: true,
59
+ status
60
+ },
61
+ metrics: {
62
+ jobStepsSettledStatus: status
63
+ }
64
+ };
65
+ }
66
+ return {
67
+ outcome: {
68
+ jobFinished: false
69
+ },
70
+ metrics: {}
71
+ };
72
+ }
73
+ case 'restart-job-from-step':
74
+ {
75
+ // Record the failed attempt FIRST (audit, with the restart feedback), then
76
+ // rewind the projection from restart_from so the prior result is preserved
77
+ // only in the attempt history. All in one transaction with the report.
78
+ await finishStepAttempt({
79
+ stepId: decision.failedStepId,
80
+ attempt: decision.attempt,
81
+ status: 'failed',
82
+ output: ctx.result.output ?? null,
83
+ response: ctx.result.response ?? null,
84
+ error: decision.failureError,
85
+ exitCode: ctx.result.exitCode ?? null,
86
+ logOutcome: ctx.logOutcome,
87
+ gateResult: ctx.gateResult ?? null,
88
+ restartFeedback: decision.feedback
89
+ }, tx);
90
+ await rewindStepsToPending({
91
+ jobExecutionId: ctx.jobExecutionId,
92
+ fromPosition: decision.restartFromPosition
93
+ }, tx);
94
+ await writeStepRestartEnqueuedOutbox(tx, {
95
+ jobId: ctx.jobId,
96
+ failedStepId: decision.failedStepId,
97
+ failedStepAttempt: decision.attempt,
98
+ restartFromStepId: decision.restartFromStepId,
99
+ feedback: decision.feedback
100
+ });
101
+ // The job stays running; the next pull re-dispatches restart_from. Do not
102
+ // derive completion or emit a completion event.
103
+ return {
104
+ outcome: {
105
+ jobFinished: false
106
+ },
107
+ metrics: {
108
+ stepRestartEnqueued: true
109
+ }
110
+ };
111
+ }
112
+ }
113
+ // Re-derive completion from the post-apply projection and emit the
114
+ // steps-settled signal exactly once, here on the applied path.
115
+ const after = await getStepsByJobExecutionIdForUpdate(ctx.jobExecutionId, tx);
116
+ if (after.every((step)=>isTerminal(step.status))) {
117
+ const status = deriveCompletion(after);
118
+ await writeJobStepsSettledOutbox(tx, {
119
+ jobId: ctx.jobId,
120
+ jobExecutionId: ctx.jobExecutionId,
121
+ status
122
+ });
123
+ return {
124
+ outcome: {
125
+ jobFinished: true,
126
+ status
127
+ },
128
+ metrics: {
129
+ jobStepsSettledStatus: status
130
+ }
131
+ };
132
+ }
133
+ return {
134
+ outcome: {
135
+ jobFinished: false
136
+ },
137
+ metrics: {}
138
+ };
139
+ }
140
+
141
+ //# sourceMappingURL=apply-step-transition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/step-transition/apply-step-transition.ts"],"sourcesContent":["import type {LogOutcomeDto} from '@shipfox/api-workflows-dto';\nimport type {Tx} from '#db/db.js';\nimport {\n applyStepResult,\n finishStepAttempt,\n getStepsByJobExecutionIdForUpdate,\n rewindStepsToPending,\n settleJobFailed,\n writeJobStepsSettledOutbox,\n writeStepRestartEnqueuedOutbox,\n} from '#db/workflow-runs.js';\nimport {\n deriveCompletion,\n isTerminal,\n type StepReport,\n type StepTransitionDecision,\n} from './decide-step-transition.js';\n\nexport type StepProgressionOutcome =\n | {jobFinished: false}\n | {jobFinished: true; status: 'succeeded' | 'failed'};\n\nexport interface StepProgressionMetrics {\n jobStepsSettledStatus?: 'succeeded' | 'failed';\n stepRestartEnqueued?: boolean;\n}\n\nexport interface StepProgressionResult {\n outcome: StepProgressionOutcome;\n metrics: StepProgressionMetrics;\n}\n\nexport interface ApplyStepTransitionContext {\n jobId: string;\n jobExecutionId: string;\n result: StepReport;\n logOutcome: LogOutcomeDto;\n // Gate evaluation audit payload to record on the attempt, when a gate ran.\n gateResult?: Record<string, unknown> | null;\n}\n\n// Durable side of the decision: writes the attempt + projection for a transition,\n// then derives job completion from the post-apply projection and enqueues the\n// completion event in the same transaction. Only called for a running target, so\n// every path here is an actual state change (idempotent no-ops are handled by the\n// caller before deciding).\nexport async function applyStepTransition(\n decision: StepTransitionDecision,\n ctx: ApplyStepTransitionContext,\n tx: Tx,\n): Promise<StepProgressionResult> {\n switch (decision.kind) {\n case 'complete-step':\n case 'complete-job': {\n // A passing gate makes a step succeed even if the raw command status was\n // 'failed', so the projection error is cleared regardless of the report.\n await finishStepAttempt(\n {\n stepId: decision.stepId,\n attempt: decision.attempt,\n status: 'succeeded',\n output: ctx.result.output ?? null,\n response: ctx.result.response ?? null,\n exitCode: ctx.result.exitCode ?? null,\n logOutcome: ctx.logOutcome,\n gateResult: ctx.gateResult ?? null,\n },\n tx,\n );\n await applyStepResult(\n {\n jobExecutionId: ctx.jobExecutionId,\n stepId: decision.stepId,\n status: 'succeeded',\n error: null,\n },\n tx,\n );\n break;\n }\n case 'fail-job':\n case 'fail-job-restart-exhausted': {\n await finishStepAttempt(\n {\n stepId: decision.failedStepId,\n attempt: decision.attempt,\n status: 'failed',\n output: ctx.result.output ?? null,\n response: ctx.result.response ?? null,\n error: decision.failureError,\n exitCode: ctx.result.exitCode ?? null,\n logOutcome: ctx.logOutcome,\n gateResult: ctx.gateResult ?? null,\n },\n tx,\n );\n const status = await settleJobFailed(tx, {\n jobId: ctx.jobId,\n jobExecutionId: ctx.jobExecutionId,\n failedStepId: decision.failedStepId,\n error: decision.failureError ?? {message: 'Step failed'},\n });\n if (status !== null) {\n return {\n outcome: {jobFinished: true, status},\n metrics: {jobStepsSettledStatus: status},\n };\n }\n return {outcome: {jobFinished: false}, metrics: {}};\n }\n case 'restart-job-from-step': {\n // Record the failed attempt FIRST (audit, with the restart feedback), then\n // rewind the projection from restart_from so the prior result is preserved\n // only in the attempt history. All in one transaction with the report.\n await finishStepAttempt(\n {\n stepId: decision.failedStepId,\n attempt: decision.attempt,\n status: 'failed',\n output: ctx.result.output ?? null,\n response: ctx.result.response ?? null,\n error: decision.failureError,\n exitCode: ctx.result.exitCode ?? null,\n logOutcome: ctx.logOutcome,\n gateResult: ctx.gateResult ?? null,\n restartFeedback: decision.feedback,\n },\n tx,\n );\n await rewindStepsToPending(\n {jobExecutionId: ctx.jobExecutionId, fromPosition: decision.restartFromPosition},\n tx,\n );\n await writeStepRestartEnqueuedOutbox(tx, {\n jobId: ctx.jobId,\n failedStepId: decision.failedStepId,\n failedStepAttempt: decision.attempt,\n restartFromStepId: decision.restartFromStepId,\n feedback: decision.feedback,\n });\n // The job stays running; the next pull re-dispatches restart_from. Do not\n // derive completion or emit a completion event.\n return {outcome: {jobFinished: false}, metrics: {stepRestartEnqueued: true}};\n }\n }\n\n // Re-derive completion from the post-apply projection and emit the\n // steps-settled signal exactly once, here on the applied path.\n const after = await getStepsByJobExecutionIdForUpdate(ctx.jobExecutionId, tx);\n if (after.every((step) => isTerminal(step.status))) {\n const status = deriveCompletion(after);\n await writeJobStepsSettledOutbox(tx, {\n jobId: ctx.jobId,\n jobExecutionId: ctx.jobExecutionId,\n status,\n });\n return {\n outcome: {jobFinished: true, status},\n metrics: {jobStepsSettledStatus: status},\n };\n }\n return {outcome: {jobFinished: false}, metrics: {}};\n}\n"],"names":["applyStepResult","finishStepAttempt","getStepsByJobExecutionIdForUpdate","rewindStepsToPending","settleJobFailed","writeJobStepsSettledOutbox","writeStepRestartEnqueuedOutbox","deriveCompletion","isTerminal","applyStepTransition","decision","ctx","tx","kind","stepId","attempt","status","output","result","response","exitCode","logOutcome","gateResult","jobExecutionId","error","failedStepId","failureError","jobId","message","outcome","jobFinished","metrics","jobStepsSettledStatus","restartFeedback","feedback","fromPosition","restartFromPosition","failedStepAttempt","restartFromStepId","stepRestartEnqueued","after","every","step"],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import type { PersistedEvaluationTraceEntry, Step, StepStatus } from '../entities/step.js';
2
+ export declare function isTerminal(status: StepStatus): boolean;
3
+ export declare function deriveCompletion(steps: Step[]): 'succeeded' | 'failed';
4
+ export interface StepReport {
5
+ status: 'succeeded' | 'failed';
6
+ exitCode?: number | null;
7
+ error?: Record<string, unknown> | null;
8
+ output?: Record<string, unknown> | null;
9
+ response?: string | null;
10
+ }
11
+ export type GateOutcome = {
12
+ kind: 'no-gate';
13
+ } | {
14
+ kind: 'passed';
15
+ source: string;
16
+ trace?: readonly PersistedEvaluationTraceEntry[];
17
+ } | {
18
+ kind: 'failed';
19
+ source: string;
20
+ trace?: readonly PersistedEvaluationTraceEntry[];
21
+ } | {
22
+ kind: 'uncheckable';
23
+ reason: string;
24
+ source?: string;
25
+ trace?: readonly PersistedEvaluationTraceEntry[];
26
+ };
27
+ export interface DecideStepTransitionInput {
28
+ steps: Step[];
29
+ target: Step;
30
+ reportedAttempt: number;
31
+ result: StepReport;
32
+ gateOutcome?: GateOutcome;
33
+ gateOnFailure?: {
34
+ restartFrom: string;
35
+ feedback?: string;
36
+ };
37
+ restartFeedback?: string;
38
+ maxAttempts?: number;
39
+ gatingAttemptCount?: number;
40
+ }
41
+ export declare const DEFAULT_RESTART_ATTEMPT_CAP = 3;
42
+ export type StepTransitionDecision = {
43
+ kind: 'complete-step';
44
+ stepId: string;
45
+ attempt: number;
46
+ } | {
47
+ kind: 'complete-job';
48
+ stepId: string;
49
+ attempt: number;
50
+ } | {
51
+ kind: 'fail-job';
52
+ failedStepId: string;
53
+ attempt: number;
54
+ failureError: Record<string, unknown> | null;
55
+ } | {
56
+ kind: 'restart-job-from-step';
57
+ failedStepId: string;
58
+ restartFromStepId: string;
59
+ restartFromPosition: number;
60
+ attempt: number;
61
+ feedback: string;
62
+ failureError: Record<string, unknown> | null;
63
+ } | {
64
+ kind: 'fail-job-restart-exhausted';
65
+ failedStepId: string;
66
+ attempt: number;
67
+ maxAttempts: number;
68
+ failureError: Record<string, unknown> | null;
69
+ };
70
+ export declare function decideStepTransition(input: DecideStepTransitionInput): StepTransitionDecision;
71
+ //# sourceMappingURL=decide-step-transition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decide-step-transition.d.ts","sourceRoot":"","sources":["../../../src/core/step-transition/decide-step-transition.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ const TERMINAL_STATUSES = new Set([
2
+ 'succeeded',
3
+ 'failed',
4
+ 'cancelled',
5
+ 'skipped'
6
+ ]);
7
+ export function isTerminal(status) {
8
+ return TERMINAL_STATUSES.has(status);
9
+ }
10
+ export function deriveCompletion(steps) {
11
+ return steps.some((step)=>step.status === 'failed') ? 'failed' : 'succeeded';
12
+ }
13
+ // Per-step restart cap: the gating step may run at most this many attempts before
14
+ // a further restart is refused. Bounds runaway restart loops.
15
+ export const DEFAULT_RESTART_ATTEMPT_CAP = 3;
16
+ function succeed(target, attempt, steps) {
17
+ // Completes the job when every other step is already terminal, otherwise just
18
+ // advances this step.
19
+ const everyOtherTerminal = steps.filter((step)=>step.id !== target.id).every((step)=>isTerminal(step.status));
20
+ return everyOtherTerminal ? {
21
+ kind: 'complete-job',
22
+ stepId: target.id,
23
+ attempt
24
+ } : {
25
+ kind: 'complete-step',
26
+ stepId: target.id,
27
+ attempt
28
+ };
29
+ }
30
+ function fail(target, attempt, failureError) {
31
+ return {
32
+ kind: 'fail-job',
33
+ failedStepId: target.id,
34
+ attempt,
35
+ failureError
36
+ };
37
+ }
38
+ // Pure: maps a step report (and its precomputed gate outcome) to a transition
39
+ // decision. No DB, no expression engine. A passing gate succeeds; a checkable
40
+ // failure with a resolvable `restart_from` rewinds (until the per-step attempt cap
41
+ // is hit); everything else fails the job. An `uncheckable` failure (no exit code /
42
+ // eval error) is always a plain failure, never a restart.
43
+ export function decideStepTransition(input) {
44
+ const { steps, target, reportedAttempt, result, gateOnFailure } = input;
45
+ const gate = input.gateOutcome ?? {
46
+ kind: 'no-gate'
47
+ };
48
+ const maxAttempts = input.maxAttempts ?? DEFAULT_RESTART_ATTEMPT_CAP;
49
+ // 1. Did the step pass? The gate (when present and checkable) is authoritative
50
+ // over the raw command status.
51
+ if (gate.kind === 'no-gate' ? result.status === 'succeeded' : gate.kind === 'passed') {
52
+ return succeed(target, reportedAttempt, steps);
53
+ }
54
+ // 2. It failed. Classify the failure error and whether it is restartable.
55
+ // `uncheckable` (no exit code / eval error) is a plain command failure that
56
+ // never restarts.
57
+ const uncheckable = gate.kind === 'uncheckable';
58
+ const failureError = gate.kind === 'failed' ? {
59
+ kind: 'gate_failed',
60
+ message: 'gate condition not met',
61
+ source: gate.source
62
+ } : gate.kind === 'uncheckable' ? result.error ?? {
63
+ kind: 'gate_uncheckable',
64
+ message: gate.reason
65
+ } : result.error ?? null;
66
+ // 3. Restart when a policy is configured and the failure is checkable.
67
+ if (gateOnFailure?.restartFrom && !uncheckable) {
68
+ // Exclude the synthetic setup step: a user step legitimately named "Set up job"
69
+ // would otherwise resolve to position 0 and rewind setup (deleting the workspace
70
+ // mid-job). Duplicate user-step names are already impossible (normalize rejects
71
+ // them with duplicate-step-id), so this is the only collision to guard.
72
+ const restartStep = steps.find((step)=>step.type !== 'setup' && step.position < target.position && step.key === gateOnFailure.restartFrom);
73
+ if (!restartStep) {
74
+ // The model validates restart_from to an earlier named step, but fail closed
75
+ // if it can't be resolved at runtime rather than silently restarting wrong.
76
+ return fail(target, reportedAttempt, {
77
+ kind: 'restart_unresolved',
78
+ message: `could not resolve restart_from "${gateOnFailure.restartFrom}"`,
79
+ restart_from: gateOnFailure.restartFrom
80
+ });
81
+ }
82
+ const gatingAttemptCount = input.gatingAttemptCount ?? reportedAttempt;
83
+ if (gatingAttemptCount >= maxAttempts) {
84
+ return {
85
+ kind: 'fail-job-restart-exhausted',
86
+ failedStepId: target.id,
87
+ attempt: reportedAttempt,
88
+ maxAttempts,
89
+ failureError: {
90
+ kind: 'restart_exhausted',
91
+ maxAttempts,
92
+ restart_from: gateOnFailure.restartFrom
93
+ }
94
+ };
95
+ }
96
+ return {
97
+ kind: 'restart-job-from-step',
98
+ failedStepId: target.id,
99
+ restartFromStepId: restartStep.id,
100
+ restartFromPosition: restartStep.position,
101
+ attempt: reportedAttempt,
102
+ feedback: input.restartFeedback ?? gateOnFailure.feedback ?? 'gate condition not met',
103
+ failureError
104
+ };
105
+ }
106
+ // 4. No restart → plain fail-and-cancel.
107
+ return fail(target, reportedAttempt, failureError);
108
+ }
109
+
110
+ //# sourceMappingURL=decide-step-transition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/step-transition/decide-step-transition.ts"],"sourcesContent":["import type {PersistedEvaluationTraceEntry, Step, StepStatus} from '../entities/step.js';\n\nconst TERMINAL_STATUSES: ReadonlySet<StepStatus> = new Set([\n 'succeeded',\n 'failed',\n 'cancelled',\n 'skipped',\n]);\n\nexport function isTerminal(status: StepStatus): boolean {\n return TERMINAL_STATUSES.has(status);\n}\n\nexport function deriveCompletion(steps: Step[]): 'succeeded' | 'failed' {\n return steps.some((step) => step.status === 'failed') ? 'failed' : 'succeeded';\n}\n\n// The report the runner sent for the step being decided.\nexport interface StepReport {\n status: 'succeeded' | 'failed';\n exitCode?: number | null;\n error?: Record<string, unknown> | null;\n output?: Record<string, unknown> | null;\n response?: string | null;\n}\n\n// Precomputed gate evaluation (the CEL engine runs in evaluate-gate.ts, never\n// here). `passed`/`failed` are clean evaluations; `uncheckable` means the gate\n// could not be evaluated (no exit code, or an evaluation error) and is treated\n// as a plain command failure — never a restart.\nexport type GateOutcome =\n | {kind: 'no-gate'}\n | {kind: 'passed'; source: string; trace?: readonly PersistedEvaluationTraceEntry[]}\n | {kind: 'failed'; source: string; trace?: readonly PersistedEvaluationTraceEntry[]}\n | {\n kind: 'uncheckable';\n reason: string;\n source?: string;\n trace?: readonly PersistedEvaluationTraceEntry[];\n };\n\nexport interface DecideStepTransitionInput {\n // Full job projection, position-ordered (as returned by getStepsByJobIdForUpdate).\n steps: Step[];\n // The reporting step, already confirmed running at `reportedAttempt`.\n target: Step;\n reportedAttempt: number;\n result: StepReport;\n // Precomputed gate evaluation. Absent ⇒ no gate, so `result.status` is authoritative.\n gateOutcome?: GateOutcome;\n // The gate's on_failure policy, if any. Drives the restart branch.\n gateOnFailure?: {restartFrom: string; feedback?: string};\n restartFeedback?: string;\n // Max total attempts for the gating step before restart is exhausted; defaults\n // to DEFAULT_RESTART_ATTEMPT_CAP.\n maxAttempts?: number;\n // The gating step's own execution count (number of its attempts), used for the\n // cap. Defaults to `reportedAttempt` — correct for a single-gate job, where the\n // two are equal; the service passes the real count so a downstream gate in a\n // multi-gate job isn't penalized for upstream-induced rewinds.\n gatingAttemptCount?: number;\n}\n\n// Per-step restart cap: the gating step may run at most this many attempts before\n// a further restart is refused. Bounds runaway restart loops.\nexport const DEFAULT_RESTART_ATTEMPT_CAP = 3;\n\n// The semantic outcome of a step report, independent of persistence.\nexport type StepTransitionDecision =\n | {kind: 'complete-step'; stepId: string; attempt: number}\n // The step succeeds and is the last to finish; apply re-derives the job's\n // terminal status from the projection (it may be `failed` if a sibling was\n // cancelled), so the status is not carried on the decision.\n | {kind: 'complete-job'; stepId: string; attempt: number}\n | {\n kind: 'fail-job';\n failedStepId: string;\n attempt: number;\n // The error to record on the step/attempt (the reported error, or a\n // structured gate error).\n failureError: Record<string, unknown> | null;\n }\n | {\n kind: 'restart-job-from-step';\n failedStepId: string;\n restartFromStepId: string;\n restartFromPosition: number;\n attempt: number;\n feedback: string;\n // Recorded on the failed attempt before the rewind clears the projection.\n failureError: Record<string, unknown> | null;\n }\n | {\n kind: 'fail-job-restart-exhausted';\n failedStepId: string;\n attempt: number;\n maxAttempts: number;\n failureError: Record<string, unknown> | null;\n };\n\nfunction succeed(target: Step, attempt: number, steps: Step[]): StepTransitionDecision {\n // Completes the job when every other step is already terminal, otherwise just\n // advances this step.\n const everyOtherTerminal = steps\n .filter((step) => step.id !== target.id)\n .every((step) => isTerminal(step.status));\n return everyOtherTerminal\n ? {kind: 'complete-job', stepId: target.id, attempt}\n : {kind: 'complete-step', stepId: target.id, attempt};\n}\n\nfunction fail(\n target: Step,\n attempt: number,\n failureError: Record<string, unknown> | null,\n): StepTransitionDecision {\n return {\n kind: 'fail-job',\n failedStepId: target.id,\n attempt,\n failureError,\n };\n}\n\n// Pure: maps a step report (and its precomputed gate outcome) to a transition\n// decision. No DB, no expression engine. A passing gate succeeds; a checkable\n// failure with a resolvable `restart_from` rewinds (until the per-step attempt cap\n// is hit); everything else fails the job. An `uncheckable` failure (no exit code /\n// eval error) is always a plain failure, never a restart.\nexport function decideStepTransition(input: DecideStepTransitionInput): StepTransitionDecision {\n const {steps, target, reportedAttempt, result, gateOnFailure} = input;\n const gate = input.gateOutcome ?? {kind: 'no-gate'};\n const maxAttempts = input.maxAttempts ?? DEFAULT_RESTART_ATTEMPT_CAP;\n\n // 1. Did the step pass? The gate (when present and checkable) is authoritative\n // over the raw command status.\n if (gate.kind === 'no-gate' ? result.status === 'succeeded' : gate.kind === 'passed') {\n return succeed(target, reportedAttempt, steps);\n }\n\n // 2. It failed. Classify the failure error and whether it is restartable.\n // `uncheckable` (no exit code / eval error) is a plain command failure that\n // never restarts.\n const uncheckable = gate.kind === 'uncheckable';\n const failureError: Record<string, unknown> | null =\n gate.kind === 'failed'\n ? {kind: 'gate_failed', message: 'gate condition not met', source: gate.source}\n : gate.kind === 'uncheckable'\n ? (result.error ?? {kind: 'gate_uncheckable', message: gate.reason})\n : (result.error ?? null);\n\n // 3. Restart when a policy is configured and the failure is checkable.\n if (gateOnFailure?.restartFrom && !uncheckable) {\n // Exclude the synthetic setup step: a user step legitimately named \"Set up job\"\n // would otherwise resolve to position 0 and rewind setup (deleting the workspace\n // mid-job). Duplicate user-step names are already impossible (normalize rejects\n // them with duplicate-step-id), so this is the only collision to guard.\n const restartStep = steps.find(\n (step) =>\n step.type !== 'setup' &&\n step.position < target.position &&\n step.key === gateOnFailure.restartFrom,\n );\n if (!restartStep) {\n // The model validates restart_from to an earlier named step, but fail closed\n // if it can't be resolved at runtime rather than silently restarting wrong.\n return fail(target, reportedAttempt, {\n kind: 'restart_unresolved',\n message: `could not resolve restart_from \"${gateOnFailure.restartFrom}\"`,\n restart_from: gateOnFailure.restartFrom,\n });\n }\n const gatingAttemptCount = input.gatingAttemptCount ?? reportedAttempt;\n if (gatingAttemptCount >= maxAttempts) {\n return {\n kind: 'fail-job-restart-exhausted',\n failedStepId: target.id,\n attempt: reportedAttempt,\n maxAttempts,\n failureError: {\n kind: 'restart_exhausted',\n maxAttempts,\n restart_from: gateOnFailure.restartFrom,\n },\n };\n }\n return {\n kind: 'restart-job-from-step',\n failedStepId: target.id,\n restartFromStepId: restartStep.id,\n restartFromPosition: restartStep.position,\n attempt: reportedAttempt,\n feedback: input.restartFeedback ?? gateOnFailure.feedback ?? 'gate condition not met',\n failureError,\n };\n }\n\n // 4. No restart → plain fail-and-cancel.\n return fail(target, reportedAttempt, failureError);\n}\n"],"names":["TERMINAL_STATUSES","Set","isTerminal","status","has","deriveCompletion","steps","some","step","DEFAULT_RESTART_ATTEMPT_CAP","succeed","target","attempt","everyOtherTerminal","filter","id","every","kind","stepId","fail","failureError","failedStepId","decideStepTransition","input","reportedAttempt","result","gateOnFailure","gate","gateOutcome","maxAttempts","uncheckable","message","source","error","reason","restartFrom","restartStep","find","type","position","key","restart_from","gatingAttemptCount","restartFromStepId","restartFromPosition","feedback","restartFeedback"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { type ResolvedField, type WorkflowExpression } from '@shipfox/expression';
2
+ import type { GateOutcome, StepReport } from './decide-step-transition.js';
3
+ export declare const GATE_EVALUATION_ERROR_REASON = "gate expression evaluation failed";
4
+ export interface StepGate {
5
+ success?: WorkflowExpression;
6
+ onFailure?: {
7
+ restartFrom: string;
8
+ feedback?: string;
9
+ feedbackTemplate?: ResolvedField;
10
+ };
11
+ }
12
+ export declare function readStepGate(config: Record<string, unknown>): StepGate | undefined;
13
+ /**
14
+ * Gate evaluation fails closed: a missing exit code or CEL evaluation error is
15
+ * `uncheckable` (a plain command failure), never a gate failure that can restart.
16
+ *
17
+ * Callers hold step-row locks while this runs. Keep the CEL context bounded
18
+ * unless evaluation gets a budget outside the lock. The materializer only
19
+ * persists CEL expressions, and this evaluator only needs the validated source.
20
+ */
21
+ export declare function evaluateGate(gate: StepGate | undefined, result: StepReport): GateOutcome;
22
+ export declare function evaluateGateFeedback(params: {
23
+ readonly gate: StepGate;
24
+ readonly result: StepReport;
25
+ readonly definitionId: string;
26
+ }): string;
27
+ export declare function gateResultPayload(outcome: GateOutcome, exitCode: number | null | undefined): Record<string, unknown> | null;
28
+ //# sourceMappingURL=evaluate-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate-gate.d.ts","sourceRoot":"","sources":["../../../src/core/step-transition/evaluate-gate.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,KAAK,EAAC,WAAW,EAAE,UAAU,EAAC,MAAM,6BAA6B,CAAC;AAMzE,eAAO,MAAM,4BAA4B,sCAAsC,CAAC;AAGhF,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,SAAS,CAAC,EAAE;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,aAAa,CAAA;KAAC,CAAC;CACxF;AAID,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,GAAG,SAAS,CAoClF;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,WAAW,CAmCxF;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,GAAG,MAAM,CAkBT;AAKD,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CA6BhC"}
@@ -0,0 +1,159 @@
1
+ import { capTraceEntries, evaluatePlannedPredicateAtSite, predicateTraceEntry } from '@shipfox/expression';
2
+ import { assembleGateContext } from '../step-config/assemble-run-context.js';
3
+ import { completeStepField } from '../step-config/fields.js';
4
+ // The exact `uncheckable` reason recorded when the gate's CEL expression itself
5
+ // throws (as opposed to a missing exit code). The DTO mapper keys on this string to
6
+ // surface a distinct `evaluation_error` gate result, so the producer and the mapper
7
+ // must share this constant rather than duplicating the literal.
8
+ export const GATE_EVALUATION_ERROR_REASON = 'gate expression evaluation failed';
9
+ // Read the gate persisted on a step's config by the materializer. Returns
10
+ // undefined when the step has no gate of interest.
11
+ export function readStepGate(config) {
12
+ const gate = config.gate;
13
+ if (!gate || typeof gate !== 'object') return undefined;
14
+ const raw = gate;
15
+ const successRaw = raw.success;
16
+ const success = successRaw && typeof successRaw.source === 'string' ? // JSON is structurally a WorkflowExpression.
17
+ successRaw : undefined;
18
+ const onFailureRaw = raw.on_failure;
19
+ const feedbackTemplateRaw = onFailureRaw?.feedback_template;
20
+ const feedbackTemplate = Array.isArray(feedbackTemplateRaw?.segments) && feedbackTemplateRaw.segments.every((segment)=>typeof segment === 'object' && segment !== null) ? feedbackTemplateRaw : undefined;
21
+ const onFailure = onFailureRaw && typeof onFailureRaw.restart_from === 'string' ? {
22
+ restartFrom: onFailureRaw.restart_from,
23
+ ...typeof onFailureRaw.feedback === 'string' ? {
24
+ feedback: onFailureRaw.feedback
25
+ } : {},
26
+ ...feedbackTemplate === undefined ? {} : {
27
+ feedbackTemplate
28
+ }
29
+ } : undefined;
30
+ if (!success && !onFailure) return undefined;
31
+ return {
32
+ ...success ? {
33
+ success
34
+ } : {},
35
+ ...onFailure ? {
36
+ onFailure
37
+ } : {}
38
+ };
39
+ }
40
+ /**
41
+ * Gate evaluation fails closed: a missing exit code or CEL evaluation error is
42
+ * `uncheckable` (a plain command failure), never a gate failure that can restart.
43
+ *
44
+ * Callers hold step-row locks while this runs. Keep the CEL context bounded
45
+ * unless evaluation gets a budget outside the lock. The materializer only
46
+ * persists CEL expressions, and this evaluator only needs the validated source.
47
+ */ export function evaluateGate(gate, result) {
48
+ if (!gate?.success) return {
49
+ kind: 'no-gate'
50
+ };
51
+ const source = gate.success.source;
52
+ if (result.exitCode === null || result.exitCode === undefined) {
53
+ return {
54
+ kind: 'uncheckable',
55
+ reason: 'step produced no exit code'
56
+ };
57
+ }
58
+ const context = assembleGateContext({
59
+ status: result.status,
60
+ exitCode: result.exitCode,
61
+ output: result.output
62
+ });
63
+ const outcome = evaluatePlannedPredicateAtSite({
64
+ expression: gate.success,
65
+ field: 'step.success',
66
+ site: context.site,
67
+ context: context.values
68
+ });
69
+ const trace = capTraceEntries([
70
+ {
71
+ ...predicateTraceEntry({
72
+ expression: source,
73
+ route: outcome.route,
74
+ site: context.site,
75
+ value: outcome.value,
76
+ degraded: outcome.evaluationFailed
77
+ }),
78
+ field: 'step.success'
79
+ }
80
+ ]);
81
+ if (outcome.evaluationFailed) {
82
+ return {
83
+ kind: 'uncheckable',
84
+ reason: GATE_EVALUATION_ERROR_REASON,
85
+ source,
86
+ trace
87
+ };
88
+ }
89
+ return outcome.value ? {
90
+ kind: 'passed',
91
+ source,
92
+ trace
93
+ } : {
94
+ kind: 'failed',
95
+ source,
96
+ trace
97
+ };
98
+ }
99
+ export function evaluateGateFeedback(params) {
100
+ const feedbackTemplate = params.gate.onFailure?.feedbackTemplate;
101
+ if (feedbackTemplate === undefined) {
102
+ return params.gate.onFailure?.feedback ?? 'gate condition not met';
103
+ }
104
+ const context = assembleGateContext({
105
+ status: params.result.status,
106
+ exitCode: params.result.exitCode ?? null,
107
+ output: params.result.output
108
+ });
109
+ return completeStepField({
110
+ field: 'step.feedback',
111
+ errorField: 'step.feedback',
112
+ template: feedbackTemplate,
113
+ context,
114
+ definitionId: params.definitionId
115
+ });
116
+ }
117
+ // Build the audit payload recorded on the step attempt for a gate evaluation.
118
+ // Includes the evaluated `exit_code` so the gate decision is reconstructable from
119
+ // the attempt row alone, independent of the column shape.
120
+ export function gateResultPayload(outcome, exitCode) {
121
+ const exit_code = exitCode ?? null;
122
+ switch(outcome.kind){
123
+ case 'no-gate':
124
+ return null;
125
+ case 'passed':
126
+ return {
127
+ passed: true,
128
+ source: outcome.source,
129
+ exit_code,
130
+ ...outcome.trace === undefined ? {} : {
131
+ trace: outcome.trace
132
+ }
133
+ };
134
+ case 'failed':
135
+ return {
136
+ passed: false,
137
+ source: outcome.source,
138
+ exit_code,
139
+ ...outcome.trace === undefined ? {} : {
140
+ trace: outcome.trace
141
+ }
142
+ };
143
+ case 'uncheckable':
144
+ return {
145
+ passed: false,
146
+ uncheckable: true,
147
+ reason: outcome.reason,
148
+ exit_code,
149
+ ...outcome.source === undefined ? {} : {
150
+ source: outcome.source
151
+ },
152
+ ...outcome.trace === undefined ? {} : {
153
+ trace: outcome.trace
154
+ }
155
+ };
156
+ }
157
+ }
158
+
159
+ //# sourceMappingURL=evaluate-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/step-transition/evaluate-gate.ts"],"sourcesContent":["import {\n capTraceEntries,\n evaluatePlannedPredicateAtSite,\n predicateTraceEntry,\n type ResolvedField,\n type WorkflowExpression,\n} from '@shipfox/expression';\nimport {assembleGateContext} from '../step-config/assemble-run-context.js';\nimport {completeStepField} from '../step-config/fields.js';\nimport type {GateOutcome, StepReport} from './decide-step-transition.js';\n\n// The exact `uncheckable` reason recorded when the gate's CEL expression itself\n// throws (as opposed to a missing exit code). The DTO mapper keys on this string to\n// surface a distinct `evaluation_error` gate result, so the producer and the mapper\n// must share this constant rather than duplicating the literal.\nexport const GATE_EVALUATION_ERROR_REASON = 'gate expression evaluation failed';\n\n// The gate as parsed from a step's materialized `config.gate` (snake_case JSON).\nexport interface StepGate {\n success?: WorkflowExpression;\n onFailure?: {restartFrom: string; feedback?: string; feedbackTemplate?: ResolvedField};\n}\n\n// Read the gate persisted on a step's config by the materializer. Returns\n// undefined when the step has no gate of interest.\nexport function readStepGate(config: Record<string, unknown>): StepGate | undefined {\n const gate = config.gate;\n if (!gate || typeof gate !== 'object') return undefined;\n const raw = gate as Record<string, unknown>;\n\n const successRaw = raw.success as Record<string, unknown> | undefined;\n const success =\n successRaw && typeof successRaw.source === 'string'\n ? // The model validated this expression before materialization; the stored\n // JSON is structurally a WorkflowExpression.\n (successRaw as unknown as WorkflowExpression)\n : undefined;\n\n const onFailureRaw = raw.on_failure as Record<string, unknown> | undefined;\n const feedbackTemplateRaw = onFailureRaw?.feedback_template as\n | Record<string, unknown>\n | undefined;\n const feedbackTemplate =\n Array.isArray(feedbackTemplateRaw?.segments) &&\n feedbackTemplateRaw.segments.every((segment) => typeof segment === 'object' && segment !== null)\n ? (feedbackTemplateRaw as unknown as ResolvedField)\n : undefined;\n const onFailure =\n onFailureRaw && typeof onFailureRaw.restart_from === 'string'\n ? {\n restartFrom: onFailureRaw.restart_from,\n ...(typeof onFailureRaw.feedback === 'string' ? {feedback: onFailureRaw.feedback} : {}),\n ...(feedbackTemplate === undefined ? {} : {feedbackTemplate}),\n }\n : undefined;\n\n if (!success && !onFailure) return undefined;\n return {\n ...(success ? {success} : {}),\n ...(onFailure ? {onFailure} : {}),\n };\n}\n\n/**\n * Gate evaluation fails closed: a missing exit code or CEL evaluation error is\n * `uncheckable` (a plain command failure), never a gate failure that can restart.\n *\n * Callers hold step-row locks while this runs. Keep the CEL context bounded\n * unless evaluation gets a budget outside the lock. The materializer only\n * persists CEL expressions, and this evaluator only needs the validated source.\n */\nexport function evaluateGate(gate: StepGate | undefined, result: StepReport): GateOutcome {\n if (!gate?.success) return {kind: 'no-gate'};\n const source = gate.success.source;\n\n if (result.exitCode === null || result.exitCode === undefined) {\n return {kind: 'uncheckable', reason: 'step produced no exit code'};\n }\n\n const context = assembleGateContext({\n status: result.status,\n exitCode: result.exitCode,\n output: result.output,\n });\n const outcome = evaluatePlannedPredicateAtSite({\n expression: gate.success,\n field: 'step.success',\n site: context.site,\n context: context.values,\n });\n const trace = capTraceEntries([\n {\n ...predicateTraceEntry({\n expression: source,\n route: outcome.route,\n site: context.site,\n value: outcome.value,\n degraded: outcome.evaluationFailed,\n }),\n field: 'step.success',\n },\n ]);\n if (outcome.evaluationFailed) {\n return {kind: 'uncheckable', reason: GATE_EVALUATION_ERROR_REASON, source, trace};\n }\n return outcome.value ? {kind: 'passed', source, trace} : {kind: 'failed', source, trace};\n}\n\nexport function evaluateGateFeedback(params: {\n readonly gate: StepGate;\n readonly result: StepReport;\n readonly definitionId: string;\n}): string {\n const feedbackTemplate = params.gate.onFailure?.feedbackTemplate;\n if (feedbackTemplate === undefined) {\n return params.gate.onFailure?.feedback ?? 'gate condition not met';\n }\n\n const context = assembleGateContext({\n status: params.result.status,\n exitCode: params.result.exitCode ?? null,\n output: params.result.output,\n });\n return completeStepField({\n field: 'step.feedback',\n errorField: 'step.feedback',\n template: feedbackTemplate,\n context,\n definitionId: params.definitionId,\n });\n}\n\n// Build the audit payload recorded on the step attempt for a gate evaluation.\n// Includes the evaluated `exit_code` so the gate decision is reconstructable from\n// the attempt row alone, independent of the column shape.\nexport function gateResultPayload(\n outcome: GateOutcome,\n exitCode: number | null | undefined,\n): Record<string, unknown> | null {\n const exit_code = exitCode ?? null;\n switch (outcome.kind) {\n case 'no-gate':\n return null;\n case 'passed':\n return {\n passed: true,\n source: outcome.source,\n exit_code,\n ...(outcome.trace === undefined ? {} : {trace: outcome.trace}),\n };\n case 'failed':\n return {\n passed: false,\n source: outcome.source,\n exit_code,\n ...(outcome.trace === undefined ? {} : {trace: outcome.trace}),\n };\n case 'uncheckable':\n return {\n passed: false,\n uncheckable: true,\n reason: outcome.reason,\n exit_code,\n ...(outcome.source === undefined ? {} : {source: outcome.source}),\n ...(outcome.trace === undefined ? {} : {trace: outcome.trace}),\n };\n }\n}\n"],"names":["capTraceEntries","evaluatePlannedPredicateAtSite","predicateTraceEntry","assembleGateContext","completeStepField","GATE_EVALUATION_ERROR_REASON","readStepGate","config","gate","undefined","raw","successRaw","success","source","onFailureRaw","on_failure","feedbackTemplateRaw","feedback_template","feedbackTemplate","Array","isArray","segments","every","segment","onFailure","restart_from","restartFrom","feedback","evaluateGate","result","kind","exitCode","reason","context","status","output","outcome","expression","field","site","values","trace","route","value","degraded","evaluationFailed","evaluateGateFeedback","params","errorField","template","definitionId","gateResultPayload","exit_code","passed","uncheckable"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type OutputDeclarations } from '@shipfox/expression';
2
+ export declare function readStepOutputs(config: Record<string, unknown>): OutputDeclarations | undefined;
3
+ //# sourceMappingURL=read-step-outputs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-step-outputs.d.ts","sourceRoot":"","sources":["../../../src/core/step-transition/read-step-outputs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,KAAK,kBAAkB,EAAc,MAAM,qBAAqB,CAAC;AAIzE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,kBAAkB,GAAG,SAAS,CAkB/F"}
@@ -0,0 +1,24 @@
1
+ import { outputTypes } from '@shipfox/expression';
2
+ const outputTypeSet = new Set(outputTypes);
3
+ export function readStepOutputs(config) {
4
+ const outputs = config.outputs;
5
+ if (!isRecord(outputs)) return undefined;
6
+ const declarations = Object.create(null);
7
+ for (const [key, declaration] of Object.entries(outputs)){
8
+ if (!isRecord(declaration)) return undefined;
9
+ const type = declaration.type;
10
+ if (typeof type !== 'string' || !outputTypeSet.has(type)) return undefined;
11
+ declarations[key] = {
12
+ type: type,
13
+ ...!Object.hasOwn(declaration, 'schema') ? {} : {
14
+ schema: declaration.schema
15
+ }
16
+ };
17
+ }
18
+ return declarations;
19
+ }
20
+ function isRecord(value) {
21
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
22
+ }
23
+
24
+ //# sourceMappingURL=read-step-outputs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/core/step-transition/read-step-outputs.ts"],"sourcesContent":["import {type OutputDeclarations, outputTypes} from '@shipfox/expression';\n\nconst outputTypeSet = new Set<string>(outputTypes);\n\nexport function readStepOutputs(config: Record<string, unknown>): OutputDeclarations | undefined {\n const outputs = config.outputs;\n if (!isRecord(outputs)) return undefined;\n\n const declarations: Record<string, {type: (typeof outputTypes)[number]; schema?: unknown}> =\n Object.create(null) as Record<string, {type: (typeof outputTypes)[number]; schema?: unknown}>;\n\n for (const [key, declaration] of Object.entries(outputs)) {\n if (!isRecord(declaration)) return undefined;\n const type = declaration.type;\n if (typeof type !== 'string' || !outputTypeSet.has(type)) return undefined;\n declarations[key] = {\n type: type as (typeof outputTypes)[number],\n ...(!Object.hasOwn(declaration, 'schema') ? {} : {schema: declaration.schema}),\n };\n }\n\n return declarations;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"],"names":["outputTypes","outputTypeSet","Set","readStepOutputs","config","outputs","isRecord","undefined","declarations","Object","create","key","declaration","entries","type","has","hasOwn","schema","value","Array","isArray"],"mappings":"AAAA,SAAiCA,WAAW,QAAO,sBAAsB;AAEzE,MAAMC,gBAAgB,IAAIC,IAAYF;AAEtC,OAAO,SAASG,gBAAgBC,MAA+B;IAC7D,MAAMC,UAAUD,OAAOC,OAAO;IAC9B,IAAI,CAACC,SAASD,UAAU,OAAOE;IAE/B,MAAMC,eACJC,OAAOC,MAAM,CAAC;IAEhB,KAAK,MAAM,CAACC,KAAKC,YAAY,IAAIH,OAAOI,OAAO,CAACR,SAAU;QACxD,IAAI,CAACC,SAASM,cAAc,OAAOL;QACnC,MAAMO,OAAOF,YAAYE,IAAI;QAC7B,IAAI,OAAOA,SAAS,YAAY,CAACb,cAAcc,GAAG,CAACD,OAAO,OAAOP;QACjEC,YAAY,CAACG,IAAI,GAAG;YAClBG,MAAMA;YACN,GAAI,CAACL,OAAOO,MAAM,CAACJ,aAAa,YAAY,CAAC,IAAI;gBAACK,QAAQL,YAAYK,MAAM;YAAA,CAAC;QAC/E;IACF;IAEA,OAAOT;AACT;AAEA,SAASF,SAASY,KAAc;IAC9B,OAAO,OAAOA,UAAU,YAAYA,UAAU,QAAQ,CAACC,MAAMC,OAAO,CAACF;AACvE"}