@shipfox/api-workflows 10.2.0 → 12.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 (354) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/CHANGELOG.md +117 -0
  3. package/README.md +75 -0
  4. package/dist/core/agent-defaults.d.ts +2 -1
  5. package/dist/core/agent-defaults.d.ts.map +1 -1
  6. package/dist/core/agent-defaults.js.map +1 -1
  7. package/dist/core/checkout.d.ts +7 -21
  8. package/dist/core/checkout.d.ts.map +1 -1
  9. package/dist/core/checkout.js +122 -41
  10. package/dist/core/checkout.js.map +1 -1
  11. package/dist/core/entities/job-execution.d.ts +8 -0
  12. package/dist/core/entities/job-execution.d.ts.map +1 -1
  13. package/dist/core/entities/job-execution.js +13 -1
  14. package/dist/core/entities/job-execution.js.map +1 -1
  15. package/dist/core/entities/job-listener-event.d.ts +2 -0
  16. package/dist/core/entities/job-listener-event.d.ts.map +1 -1
  17. package/dist/core/entities/job-listener-event.js.map +1 -1
  18. package/dist/core/entities/step.d.ts +13 -3
  19. package/dist/core/entities/step.d.ts.map +1 -1
  20. package/dist/core/entities/step.js +6 -0
  21. package/dist/core/entities/step.js.map +1 -1
  22. package/dist/core/entities/workflow-run-attempt.d.ts +1 -0
  23. package/dist/core/entities/workflow-run-attempt.d.ts.map +1 -1
  24. package/dist/core/entities/workflow-run-attempt.js.map +1 -1
  25. package/dist/core/entities/workflow-run.d.ts +17 -0
  26. package/dist/core/entities/workflow-run.d.ts.map +1 -1
  27. package/dist/core/entities/workflow-run.js.map +1 -1
  28. package/dist/core/errors.d.ts +9 -2
  29. package/dist/core/errors.d.ts.map +1 -1
  30. package/dist/core/errors.js +10 -5
  31. package/dist/core/errors.js.map +1 -1
  32. package/dist/core/job-execution.d.ts.map +1 -1
  33. package/dist/core/job-execution.js +14 -8
  34. package/dist/core/job-execution.js.map +1 -1
  35. package/dist/core/job-transition/decide-job-activation.d.ts +1 -0
  36. package/dist/core/job-transition/decide-job-activation.d.ts.map +1 -1
  37. package/dist/core/job-transition/decide-job-activation.js +1 -0
  38. package/dist/core/job-transition/decide-job-activation.js.map +1 -1
  39. package/dist/core/job-transition/derive-job-success.d.ts +1 -0
  40. package/dist/core/job-transition/derive-job-success.d.ts.map +1 -1
  41. package/dist/core/job-transition/derive-job-success.js +5 -8
  42. package/dist/core/job-transition/derive-job-success.js.map +1 -1
  43. package/dist/core/listener-execution-materialization.d.ts +6 -3
  44. package/dist/core/listener-execution-materialization.d.ts.map +1 -1
  45. package/dist/core/listener-execution-materialization.js +44 -6
  46. package/dist/core/listener-execution-materialization.js.map +1 -1
  47. package/dist/core/resolve-trigger-reference.d.ts +11 -0
  48. package/dist/core/resolve-trigger-reference.d.ts.map +1 -0
  49. package/dist/core/resolve-trigger-reference.js +39 -0
  50. package/dist/core/resolve-trigger-reference.js.map +1 -0
  51. package/dist/core/run-workflow.d.ts +1 -0
  52. package/dist/core/run-workflow.d.ts.map +1 -1
  53. package/dist/core/run-workflow.js +1 -0
  54. package/dist/core/run-workflow.js.map +1 -1
  55. package/dist/core/step-config/agent.d.ts +1 -2
  56. package/dist/core/step-config/agent.d.ts.map +1 -1
  57. package/dist/core/step-config/agent.js +22 -7
  58. package/dist/core/step-config/agent.js.map +1 -1
  59. package/dist/core/step-config/assemble-run-context.d.ts +19 -8
  60. package/dist/core/step-config/assemble-run-context.d.ts.map +1 -1
  61. package/dist/core/step-config/assemble-run-context.js +51 -19
  62. package/dist/core/step-config/assemble-run-context.js.map +1 -1
  63. package/dist/core/step-config/complete-step-dispatch-config.d.ts.map +1 -1
  64. package/dist/core/step-config/complete-step-dispatch-config.js +72 -4
  65. package/dist/core/step-config/complete-step-dispatch-config.js.map +1 -1
  66. package/dist/core/step-config/index.d.ts +1 -0
  67. package/dist/core/step-config/index.d.ts.map +1 -1
  68. package/dist/core/step-config/index.js +1 -0
  69. package/dist/core/step-config/index.js.map +1 -1
  70. package/dist/core/step-config/materialize-job-execution-steps.d.ts +1 -1
  71. package/dist/core/step-config/materialize-job-execution-steps.d.ts.map +1 -1
  72. package/dist/core/step-config/materialize-job-execution-steps.js +49 -8
  73. package/dist/core/step-config/materialize-job-execution-steps.js.map +1 -1
  74. package/dist/core/step-config/materialize-workflow-model.d.ts +3 -3
  75. package/dist/core/step-config/materialize-workflow-model.d.ts.map +1 -1
  76. package/dist/core/step-config/materialize-workflow-model.js +9 -5
  77. package/dist/core/step-config/materialize-workflow-model.js.map +1 -1
  78. package/dist/core/step-config/resolve-job-execution-name.d.ts +3 -3
  79. package/dist/core/step-config/resolve-job-execution-name.d.ts.map +1 -1
  80. package/dist/core/step-config/resolve-job-execution-name.js +24 -13
  81. package/dist/core/step-config/resolve-job-execution-name.js.map +1 -1
  82. package/dist/core/step-config/resolve-step-config.d.ts.map +1 -1
  83. package/dist/core/step-config/resolve-step-config.js +174 -9
  84. package/dist/core/step-config/resolve-step-config.js.map +1 -1
  85. package/dist/core/step-config/resolve-workflow-run-name.d.ts +19 -0
  86. package/dist/core/step-config/resolve-workflow-run-name.d.ts.map +1 -0
  87. package/dist/core/step-config/resolve-workflow-run-name.js +73 -0
  88. package/dist/core/step-config/resolve-workflow-run-name.js.map +1 -0
  89. package/dist/core/step-transition/decide-step-transition.js.map +1 -1
  90. package/dist/core/step-transition/evaluate-gate.d.ts +2 -1
  91. package/dist/core/step-transition/evaluate-gate.d.ts.map +1 -1
  92. package/dist/core/step-transition/evaluate-gate.js +5 -3
  93. package/dist/core/step-transition/evaluate-gate.js.map +1 -1
  94. package/dist/core/workflow-run-creation.d.ts +3 -0
  95. package/dist/core/workflow-run-creation.d.ts.map +1 -1
  96. package/dist/core/workflow-run-creation.js +22 -7
  97. package/dist/core/workflow-run-creation.js.map +1 -1
  98. package/dist/db/db.d.ts +278 -10
  99. package/dist/db/db.d.ts.map +1 -1
  100. package/dist/db/db.js +2 -0
  101. package/dist/db/db.js.map +1 -1
  102. package/dist/db/index.d.ts +3 -2
  103. package/dist/db/index.d.ts.map +1 -1
  104. package/dist/db/index.js +2 -1
  105. package/dist/db/index.js.map +1 -1
  106. package/dist/db/job-listener-events.d.ts +2 -0
  107. package/dist/db/job-listener-events.d.ts.map +1 -1
  108. package/dist/db/job-listener-events.js +1 -0
  109. package/dist/db/job-listener-events.js.map +1 -1
  110. package/dist/db/job-listeners.d.ts +2 -0
  111. package/dist/db/job-listeners.d.ts.map +1 -1
  112. package/dist/db/job-listeners.js +81 -21
  113. package/dist/db/job-listeners.js.map +1 -1
  114. package/dist/db/schema/job-executions.d.ts +3 -3
  115. package/dist/db/schema/job-executions.d.ts.map +1 -1
  116. package/dist/db/schema/job-executions.js +8 -4
  117. package/dist/db/schema/job-executions.js.map +1 -1
  118. package/dist/db/schema/job-listener-events.d.ts +20 -0
  119. package/dist/db/schema/job-listener-events.d.ts.map +1 -1
  120. package/dist/db/schema/job-listener-events.js +2 -0
  121. package/dist/db/schema/job-listener-events.js.map +1 -1
  122. package/dist/db/schema/step-attempts.js +2 -2
  123. package/dist/db/schema/step-attempts.js.map +1 -1
  124. package/dist/db/schema/steps.d.ts +4 -2
  125. package/dist/db/schema/steps.d.ts.map +1 -1
  126. package/dist/db/schema/steps.js +1 -1
  127. package/dist/db/schema/steps.js.map +1 -1
  128. package/dist/db/schema/workflow-run-attempts.d.ts +21 -2
  129. package/dist/db/schema/workflow-run-attempts.d.ts.map +1 -1
  130. package/dist/db/schema/workflow-run-attempts.js +2 -0
  131. package/dist/db/schema/workflow-run-attempts.js.map +1 -1
  132. package/dist/db/schema/workflow-run-counters.d.ts +43 -0
  133. package/dist/db/schema/workflow-run-counters.d.ts.map +1 -0
  134. package/dist/db/schema/workflow-run-counters.js +10 -0
  135. package/dist/db/schema/workflow-run-counters.js.map +1 -0
  136. package/dist/db/schema/workflow-runs.d.ts +54 -1
  137. package/dist/db/schema/workflow-runs.d.ts.map +1 -1
  138. package/dist/db/schema/workflow-runs.js +10 -2
  139. package/dist/db/schema/workflow-runs.js.map +1 -1
  140. package/dist/db/workflow-runs/job-executions.d.ts.map +1 -1
  141. package/dist/db/workflow-runs/job-executions.js +35 -14
  142. package/dist/db/workflow-runs/job-executions.js.map +1 -1
  143. package/dist/db/workflow-runs/jobs.d.ts +2 -0
  144. package/dist/db/workflow-runs/jobs.d.ts.map +1 -1
  145. package/dist/db/workflow-runs/jobs.js +9 -5
  146. package/dist/db/workflow-runs/jobs.js.map +1 -1
  147. package/dist/db/workflow-runs/queries.d.ts +51 -0
  148. package/dist/db/workflow-runs/queries.d.ts.map +1 -1
  149. package/dist/db/workflow-runs/queries.js +82 -2
  150. package/dist/db/workflow-runs/queries.js.map +1 -1
  151. package/dist/db/workflow-runs/run-create.d.ts +1 -0
  152. package/dist/db/workflow-runs/run-create.d.ts.map +1 -1
  153. package/dist/db/workflow-runs/run-create.js +159 -32
  154. package/dist/db/workflow-runs/run-create.js.map +1 -1
  155. package/dist/db/workflow-runs/run-rerun.d.ts.map +1 -1
  156. package/dist/db/workflow-runs/run-rerun.js +13 -5
  157. package/dist/db/workflow-runs/run-rerun.js.map +1 -1
  158. package/dist/db/workflow-runs/shared.d.ts +1 -0
  159. package/dist/db/workflow-runs/shared.d.ts.map +1 -1
  160. package/dist/db/workflow-runs/shared.js +2 -1
  161. package/dist/db/workflow-runs/shared.js.map +1 -1
  162. package/dist/db/workflow-runs/steps.js +3 -3
  163. package/dist/db/workflow-runs/steps.js.map +1 -1
  164. package/dist/db/workflow-runs.d.ts +4 -3
  165. package/dist/db/workflow-runs.d.ts.map +1 -1
  166. package/dist/db/workflow-runs.js +3 -2
  167. package/dist/db/workflow-runs.js.map +1 -1
  168. package/dist/metrics/instance.d.ts +1 -0
  169. package/dist/metrics/instance.d.ts.map +1 -1
  170. package/dist/metrics/instance.js +9 -0
  171. package/dist/metrics/instance.js.map +1 -1
  172. package/dist/presentation/dto/checkout-token.d.ts +1 -0
  173. package/dist/presentation/dto/checkout-token.d.ts.map +1 -1
  174. package/dist/presentation/dto/checkout-token.js +1 -0
  175. package/dist/presentation/dto/checkout-token.js.map +1 -1
  176. package/dist/presentation/dto/index.d.ts +1 -1
  177. package/dist/presentation/dto/index.d.ts.map +1 -1
  178. package/dist/presentation/dto/index.js +1 -1
  179. package/dist/presentation/dto/index.js.map +1 -1
  180. package/dist/presentation/dto/step.d.ts.map +1 -1
  181. package/dist/presentation/dto/step.js +2 -2
  182. package/dist/presentation/dto/step.js.map +1 -1
  183. package/dist/presentation/dto/workflow-run.d.ts +3 -1
  184. package/dist/presentation/dto/workflow-run.d.ts.map +1 -1
  185. package/dist/presentation/dto/workflow-run.js +34 -0
  186. package/dist/presentation/dto/workflow-run.js.map +1 -1
  187. package/dist/presentation/inter-module.d.ts.map +1 -1
  188. package/dist/presentation/inter-module.js +31 -3
  189. package/dist/presentation/inter-module.js.map +1 -1
  190. package/dist/presentation/routes/checkout-token.d.ts +1 -1
  191. package/dist/presentation/routes/checkout-token.d.ts.map +1 -1
  192. package/dist/presentation/routes/checkout-token.js +32 -20
  193. package/dist/presentation/routes/checkout-token.js.map +1 -1
  194. package/dist/presentation/routes/leased-step.d.ts +2 -0
  195. package/dist/presentation/routes/leased-step.d.ts.map +1 -1
  196. package/dist/presentation/routes/leased-step.js +2 -1
  197. package/dist/presentation/routes/leased-step.js.map +1 -1
  198. package/dist/presentation/routes/list-runs.d.ts.map +1 -1
  199. package/dist/presentation/routes/list-runs.js +9 -3
  200. package/dist/presentation/routes/list-runs.js.map +1 -1
  201. package/dist/presentation/routes/project-access.d.ts +1 -0
  202. package/dist/presentation/routes/project-access.d.ts.map +1 -1
  203. package/dist/presentation/routes/report-step.d.ts.map +1 -1
  204. package/dist/presentation/routes/report-step.js +9 -2
  205. package/dist/presentation/routes/report-step.js.map +1 -1
  206. package/dist/presentation/routes/require-accessible-run.d.ts.map +1 -1
  207. package/dist/presentation/routes/require-accessible-run.js +1 -1
  208. package/dist/presentation/routes/require-accessible-run.js.map +1 -1
  209. package/dist/presentation/subscribers/on-job-steps-settled.js +1 -1
  210. package/dist/presentation/subscribers/on-job-steps-settled.js.map +1 -1
  211. package/dist/presentation/subscribers/on-runner-job-claimed.d.ts.map +1 -1
  212. package/dist/presentation/subscribers/on-runner-job-claimed.js +21 -0
  213. package/dist/presentation/subscribers/on-runner-job-claimed.js.map +1 -1
  214. package/dist/temporal/activities/index.d.ts.map +1 -1
  215. package/dist/temporal/activities/index.js +2 -1
  216. package/dist/temporal/activities/index.js.map +1 -1
  217. package/dist/temporal/activities/orchestration-activities.d.ts +1 -0
  218. package/dist/temporal/activities/orchestration-activities.d.ts.map +1 -1
  219. package/dist/temporal/activities/orchestration-activities.js.map +1 -1
  220. package/dist/temporal/constants.d.ts +1 -0
  221. package/dist/temporal/constants.d.ts.map +1 -1
  222. package/dist/temporal/constants.js +1 -0
  223. package/dist/temporal/constants.js.map +1 -1
  224. package/dist/temporal/index.d.ts +1 -1
  225. package/dist/temporal/index.d.ts.map +1 -1
  226. package/dist/temporal/index.js +1 -1
  227. package/dist/temporal/index.js.map +1 -1
  228. package/dist/temporal/workflows/index.bundle.js +82 -43
  229. package/dist/temporal/workflows/index.d.ts +1 -1
  230. package/dist/temporal/workflows/index.d.ts.map +1 -1
  231. package/dist/temporal/workflows/index.js +1 -1
  232. package/dist/temporal/workflows/index.js.map +1 -1
  233. package/dist/temporal/workflows/job-execution-orchestration.d.ts +5 -0
  234. package/dist/temporal/workflows/job-execution-orchestration.d.ts.map +1 -1
  235. package/dist/temporal/workflows/job-execution-orchestration.js +77 -43
  236. package/dist/temporal/workflows/job-execution-orchestration.js.map +1 -1
  237. package/dist/temporal/workflows/test-env.d.ts +5 -1
  238. package/dist/temporal/workflows/test-env.d.ts.map +1 -1
  239. package/dist/temporal/workflows/test-env.js +32 -11
  240. package/dist/temporal/workflows/test-env.js.map +1 -1
  241. package/dist/tsconfig.test.tsbuildinfo +1 -1
  242. package/drizzle/0000_initial.sql +14 -2
  243. package/drizzle/0001_windy_sunfire.sql +1 -0
  244. package/drizzle/meta/0000_snapshot.json +93 -1
  245. package/drizzle/meta/0001_snapshot.json +1711 -0
  246. package/drizzle/meta/_journal.json +2 -2
  247. package/package.json +21 -21
  248. package/src/core/agent-defaults.ts +2 -1
  249. package/src/core/checkout.test.ts +378 -67
  250. package/src/core/checkout.ts +142 -59
  251. package/src/core/entities/job-execution.test.ts +21 -0
  252. package/src/core/entities/job-execution.ts +24 -0
  253. package/src/core/entities/job-listener-event.ts +3 -0
  254. package/src/core/entities/step.ts +15 -3
  255. package/src/core/entities/workflow-run-attempt.ts +1 -0
  256. package/src/core/entities/workflow-run.ts +16 -0
  257. package/src/core/errors.ts +21 -7
  258. package/src/core/job-execution.ts +27 -4
  259. package/src/core/job-transition/decide-job-activation.test.ts +4 -0
  260. package/src/core/job-transition/decide-job-activation.ts +2 -0
  261. package/src/core/job-transition/derive-job-success.test.ts +12 -0
  262. package/src/core/job-transition/derive-job-success.ts +6 -9
  263. package/src/core/listener-execution-materialization.test.ts +2 -0
  264. package/src/core/listener-execution-materialization.ts +57 -11
  265. package/src/core/resolve-trigger-reference.test.ts +160 -0
  266. package/src/core/resolve-trigger-reference.ts +53 -0
  267. package/src/core/run-workflow.ts +2 -0
  268. package/src/core/step-config/agent.ts +29 -12
  269. package/src/core/step-config/assemble-run-context.test.ts +149 -6
  270. package/src/core/step-config/assemble-run-context.ts +87 -25
  271. package/src/core/step-config/complete-step-dispatch-config.test.ts +125 -2
  272. package/src/core/step-config/complete-step-dispatch-config.ts +83 -1
  273. package/src/core/step-config/index.ts +7 -0
  274. package/src/core/step-config/materialize-job-execution-steps.test.ts +250 -1
  275. package/src/core/step-config/materialize-job-execution-steps.ts +57 -10
  276. package/src/core/step-config/materialize-workflow-model.test.ts +212 -4
  277. package/src/core/step-config/materialize-workflow-model.ts +33 -28
  278. package/src/core/step-config/resolve-job-execution-name.test.ts +37 -15
  279. package/src/core/step-config/resolve-job-execution-name.ts +30 -15
  280. package/src/core/step-config/resolve-step-config.ts +175 -10
  281. package/src/core/step-config/resolve-workflow-run-name.test.ts +115 -0
  282. package/src/core/step-config/resolve-workflow-run-name.ts +108 -0
  283. package/src/core/step-transition/decide-step-transition.ts +2 -2
  284. package/src/core/step-transition/evaluate-gate.test.ts +8 -0
  285. package/src/core/step-transition/evaluate-gate.ts +8 -1
  286. package/src/core/workflow-run-creation.test.ts +7 -4
  287. package/src/core/workflow-run-creation.ts +13 -7
  288. package/src/db/db.ts +2 -0
  289. package/src/db/index.ts +6 -0
  290. package/src/db/job-listener-events.test.ts +19 -0
  291. package/src/db/job-listener-events.ts +3 -0
  292. package/src/db/job-listeners.test.ts +187 -5
  293. package/src/db/job-listeners.ts +122 -30
  294. package/src/db/schema/job-executions.ts +12 -5
  295. package/src/db/schema/job-listener-events.ts +3 -0
  296. package/src/db/schema/step-attempts.ts +2 -2
  297. package/src/db/schema/steps.ts +2 -1
  298. package/src/db/schema/workflow-run-attempts.ts +2 -0
  299. package/src/db/schema/workflow-run-counters.ts +13 -0
  300. package/src/db/schema/workflow-runs.ts +11 -2
  301. package/src/db/workflow-runs/job-executions.ts +37 -15
  302. package/src/db/workflow-runs/jobs.ts +17 -4
  303. package/src/db/workflow-runs/queries.test.ts +206 -0
  304. package/src/db/workflow-runs/queries.ts +146 -2
  305. package/src/db/workflow-runs/run-create.test.ts +606 -8
  306. package/src/db/workflow-runs/run-create.ts +185 -40
  307. package/src/db/workflow-runs/run-rerun.test.ts +61 -2
  308. package/src/db/workflow-runs/run-rerun.ts +15 -5
  309. package/src/db/workflow-runs/shared.ts +2 -0
  310. package/src/db/workflow-runs/steps.ts +3 -3
  311. package/src/db/workflow-runs.ts +7 -0
  312. package/src/metrics/instance.ts +14 -0
  313. package/src/presentation/dto/checkout-token.test.ts +19 -9
  314. package/src/presentation/dto/checkout-token.ts +2 -1
  315. package/src/presentation/dto/index.ts +1 -1
  316. package/src/presentation/dto/job.test.ts +9 -0
  317. package/src/presentation/dto/step.test.ts +12 -0
  318. package/src/presentation/dto/step.ts +5 -2
  319. package/src/presentation/dto/workflow-run.ts +44 -2
  320. package/src/presentation/inter-module.test.ts +165 -0
  321. package/src/presentation/inter-module.ts +38 -4
  322. package/src/presentation/routes/cancel-run.test.ts +1 -1
  323. package/src/presentation/routes/checkout-token.test.ts +357 -142
  324. package/src/presentation/routes/checkout-token.ts +56 -26
  325. package/src/presentation/routes/get-run-aggregates.test.ts +1 -1
  326. package/src/presentation/routes/get-run.test.ts +29 -1
  327. package/src/presentation/routes/get-step-secrets.test.ts +7 -2
  328. package/src/presentation/routes/leased-step.ts +9 -1
  329. package/src/presentation/routes/list-run-attempts.test.ts +1 -1
  330. package/src/presentation/routes/list-runs.test.ts +58 -1
  331. package/src/presentation/routes/list-runs.ts +8 -3
  332. package/src/presentation/routes/report-step.test.ts +25 -0
  333. package/src/presentation/routes/report-step.ts +10 -2
  334. package/src/presentation/routes/require-accessible-run.ts +4 -1
  335. package/src/presentation/routes/rerun-run.test.ts +1 -1
  336. package/src/presentation/subscribers/on-job-steps-settled.ts +1 -1
  337. package/src/presentation/subscribers/on-runner-job-claimed.test.ts +49 -0
  338. package/src/presentation/subscribers/on-runner-job-claimed.ts +22 -0
  339. package/src/temporal/activities/index.ts +1 -0
  340. package/src/temporal/activities/orchestration-activities.ts +1 -0
  341. package/src/temporal/constants.ts +1 -0
  342. package/src/temporal/index.ts +1 -0
  343. package/src/temporal/workflows/index.ts +1 -0
  344. package/src/temporal/workflows/job-execution-orchestration.test.ts +142 -6
  345. package/src/temporal/workflows/job-execution-orchestration.ts +99 -50
  346. package/src/temporal/workflows/run-orchestration.test.ts +1 -1
  347. package/src/temporal/workflows/test-env.ts +50 -13
  348. package/test/factories/project.ts +2 -0
  349. package/test/factories/workflow-model.ts +80 -26
  350. package/test/factories/workflow-run.ts +4 -1
  351. package/test/fixtures/agent-inter-module.ts +2 -1
  352. package/test/fixtures/job-with-steps.ts +1 -1
  353. package/tsconfig.build.tsbuildinfo +1 -1
  354. package/drizzle/0001_agent_tool_materialization.sql +0 -1
@@ -12,8 +12,8 @@
12
12
  {
13
13
  "idx": 1,
14
14
  "version": "7",
15
- "when": 1783439600000,
16
- "tag": "0001_agent_tool_materialization",
15
+ "when": 1785771111717,
16
+ "tag": "0001_windy_sunfire",
17
17
  "breakpoints": true
18
18
  }
19
19
  ]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shipfox/api-workflows",
3
3
  "license": "MIT",
4
- "version": "10.2.0",
4
+ "version": "12.0.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ShipfoxHQ/shipfox.git",
@@ -22,29 +22,29 @@
22
22
  "@temporalio/workflow": "1.18.1",
23
23
  "drizzle-orm": "^0.45.2",
24
24
  "zod": "^4.4.3",
25
- "@shipfox/api-auth-context": "10.2.0",
26
- "@shipfox/api-auth-dto": "10.2.0",
27
- "@shipfox/api-agent-dto": "10.0.0",
28
- "@shipfox/annotations-dto": "9.0.2",
29
- "@shipfox/api-definitions-dto": "10.0.0",
30
- "@shipfox/api-projects-dto": "10.1.0",
31
- "@shipfox/api-integration-core-dto": "9.0.2",
32
- "@shipfox/api-runners-dto": "10.2.0",
33
- "@shipfox/api-secrets-dto": "9.0.2",
34
- "@shipfox/api-workflows-dto": "10.0.0",
35
- "@shipfox/api-workspaces-dto": "10.2.0",
36
- "@shipfox/inter-module": "0.2.2",
37
- "@shipfox/expression": "1.2.0",
38
- "@shipfox/node-drizzle": "0.3.4",
25
+ "@shipfox/api-auth-dto": "12.0.0",
26
+ "@shipfox/annotations-dto": "12.0.0",
27
+ "@shipfox/api-definitions-dto": "12.0.0",
28
+ "@shipfox/api-projects-dto": "12.0.0",
29
+ "@shipfox/api-agent-dto": "12.0.0",
30
+ "@shipfox/api-auth-context": "12.0.0",
31
+ "@shipfox/api-integration-core-dto": "12.0.0",
32
+ "@shipfox/api-runners-dto": "12.0.0",
33
+ "@shipfox/api-workflows-dto": "12.0.0",
34
+ "@shipfox/api-workspaces-dto": "12.0.0",
35
+ "@shipfox/api-secrets-dto": "12.0.0",
36
+ "@shipfox/inter-module": "0.2.3",
37
+ "@shipfox/expression": "2.0.0",
38
+ "@shipfox/node-drizzle": "0.3.5",
39
39
  "@shipfox/node-error-monitoring": "0.3.0",
40
- "@shipfox/node-fastify": "0.4.0",
41
- "@shipfox/node-module": "1.0.4",
42
- "@shipfox/node-opentelemetry": "0.6.3",
40
+ "@shipfox/node-fastify": "0.4.1",
41
+ "@shipfox/node-module": "1.0.5",
43
42
  "@shipfox/node-outbox": "0.2.6",
44
- "@shipfox/node-postgres": "0.4.4",
43
+ "@shipfox/node-opentelemetry": "0.6.3",
44
+ "@shipfox/node-postgres": "0.5.0",
45
45
  "@shipfox/node-temporal": "0.4.4",
46
- "@shipfox/runner-labels": "0.1.3",
47
- "@shipfox/workflow-document": "2.1.3"
46
+ "@shipfox/workflow-document": "3.0.0",
47
+ "@shipfox/runner-labels": "0.1.3"
48
48
  },
49
49
  "imports": {
50
50
  "#*": "./dist/*"
@@ -6,7 +6,8 @@ export interface AgentDefaultsInput {
6
6
  readonly harness?: Harness | undefined;
7
7
  readonly provider?: ModelProviderRef | undefined;
8
8
  readonly model?: string | undefined;
9
- readonly thinking?: AgentThinking | undefined;
9
+ /** A resolved template can carry any string. The agent module validates it. */
10
+ readonly thinking?: string | undefined;
10
11
  }
11
12
 
12
13
  export interface ResolvedAgentDefaults {
@@ -1,125 +1,436 @@
1
1
  import type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/inter-module';
2
2
  import type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';
3
- import * as workflowRuns from '#db/workflow-runs.js';
4
- import {jobFactory} from '#test/factories/job.js';
5
3
  import {projectFactory} from '#test/factories/project.js';
6
- import {createJobCheckoutSpec, resolveCheckoutIntent} from './checkout.js';
7
- import {
8
- CheckoutIntentUnresolvedError,
9
- JobNotFoundError,
10
- WorkflowRunNotFoundError,
11
- } from './errors.js';
4
+ import {createStepCheckoutSpec} from './checkout.js';
5
+ import type {Step} from './entities/step.js';
6
+ import type {WorkflowRunTriggerReference} from './entities/workflow-run.js';
7
+ import {CheckoutConfigInvalidError, CheckoutIntentUnresolvedError} from './errors.js';
12
8
 
13
9
  const getProjectById = vi.fn();
14
- const projects = {getProjectById} as Pick<ProjectsModuleClient, 'getProjectById'>;
10
+ const resolveCheckoutTarget = vi.fn();
11
+ const projects = {
12
+ getProjectById,
13
+ resolveCheckoutTarget,
14
+ } as Pick<ProjectsModuleClient, 'getProjectById' | 'resolveCheckoutTarget'>;
15
15
 
16
- describe('resolveCheckoutIntent', () => {
17
- it('resolves connection + repo from the project, using the project workspace', async () => {
16
+ const resolveConnection = vi.fn();
17
+ const createCheckoutSpec = vi.fn();
18
+ const integrations = {
19
+ resolveConnection,
20
+ createCheckoutSpec,
21
+ } as Pick<IntegrationsModuleClient, 'createCheckoutSpec' | 'resolveConnection'>;
22
+
23
+ describe('createStepCheckoutSpec', () => {
24
+ beforeEach(() => {
25
+ getProjectById.mockReset();
26
+ resolveCheckoutTarget.mockReset();
27
+ resolveConnection.mockReset();
28
+ createCheckoutSpec.mockReset();
29
+ });
30
+
31
+ it('resolves the default project target and setup-step defaults', async () => {
18
32
  const project = projectFactory.build();
33
+ const step = checkoutStep({
34
+ permissions: {contents: 'read'},
35
+ persist_credentials: true,
36
+ });
19
37
  getProjectById.mockResolvedValue({project});
20
- const job = await jobFactory.create({}, {transient: {projectId: project.id}});
38
+ resolveCheckoutTarget.mockResolvedValue({
39
+ projectId: project.id,
40
+ connectionId: project.sourceConnectionId,
41
+ externalRepositoryId: project.sourceExternalRepositoryId,
42
+ });
43
+ createCheckoutSpec.mockResolvedValue({
44
+ repositoryUrl: 'https://github.com/acme/repo.git',
45
+ ref: 'main',
46
+ });
21
47
 
22
- const intent = await resolveCheckoutIntent(job.id, projects as ProjectsModuleClient);
48
+ const result = await createStepCheckoutSpec({
49
+ step,
50
+ workspaceId: project.workspaceId,
51
+ projectId: project.id,
52
+ integrations: integrations as IntegrationsModuleClient,
53
+ projects: projects as ProjectsModuleClient,
54
+ });
23
55
 
24
- expect(intent).toEqual({
56
+ expect(result).toEqual({
57
+ spec: {
58
+ repositoryUrl: 'https://github.com/acme/repo.git',
59
+ ref: 'main',
60
+ },
61
+ fetchDepth: 1,
62
+ persistCredentials: true,
63
+ });
64
+ expect(resolveCheckoutTarget).toHaveBeenCalledWith({
65
+ workspaceId: project.workspaceId,
66
+ defaults: {connectionId: project.sourceConnectionId, owner: 'acme'},
67
+ target: {project: project.id},
68
+ });
69
+ expect(createCheckoutSpec).toHaveBeenCalledWith({
25
70
  workspaceId: project.workspaceId,
26
71
  connectionId: project.sourceConnectionId,
27
72
  externalRepositoryId: project.sourceExternalRepositoryId,
28
- persistCredentials: true,
29
73
  permissions: {contents: 'read'},
30
74
  });
31
75
  });
32
76
 
33
- it('throws JobNotFoundError for an unknown job', async () => {
34
- const act = resolveCheckoutIntent(crypto.randomUUID(), projects as ProjectsModuleClient);
77
+ it('passes an explicit frozen target, ref, permissions, and fetch depth', async () => {
78
+ const project = projectFactory.build();
79
+ const targetProjectId = crypto.randomUUID();
80
+ const step = checkoutStep({
81
+ project: targetProjectId,
82
+ ref: 'refs/pull/412/head',
83
+ fetch_depth: 0,
84
+ permissions: {contents: 'write'},
85
+ persist_credentials: false,
86
+ });
87
+ getProjectById.mockResolvedValue({project});
88
+ resolveCheckoutTarget.mockResolvedValue({
89
+ projectId: targetProjectId,
90
+ connectionId: crypto.randomUUID(),
91
+ externalRepositoryId: 'github:412',
92
+ });
93
+ createCheckoutSpec.mockResolvedValue({
94
+ repositoryUrl: 'https://github.com/acme/repo.git',
95
+ ref: 'refs/pull/412/head',
96
+ });
97
+
98
+ const result = await createStepCheckoutSpec({
99
+ step,
100
+ workspaceId: project.workspaceId,
101
+ projectId: project.id,
102
+ triggerReference: triggerReferenceFor(project.id),
103
+ integrations: integrations as IntegrationsModuleClient,
104
+ projects: projects as ProjectsModuleClient,
105
+ });
35
106
 
36
- await expect(act).rejects.toBeInstanceOf(JobNotFoundError);
107
+ expect(result.fetchDepth).toBe(0);
108
+ expect(result.persistCredentials).toBe(false);
109
+ expect(resolveCheckoutTarget).toHaveBeenCalledWith(
110
+ expect.objectContaining({target: {project: targetProjectId}}),
111
+ );
112
+ expect(createCheckoutSpec).toHaveBeenCalledWith({
113
+ workspaceId: project.workspaceId,
114
+ connectionId: expect.any(String),
115
+ externalRepositoryId: 'github:412',
116
+ ref: 'refs/pull/412/head',
117
+ permissions: {contents: 'write'},
118
+ });
37
119
  });
38
120
 
39
- it('resolves the checkout target while the parent job projection is still pending', async () => {
121
+ it('defaults the ref to the trigger commit for the triggered repository', async () => {
40
122
  const project = projectFactory.build();
123
+ const triggerReference = triggerReferenceFor(project.id);
124
+ const step = checkoutStep({permissions: {contents: 'read'}});
41
125
  getProjectById.mockResolvedValue({project});
42
- const job = await jobFactory.create(
43
- {},
44
- {transient: {projectId: project.id, status: 'pending'}},
45
- );
126
+ resolveCheckoutTarget.mockResolvedValue({
127
+ projectId: project.id,
128
+ connectionId: project.sourceConnectionId,
129
+ externalRepositoryId: project.sourceExternalRepositoryId,
130
+ });
131
+ createCheckoutSpec.mockResolvedValue({
132
+ repositoryUrl: 'https://github.com/acme/repo.git',
133
+ ref: triggerReference.commit,
134
+ });
46
135
 
47
- const intent = await resolveCheckoutIntent(job.id, projects as ProjectsModuleClient);
136
+ await createStepCheckoutSpec({
137
+ step,
138
+ workspaceId: project.workspaceId,
139
+ projectId: project.id,
140
+ triggerReference,
141
+ integrations: integrations as IntegrationsModuleClient,
142
+ projects: projects as ProjectsModuleClient,
143
+ });
48
144
 
49
- expect(intent.connectionId).toBe(project.sourceConnectionId);
145
+ expect(createCheckoutSpec).toHaveBeenCalledWith({
146
+ workspaceId: project.workspaceId,
147
+ connectionId: project.sourceConnectionId,
148
+ externalRepositoryId: project.sourceExternalRepositoryId,
149
+ ref: triggerReference.commit,
150
+ permissions: {contents: 'read'},
151
+ });
50
152
  });
51
153
 
52
- it('throws WorkflowRunNotFoundError when the run is missing', async () => {
154
+ it('preserves an explicit ref when the trigger targets the same project', async () => {
53
155
  const project = projectFactory.build();
156
+ const explicitRef = 'refs/pull/412/head';
157
+ const step = checkoutStep({ref: explicitRef, permissions: {contents: 'read'}});
54
158
  getProjectById.mockResolvedValue({project});
55
- const job = await jobFactory.create({}, {transient: {projectId: project.id}});
56
- vi.spyOn(workflowRuns, 'getWorkflowRunByAttemptId').mockResolvedValue(undefined);
159
+ resolveCheckoutTarget.mockResolvedValue({
160
+ projectId: project.id,
161
+ connectionId: project.sourceConnectionId,
162
+ externalRepositoryId: project.sourceExternalRepositoryId,
163
+ });
164
+ createCheckoutSpec.mockResolvedValue({
165
+ repositoryUrl: 'https://github.com/acme/repo.git',
166
+ ref: explicitRef,
167
+ });
57
168
 
58
- const act = resolveCheckoutIntent(job.id, projects as ProjectsModuleClient);
169
+ await createStepCheckoutSpec({
170
+ step,
171
+ workspaceId: project.workspaceId,
172
+ projectId: project.id,
173
+ triggerReference: triggerReferenceFor(project.id),
174
+ integrations: integrations as IntegrationsModuleClient,
175
+ projects: projects as ProjectsModuleClient,
176
+ });
59
177
 
60
- await expect(act).rejects.toBeInstanceOf(WorkflowRunNotFoundError);
178
+ expect(createCheckoutSpec).toHaveBeenCalledWith({
179
+ workspaceId: project.workspaceId,
180
+ connectionId: project.sourceConnectionId,
181
+ externalRepositoryId: project.sourceExternalRepositoryId,
182
+ ref: explicitRef,
183
+ permissions: {contents: 'read'},
184
+ });
61
185
  });
62
186
 
63
- it('throws CheckoutIntentUnresolvedError when the project is missing', async () => {
187
+ it('uses the provider default when the matching trigger reference has no commit', async () => {
64
188
  const project = projectFactory.build();
65
- getProjectById.mockResolvedValue({project: null});
66
- const job = await jobFactory.create({}, {transient: {projectId: project.id}});
189
+ const triggerReference = {...triggerReferenceFor(project.id), commit: null};
190
+ const step = checkoutStep({permissions: {contents: 'read'}});
191
+ getProjectById.mockResolvedValue({project});
192
+ resolveCheckoutTarget.mockResolvedValue({
193
+ projectId: project.id,
194
+ connectionId: project.sourceConnectionId,
195
+ externalRepositoryId: project.sourceExternalRepositoryId,
196
+ });
197
+ createCheckoutSpec.mockResolvedValue({
198
+ repositoryUrl: 'https://github.com/acme/repo.git',
199
+ ref: 'main',
200
+ });
67
201
 
68
- const act = resolveCheckoutIntent(job.id, projects as ProjectsModuleClient);
202
+ await createStepCheckoutSpec({
203
+ step,
204
+ workspaceId: project.workspaceId,
205
+ projectId: project.id,
206
+ triggerReference,
207
+ integrations: integrations as IntegrationsModuleClient,
208
+ projects: projects as ProjectsModuleClient,
209
+ });
69
210
 
70
- await expect(act).rejects.toBeInstanceOf(CheckoutIntentUnresolvedError);
211
+ expect(createCheckoutSpec).toHaveBeenCalledWith({
212
+ workspaceId: project.workspaceId,
213
+ connectionId: project.sourceConnectionId,
214
+ externalRepositoryId: project.sourceExternalRepositoryId,
215
+ permissions: {contents: 'read'},
216
+ });
71
217
  });
72
- });
73
218
 
74
- describe('createJobCheckoutSpec', () => {
75
- it('passes the resolved intent without a ref to the service', async () => {
219
+ it('keeps the provider default ref for a cross-repository target', async () => {
76
220
  const project = projectFactory.build();
221
+ const targetProjectId = crypto.randomUUID();
222
+ const step = checkoutStep({project: targetProjectId});
77
223
  getProjectById.mockResolvedValue({project});
78
- const job = await jobFactory.create({}, {transient: {projectId: project.id}});
79
- const spec = {repositoryUrl: 'https://github.com/acme/repo.git', ref: 'main'};
80
- const createCheckoutSpec = vi.fn().mockResolvedValue(spec);
81
- const integrations = {createCheckoutSpec} as Pick<
82
- IntegrationsModuleClient,
83
- 'createCheckoutSpec'
84
- >;
85
-
86
- const result = await createJobCheckoutSpec({
87
- jobId: job.id,
224
+ resolveCheckoutTarget.mockResolvedValue({
225
+ projectId: targetProjectId,
226
+ connectionId: crypto.randomUUID(),
227
+ externalRepositoryId: 'github:412',
228
+ });
229
+ createCheckoutSpec.mockResolvedValue({
230
+ repositoryUrl: 'https://github.com/acme/target.git',
231
+ ref: 'main',
232
+ });
233
+
234
+ await createStepCheckoutSpec({
235
+ step,
236
+ workspaceId: project.workspaceId,
237
+ projectId: project.id,
238
+ triggerReference: triggerReferenceFor(project.id),
88
239
  integrations: integrations as IntegrationsModuleClient,
89
240
  projects: projects as ProjectsModuleClient,
90
241
  });
91
242
 
92
- expect(result).toEqual({spec, persistCredentials: true});
93
243
  expect(createCheckoutSpec).toHaveBeenCalledWith({
94
244
  workspaceId: project.workspaceId,
245
+ connectionId: expect.any(String),
246
+ externalRepositoryId: 'github:412',
247
+ permissions: {contents: 'read'},
248
+ });
249
+ });
250
+
251
+ it('resolves a repository target using the frozen project owner as the default', async () => {
252
+ const project = projectFactory.build();
253
+ const step = checkoutStep({repository: 'repo', persist_credentials: true});
254
+ getProjectById.mockResolvedValue({project});
255
+ resolveCheckoutTarget.mockResolvedValue({
256
+ projectId: project.id,
95
257
  connectionId: project.sourceConnectionId,
96
258
  externalRepositoryId: project.sourceExternalRepositoryId,
97
- permissions: {contents: 'read'},
259
+ });
260
+ createCheckoutSpec.mockResolvedValue({
261
+ repositoryUrl: 'https://github.com/acme/repo.git',
262
+ ref: 'main',
263
+ });
264
+
265
+ await createStepCheckoutSpec({
266
+ step,
267
+ workspaceId: project.workspaceId,
268
+ projectId: project.id,
269
+ integrations: integrations as IntegrationsModuleClient,
270
+ projects: projects as ProjectsModuleClient,
271
+ });
272
+
273
+ expect(resolveCheckoutTarget).toHaveBeenCalledWith({
274
+ workspaceId: project.workspaceId,
275
+ defaults: {connectionId: project.sourceConnectionId, owner: 'acme'},
276
+ target: {repository: 'repo'},
98
277
  });
99
278
  });
100
279
 
101
- it('passes requested write contents permission to the service', async () => {
280
+ it('resolves an explicit connection slug before resolving a repository target', async () => {
102
281
  const project = projectFactory.build();
282
+ const connectionId = crypto.randomUUID();
283
+ const step = checkoutStep({connection: 'github', repository: 'acme/repo'});
103
284
  getProjectById.mockResolvedValue({project});
104
- const job = await jobFactory.create(
105
- {},
106
- {transient: {projectId: project.id, checkout: {permissions: {contents: 'write'}}}},
107
- );
108
- const spec = {repositoryUrl: 'https://github.com/acme/repo.git', ref: 'main'};
109
- const createCheckoutSpec = vi.fn().mockResolvedValue(spec);
110
- const integrations = {createCheckoutSpec} as Pick<
111
- IntegrationsModuleClient,
112
- 'createCheckoutSpec'
113
- >;
114
-
115
- await createJobCheckoutSpec({
116
- jobId: job.id,
285
+ resolveConnection.mockResolvedValue({id: connectionId, provider: 'github', slug: 'github'});
286
+ resolveCheckoutTarget.mockResolvedValue({
287
+ projectId: project.id,
288
+ connectionId,
289
+ externalRepositoryId: project.sourceExternalRepositoryId,
290
+ });
291
+ createCheckoutSpec.mockResolvedValue({
292
+ repositoryUrl: 'https://github.com/acme/repo.git',
293
+ ref: 'main',
294
+ });
295
+
296
+ await createStepCheckoutSpec({
297
+ step,
298
+ workspaceId: project.workspaceId,
299
+ projectId: project.id,
117
300
  integrations: integrations as IntegrationsModuleClient,
118
301
  projects: projects as ProjectsModuleClient,
119
302
  });
120
303
 
121
- expect(createCheckoutSpec).toHaveBeenCalledWith(
122
- expect.objectContaining({permissions: {contents: 'write'}}),
123
- );
304
+ expect(resolveConnection).toHaveBeenCalledWith({
305
+ workspaceId: project.workspaceId,
306
+ slug: 'github',
307
+ });
308
+ expect(resolveCheckoutTarget).toHaveBeenCalledWith({
309
+ workspaceId: project.workspaceId,
310
+ defaults: {connectionId: project.sourceConnectionId, owner: 'acme'},
311
+ target: {connection: connectionId, repository: 'acme/repo'},
312
+ });
313
+ });
314
+
315
+ it.each([
316
+ {repository: 'octocat/repo', owner: 'octocat'},
317
+ {repository: 'repo', owner: 'unknown'},
318
+ ])('derives the repository owner fallback for $repository', async ({repository, owner}) => {
319
+ const project = projectFactory.build({sourceRepositoryOwner: null});
320
+ const step = checkoutStep({repository});
321
+ getProjectById.mockResolvedValue({project});
322
+ resolveCheckoutTarget.mockResolvedValue({
323
+ projectId: project.id,
324
+ connectionId: project.sourceConnectionId,
325
+ externalRepositoryId: project.sourceExternalRepositoryId,
326
+ });
327
+ createCheckoutSpec.mockResolvedValue({
328
+ repositoryUrl: 'https://github.com/acme/repo.git',
329
+ ref: 'main',
330
+ });
331
+
332
+ await createStepCheckoutSpec({
333
+ step,
334
+ workspaceId: project.workspaceId,
335
+ projectId: project.id,
336
+ integrations: integrations as IntegrationsModuleClient,
337
+ projects: projects as ProjectsModuleClient,
338
+ });
339
+
340
+ expect(resolveCheckoutTarget).toHaveBeenCalledWith({
341
+ workspaceId: project.workspaceId,
342
+ defaults: {connectionId: project.sourceConnectionId, owner},
343
+ target: {repository},
344
+ });
345
+ });
346
+
347
+ it.each([
348
+ {project: crypto.randomUUID(), connection: 'github'},
349
+ {project: crypto.randomUUID(), repository: 'acme/repo'},
350
+ {connection: 'github'},
351
+ ])('rejects invalid checkout target shape: %j', async (checkout) => {
352
+ const act = createStepCheckoutSpec({
353
+ step: checkoutStep(checkout),
354
+ workspaceId: crypto.randomUUID(),
355
+ projectId: crypto.randomUUID(),
356
+ integrations: integrations as IntegrationsModuleClient,
357
+ projects: projects as ProjectsModuleClient,
358
+ });
359
+
360
+ await expect(act).rejects.toBeInstanceOf(CheckoutConfigInvalidError);
361
+ expect(getProjectById).not.toHaveBeenCalled();
362
+ expect(resolveCheckoutTarget).not.toHaveBeenCalled();
363
+ expect(createCheckoutSpec).not.toHaveBeenCalled();
364
+ });
365
+
366
+ it('throws when the run project is missing', async () => {
367
+ const projectId = crypto.randomUUID();
368
+ getProjectById.mockResolvedValue({project: null});
369
+
370
+ const act = createStepCheckoutSpec({
371
+ step: checkoutStep({}),
372
+ workspaceId: crypto.randomUUID(),
373
+ projectId,
374
+ integrations: integrations as IntegrationsModuleClient,
375
+ projects: projects as ProjectsModuleClient,
376
+ });
377
+
378
+ await expect(act).rejects.toBeInstanceOf(CheckoutIntentUnresolvedError);
379
+ expect(resolveCheckoutTarget).not.toHaveBeenCalled();
380
+ expect(createCheckoutSpec).not.toHaveBeenCalled();
381
+ });
382
+
383
+ it('identifies a missing explicit connection in the unresolved error', async () => {
384
+ const project = projectFactory.build();
385
+ const step = checkoutStep({connection: 'missing', repository: 'acme/repo'});
386
+ getProjectById.mockResolvedValue({project});
387
+ resolveConnection.mockResolvedValue(null);
388
+
389
+ const act = createStepCheckoutSpec({
390
+ step,
391
+ workspaceId: project.workspaceId,
392
+ projectId: project.id,
393
+ integrations: integrations as IntegrationsModuleClient,
394
+ projects: projects as ProjectsModuleClient,
395
+ });
396
+
397
+ await expect(act).rejects.toThrow('Checkout intent unresolved: connection missing not found');
398
+ expect(resolveCheckoutTarget).not.toHaveBeenCalled();
399
+ expect(createCheckoutSpec).not.toHaveBeenCalled();
124
400
  });
125
401
  });
402
+
403
+ function checkoutStep(checkout: Record<string, unknown>): Step {
404
+ const now = new Date();
405
+ return {
406
+ id: crypto.randomUUID(),
407
+ jobExecutionId: crypto.randomUUID(),
408
+ key: null,
409
+ name: 'Checkout',
410
+ sourceLocation: null,
411
+ status: 'running',
412
+ statusReason: null,
413
+ evaluationTrace: null,
414
+ type: 'checkout',
415
+ config: {checkout},
416
+ condition: null,
417
+ configPlan: null,
418
+ authoredConfig: null,
419
+ error: null,
420
+ position: 1,
421
+ version: 1,
422
+ currentAttempt: 1,
423
+ createdAt: now,
424
+ updatedAt: now,
425
+ };
426
+ }
427
+
428
+ function triggerReferenceFor(projectId: string): WorkflowRunTriggerReference {
429
+ return {
430
+ project: {id: projectId},
431
+ repository: 'acme/repo',
432
+ ref: 'refs/heads/feature/checkout',
433
+ commit: 'a'.repeat(40),
434
+ actor: null,
435
+ };
436
+ }