@vercel/factory 0.0.14 → 0.0.16

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 (510) hide show
  1. package/CHANGELOG.md +356 -0
  2. package/README.md +96 -2
  3. package/dist/agent-routes.d.mts +113 -0
  4. package/dist/agent-routes.mjs +91 -0
  5. package/dist/agent-routes.mjs.map +1 -0
  6. package/dist/api-contracts.d.mts +1768 -0
  7. package/dist/api-contracts.mjs +119 -0
  8. package/dist/api-contracts.mjs.map +1 -0
  9. package/dist/api-images.d.mts +30 -0
  10. package/dist/api-images.mjs +28 -0
  11. package/dist/api-images.mjs.map +1 -0
  12. package/dist/api-task-graph.mjs +57 -0
  13. package/dist/api-task-graph.mjs.map +1 -0
  14. package/dist/api.d.mts +111 -216
  15. package/dist/api.mjs +1063 -99
  16. package/dist/api.mjs.map +1 -1
  17. package/dist/approval-access.d.mts +39 -0
  18. package/dist/approval-access.mjs +62 -0
  19. package/dist/approval-access.mjs.map +1 -0
  20. package/dist/approval-contracts.d.mts +698 -0
  21. package/dist/approval-contracts.mjs +27 -0
  22. package/dist/approval-contracts.mjs.map +1 -0
  23. package/dist/approval.d.mts +49 -0
  24. package/dist/approval.mjs +39 -0
  25. package/dist/approval.mjs.map +1 -0
  26. package/dist/blob/artifacts.d.mts +37 -0
  27. package/dist/blob/artifacts.mjs +45 -0
  28. package/dist/blob/artifacts.mjs.map +1 -0
  29. package/dist/blob/index.d.mts +84 -12
  30. package/dist/blob/index.mjs +179 -45
  31. package/dist/blob/index.mjs.map +1 -1
  32. package/dist/budget.d.mts +115 -0
  33. package/dist/budget.mjs +147 -0
  34. package/dist/budget.mjs.map +1 -0
  35. package/dist/budgets.d.mts +4 -0
  36. package/dist/budgets.mjs +4 -0
  37. package/dist/build-factory.d.mts +7 -4
  38. package/dist/build-factory.mjs +2 -1
  39. package/dist/build-factory.mjs.map +1 -1
  40. package/dist/change-verification/brief.d.mts +9 -0
  41. package/dist/change-verification/brief.mjs +13 -0
  42. package/dist/change-verification/brief.mjs.map +1 -0
  43. package/dist/change-verification/dispatch.d.mts +37 -0
  44. package/dist/change-verification/dispatch.mjs +83 -0
  45. package/dist/change-verification/dispatch.mjs.map +1 -0
  46. package/dist/change-verification/eve-tool.d.mts +61 -0
  47. package/dist/change-verification/eve-tool.mjs +89 -0
  48. package/dist/change-verification/eve-tool.mjs.map +1 -0
  49. package/dist/change-verification/result.mjs +130 -0
  50. package/dist/change-verification/result.mjs.map +1 -0
  51. package/dist/changes/eve-record-change.d.mts +56 -0
  52. package/dist/changes/eve-record-change.mjs +131 -0
  53. package/dist/changes/eve-record-change.mjs.map +1 -0
  54. package/dist/changes/presentation.d.mts +14 -0
  55. package/dist/changes.d.mts +24 -0
  56. package/dist/changes.mjs +29 -0
  57. package/dist/changes.mjs.map +1 -0
  58. package/dist/client-events.d.mts +25 -0
  59. package/dist/client-events.mjs +45 -0
  60. package/dist/client-events.mjs.map +1 -0
  61. package/dist/client-stream.d.mts +28 -0
  62. package/dist/client-stream.mjs +210 -0
  63. package/dist/client-stream.mjs.map +1 -0
  64. package/dist/client-transcript.d.mts +41 -0
  65. package/dist/client-transcript.mjs +233 -0
  66. package/dist/client-transcript.mjs.map +1 -0
  67. package/dist/client.d.mts +343 -0
  68. package/dist/client.mjs +366 -0
  69. package/dist/client.mjs.map +1 -0
  70. package/dist/code-review/contracts.d.mts +27 -0
  71. package/dist/code-review/eve-post-review.d.mts +70 -0
  72. package/dist/code-review/eve-post-review.mjs +195 -0
  73. package/dist/code-review/eve-post-review.mjs.map +1 -0
  74. package/dist/code-review/eve-review-comments.d.mts +75 -0
  75. package/dist/code-review/eve-review-comments.mjs +193 -0
  76. package/dist/code-review/eve-review-comments.mjs.map +1 -0
  77. package/dist/code-review/github-contracts.d.mts +10 -0
  78. package/dist/code-review/github-reporter.d.mts +46 -0
  79. package/dist/code-review/github-reporter.mjs +262 -0
  80. package/dist/code-review/github-reporter.mjs.map +1 -0
  81. package/dist/code-review/preparation.d.mts +34 -0
  82. package/dist/code-review/preparation.mjs +23 -0
  83. package/dist/code-review/preparation.mjs.map +1 -0
  84. package/dist/code-review/stall.d.mts +17 -0
  85. package/dist/code-review/stall.mjs +30 -0
  86. package/dist/code-review/stall.mjs.map +1 -0
  87. package/dist/code-review.d.mts +7 -0
  88. package/dist/code-review.mjs +5 -0
  89. package/dist/communication.d.mts +9 -0
  90. package/dist/communication.mjs +9 -0
  91. package/dist/connectors/github.d.mts +26 -0
  92. package/dist/connectors/github.mjs +55 -0
  93. package/dist/connectors/github.mjs.map +1 -0
  94. package/dist/connectors/index.d.mts +35 -3
  95. package/dist/connectors/index.mjs +3 -52
  96. package/dist/connectors/index.mjs.map +1 -1
  97. package/dist/connectors/outbox.d.mts +34 -0
  98. package/dist/connectors/outbox.mjs +50 -0
  99. package/dist/connectors/outbox.mjs.map +1 -0
  100. package/dist/connectors/slack-approval-blocks.mjs +136 -0
  101. package/dist/connectors/slack-approval-blocks.mjs.map +1 -0
  102. package/dist/connectors/slack-approvals.d.mts +29 -0
  103. package/dist/connectors/slack-approvals.mjs +346 -0
  104. package/dist/connectors/slack-approvals.mjs.map +1 -0
  105. package/dist/connectors/slack.d.mts +35 -52
  106. package/dist/connectors/slack.mjs +13 -85
  107. package/dist/connectors/slack.mjs.map +1 -1
  108. package/dist/deepsec/eve-tool.d.mts +110 -0
  109. package/dist/deepsec/eve-tool.mjs +166 -0
  110. package/dist/deepsec/eve-tool.mjs.map +1 -0
  111. package/dist/deepsec/finding.d.mts +84 -0
  112. package/dist/deepsec/finding.mjs +56 -0
  113. package/dist/deepsec/finding.mjs.map +1 -0
  114. package/dist/deepsec.d.mts +3 -0
  115. package/dist/delivery-metrics/metrics.d.mts +93 -0
  116. package/dist/delivery-metrics/metrics.mjs +200 -0
  117. package/dist/delivery-metrics/metrics.mjs.map +1 -0
  118. package/dist/delivery-metrics.d.mts +2 -0
  119. package/dist/delivery-metrics.mjs +2 -0
  120. package/dist/dispatch.d.mts +152 -0
  121. package/dist/dispatch.mjs +199 -0
  122. package/dist/dispatch.mjs.map +1 -0
  123. package/dist/errors.d.mts +15 -0
  124. package/dist/errors.mjs +38 -0
  125. package/dist/errors.mjs.map +1 -0
  126. package/dist/eve/index.d.mts +209 -1277
  127. package/dist/eve/index.mjs +312 -1073
  128. package/dist/eve/index.mjs.map +1 -1
  129. package/dist/eve/invoke.d.mts +144 -0
  130. package/dist/eve/invoke.mjs +254 -0
  131. package/dist/eve/invoke.mjs.map +1 -0
  132. package/dist/eve/session-client.d.mts +186 -0
  133. package/dist/eve/session-client.mjs +245 -0
  134. package/dist/eve/session-client.mjs.map +1 -0
  135. package/dist/eve/task-execution.d.mts +380 -0
  136. package/dist/eve/task-execution.mjs +73 -0
  137. package/dist/eve/task-execution.mjs.map +1 -0
  138. package/dist/eve/task-session.d.mts +129 -0
  139. package/dist/eve/task-session.mjs +245 -0
  140. package/dist/eve/task-session.mjs.map +1 -0
  141. package/dist/eve/transcript.d.mts +37 -0
  142. package/dist/eve/transcript.mjs +69 -0
  143. package/dist/eve/transcript.mjs.map +1 -0
  144. package/dist/execution-public.d.mts +8 -0
  145. package/dist/execution-public.mjs +7 -0
  146. package/dist/execution.d.mts +183 -0
  147. package/dist/execution.mjs +223 -0
  148. package/dist/execution.mjs.map +1 -0
  149. package/dist/finding-remediation/admission.d.mts +53 -0
  150. package/dist/finding-remediation/admission.mjs +90 -0
  151. package/dist/finding-remediation/admission.mjs.map +1 -0
  152. package/dist/finding-remediation/brief.d.mts +14 -0
  153. package/dist/finding-remediation/brief.mjs +25 -0
  154. package/dist/finding-remediation/brief.mjs.map +1 -0
  155. package/dist/finding-remediation/eve-tool.d.mts +29 -0
  156. package/dist/finding-remediation/eve-tool.mjs +34 -0
  157. package/dist/finding-remediation/eve-tool.mjs.map +1 -0
  158. package/dist/findings/fingerprint.d.mts +14 -0
  159. package/dist/findings/fingerprint.mjs +28 -0
  160. package/dist/findings/fingerprint.mjs.map +1 -0
  161. package/dist/findings.d.mts +7 -0
  162. package/dist/findings.mjs +6 -0
  163. package/dist/github-app.d.mts +54 -0
  164. package/dist/github-app.mjs +121 -0
  165. package/dist/github-app.mjs.map +1 -0
  166. package/dist/github-publication.d.mts +199 -0
  167. package/dist/github-publication.mjs +442 -0
  168. package/dist/github-publication.mjs.map +1 -0
  169. package/dist/github-transfer.d.mts +81 -0
  170. package/dist/github-transfer.mjs +273 -0
  171. package/dist/github-transfer.mjs.map +1 -0
  172. package/dist/github.d.mts +446 -2
  173. package/dist/github.mjs +357 -56
  174. package/dist/github.mjs.map +1 -1
  175. package/dist/image-input.d.mts +51 -0
  176. package/dist/image-input.mjs +63 -0
  177. package/dist/image-input.mjs.map +1 -0
  178. package/dist/inbox-activity.d.mts +53 -0
  179. package/dist/inbox-activity.mjs +41 -0
  180. package/dist/inbox-activity.mjs.map +1 -0
  181. package/dist/index.d.mts +16 -484
  182. package/dist/index.mjs +15 -522
  183. package/dist/intake-contracts.d.mts +55 -0
  184. package/dist/intake-contracts.mjs +33 -0
  185. package/dist/intake-contracts.mjs.map +1 -0
  186. package/dist/integrations/deepsec.d.mts +5 -0
  187. package/dist/integrations/deepsec.mjs +3 -0
  188. package/dist/integrations/github.d.mts +11 -0
  189. package/dist/integrations/github.mjs +9 -0
  190. package/dist/integrations/slack.d.mts +5 -0
  191. package/dist/integrations/slack.mjs +5 -0
  192. package/dist/integrations/vercel.d.mts +5 -0
  193. package/dist/integrations/vercel.mjs +4 -0
  194. package/dist/merge-resolution/contracts.d.mts +17 -0
  195. package/dist/merge-resolution/contracts.mjs +19 -0
  196. package/dist/merge-resolution/contracts.mjs.map +1 -0
  197. package/dist/merge-resolution/eve-tools.d.mts +47 -0
  198. package/dist/merge-resolution/eve-tools.mjs +122 -0
  199. package/dist/merge-resolution/eve-tools.mjs.map +1 -0
  200. package/dist/model-settings.d.mts +41 -0
  201. package/dist/model-settings.mjs +35 -0
  202. package/dist/model-settings.mjs.map +1 -0
  203. package/dist/multi-repository-changes/coordination.d.mts +49 -0
  204. package/dist/multi-repository-changes/coordination.mjs +115 -0
  205. package/dist/multi-repository-changes/coordination.mjs.map +1 -0
  206. package/dist/planning/cancellation.mjs +82 -0
  207. package/dist/planning/cancellation.mjs.map +1 -0
  208. package/dist/planning/configuration.d.mts +23 -0
  209. package/dist/planning/configuration.mjs +56 -0
  210. package/dist/planning/configuration.mjs.map +1 -0
  211. package/dist/planning/contracts.d.mts +136 -0
  212. package/dist/planning/contracts.mjs +42 -0
  213. package/dist/planning/contracts.mjs.map +1 -0
  214. package/dist/planning/dependencies.mjs +44 -0
  215. package/dist/planning/dependencies.mjs.map +1 -0
  216. package/dist/planning/effects.mjs +122 -0
  217. package/dist/planning/effects.mjs.map +1 -0
  218. package/dist/planning/reconcile.mjs +279 -0
  219. package/dist/planning/reconcile.mjs.map +1 -0
  220. package/dist/planning/runtime.d.mts +27 -0
  221. package/dist/planning/runtime.mjs +25 -0
  222. package/dist/planning/runtime.mjs.map +1 -0
  223. package/dist/planning/state.mjs +92 -0
  224. package/dist/planning/state.mjs.map +1 -0
  225. package/dist/planning/turns.mjs +262 -0
  226. package/dist/planning/turns.mjs.map +1 -0
  227. package/dist/planning/validation.mjs +106 -0
  228. package/dist/planning/validation.mjs.map +1 -0
  229. package/dist/postgres/index.d.mts +48 -1
  230. package/dist/postgres/index.mjs +45 -3
  231. package/dist/postgres/index.mjs.map +1 -1
  232. package/dist/presets/software-development/approval.d.mts +14 -0
  233. package/dist/presets/software-development/approval.mjs +21 -0
  234. package/dist/presets/software-development/approval.mjs.map +1 -0
  235. package/dist/presets/software-development/deepsec-brief.d.mts +8 -0
  236. package/dist/presets/software-development/deepsec-brief.mjs +14 -0
  237. package/dist/presets/software-development/deepsec-brief.mjs.map +1 -0
  238. package/dist/presets/software-development/dispatch.d.mts +56 -0
  239. package/dist/presets/software-development/dispatch.mjs +67 -0
  240. package/dist/presets/software-development/dispatch.mjs.map +1 -0
  241. package/dist/presets/software-development/eve-delegation-policy.d.mts +7 -0
  242. package/dist/presets/software-development/eve-delegation-policy.mjs +34 -0
  243. package/dist/presets/software-development/eve-delegation-policy.mjs.map +1 -0
  244. package/dist/presets/software-development/eve.d.mts +18 -0
  245. package/dist/presets/software-development/eve.mjs +19 -0
  246. package/dist/presets/software-development/eve.mjs.map +1 -0
  247. package/dist/presets/software-development/finish-task-policy.d.mts +7 -0
  248. package/dist/presets/software-development/finish-task-policy.mjs +9 -0
  249. package/dist/presets/software-development/finish-task-policy.mjs.map +1 -0
  250. package/dist/presets/software-development/recovery.d.mts +32 -0
  251. package/dist/presets/software-development/recovery.mjs +120 -0
  252. package/dist/presets/software-development/recovery.mjs.map +1 -0
  253. package/dist/presets/software-development/task-communication.d.mts +24 -0
  254. package/dist/presets/software-development/task-communication.mjs +157 -0
  255. package/dist/presets/software-development/task-communication.mjs.map +1 -0
  256. package/dist/presets/software-development.d.mts +10 -0
  257. package/dist/presets/software-development.mjs +9 -0
  258. package/dist/pull-requests/contracts.d.mts +72 -0
  259. package/dist/pull-requests/eve-fetch.d.mts +57 -0
  260. package/dist/pull-requests/eve-fetch.mjs +151 -0
  261. package/dist/pull-requests/eve-fetch.mjs.map +1 -0
  262. package/dist/pull-requests/github-label-manager.d.mts +27 -0
  263. package/dist/pull-requests/github-label-manager.mjs +40 -0
  264. package/dist/pull-requests/github-label-manager.mjs.map +1 -0
  265. package/dist/pull-requests/github-publisher.d.mts +67 -0
  266. package/dist/pull-requests/github-publisher.mjs +405 -0
  267. package/dist/pull-requests/github-publisher.mjs.map +1 -0
  268. package/dist/pull-requests.d.mts +6 -0
  269. package/dist/pull-requests.mjs +4 -0
  270. package/dist/receipts.d.mts +4 -0
  271. package/dist/receipts.mjs +3 -0
  272. package/dist/repositories.d.mts +18 -0
  273. package/dist/repositories.mjs +33 -0
  274. package/dist/repositories.mjs.map +1 -0
  275. package/dist/sandbox/command.d.mts +18 -0
  276. package/dist/sandbox/execution-abort.d.mts +16 -0
  277. package/dist/sandbox/execution-abort.mjs +49 -0
  278. package/dist/sandbox/execution-abort.mjs.map +1 -0
  279. package/dist/sandbox/execution-environment.d.mts +25 -0
  280. package/dist/sandbox/execution-run-ledger.d.mts +115 -0
  281. package/dist/sandbox/execution-run-ledger.mjs +209 -0
  282. package/dist/sandbox/execution-run-ledger.mjs.map +1 -0
  283. package/dist/sandbox/execution.d.mts +54 -0
  284. package/dist/sandbox/execution.mjs +228 -0
  285. package/dist/sandbox/execution.mjs.map +1 -0
  286. package/dist/sandbox/harness-runner.d.mts +79 -0
  287. package/dist/sandbox/harness-runner.mjs +162 -0
  288. package/dist/sandbox/harness-runner.mjs.map +1 -0
  289. package/dist/sandbox/index.d.mts +10 -0
  290. package/dist/sandbox/index.mjs +7 -0
  291. package/dist/sandbox/task-environment.d.mts +50 -0
  292. package/dist/sandbox/task-environment.mjs +140 -0
  293. package/dist/sandbox/task-environment.mjs.map +1 -0
  294. package/dist/sandbox/workspace.d.mts +29 -0
  295. package/dist/sandbox/workspace.mjs +28 -0
  296. package/dist/sandbox/workspace.mjs.map +1 -0
  297. package/dist/schema/agent-route.d.mts +40 -0
  298. package/dist/schema/agent-route.mjs +33 -0
  299. package/dist/schema/agent-route.mjs.map +1 -0
  300. package/dist/schema/answer.d.mts +23 -0
  301. package/dist/schema/answer.mjs +21 -0
  302. package/dist/schema/answer.mjs.map +1 -0
  303. package/dist/schema/budget.d.mts +38 -0
  304. package/dist/schema/budget.mjs +30 -0
  305. package/dist/schema/budget.mjs.map +1 -0
  306. package/dist/schema/catalog.mjs +72 -0
  307. package/dist/schema/catalog.mjs.map +1 -0
  308. package/dist/schema/change.d.mts +117 -0
  309. package/dist/schema/change.mjs +68 -0
  310. package/dist/schema/change.mjs.map +1 -0
  311. package/dist/schema/common.d.mts +33 -0
  312. package/dist/{id-BLIkCVue.mjs → schema/common.mjs} +7 -16
  313. package/dist/schema/common.mjs.map +1 -0
  314. package/dist/schema/communication.d.mts +52 -0
  315. package/dist/{communication-Kd9nU5RP.mjs → schema/communication.mjs} +8 -3
  316. package/dist/schema/communication.mjs.map +1 -0
  317. package/dist/schema/execution.d.mts +101 -0
  318. package/dist/schema/execution.mjs +86 -0
  319. package/dist/schema/execution.mjs.map +1 -0
  320. package/dist/schema/factory-config.d.mts +122 -0
  321. package/dist/schema/factory-config.mjs +90 -0
  322. package/dist/schema/factory-config.mjs.map +1 -0
  323. package/dist/schema/finding.d.mts +125 -0
  324. package/dist/schema/finding.mjs +67 -0
  325. package/dist/schema/finding.mjs.map +1 -0
  326. package/dist/schema/id.d.mts +43 -0
  327. package/dist/schema/id.mjs +32 -0
  328. package/dist/schema/id.mjs.map +1 -0
  329. package/dist/schema/outbox.d.mts +240 -0
  330. package/dist/schema/outbox.mjs +53 -0
  331. package/dist/schema/outbox.mjs.map +1 -0
  332. package/dist/schema/question-route.mjs +16 -0
  333. package/dist/schema/question-route.mjs.map +1 -0
  334. package/dist/schema/receipt.d.mts +81 -0
  335. package/dist/schema/receipt.mjs +94 -0
  336. package/dist/schema/receipt.mjs.map +1 -0
  337. package/dist/schema/repository.d.mts +30 -0
  338. package/dist/schema/repository.mjs +29 -0
  339. package/dist/schema/repository.mjs.map +1 -0
  340. package/dist/schema/session.d.mts +136 -0
  341. package/dist/schema/session.mjs +54 -0
  342. package/dist/schema/session.mjs.map +1 -0
  343. package/dist/schema/signal.d.mts +105 -0
  344. package/dist/schema/signal.mjs +81 -0
  345. package/dist/schema/signal.mjs.map +1 -0
  346. package/dist/schema/slack-pr-notifications.d.mts +12 -0
  347. package/dist/schema/slack-pr-notifications.mjs +11 -0
  348. package/dist/schema/slack-pr-notifications.mjs.map +1 -0
  349. package/dist/schema/stored-session.mjs +10 -0
  350. package/dist/schema/stored-session.mjs.map +1 -0
  351. package/dist/schema/stored-task.mjs +20 -0
  352. package/dist/schema/stored-task.mjs.map +1 -0
  353. package/dist/schema/task-effect.d.mts +39 -0
  354. package/dist/schema/task-effect.mjs +29 -0
  355. package/dist/schema/task-effect.mjs.map +1 -0
  356. package/dist/schema/task-graph.d.mts +3173 -0
  357. package/dist/schema/task-graph.mjs +97 -0
  358. package/dist/schema/task-graph.mjs.map +1 -0
  359. package/dist/schema/task-message.d.mts +254 -0
  360. package/dist/schema/task-message.mjs +189 -0
  361. package/dist/schema/task-message.mjs.map +1 -0
  362. package/dist/schema/task.d.mts +273 -0
  363. package/dist/schema/task.mjs +200 -0
  364. package/dist/schema/task.mjs.map +1 -0
  365. package/dist/schema/transcript.d.mts +176 -0
  366. package/dist/schema/transcript.mjs +87 -0
  367. package/dist/schema/transcript.mjs.map +1 -0
  368. package/dist/schema/transitions.d.mts +50 -0
  369. package/dist/schema/transitions.mjs +303 -0
  370. package/dist/schema/transitions.mjs.map +1 -0
  371. package/dist/schema/work.d.mts +150 -0
  372. package/dist/schema/work.mjs +102 -0
  373. package/dist/schema/work.mjs.map +1 -0
  374. package/dist/session-previews.d.mts +76 -0
  375. package/dist/session-previews.mjs +55 -0
  376. package/dist/session-previews.mjs.map +1 -0
  377. package/dist/session-review.d.mts +120 -0
  378. package/dist/session-review.mjs +79 -0
  379. package/dist/session-review.mjs.map +1 -0
  380. package/dist/signal-triage.d.mts +20 -0
  381. package/dist/signal-triage.mjs +85 -0
  382. package/dist/signal-triage.mjs.map +1 -0
  383. package/dist/signals.d.mts +20 -0
  384. package/dist/signals.mjs +19 -0
  385. package/dist/signals.mjs.map +1 -0
  386. package/dist/stall.d.mts +41 -0
  387. package/dist/stall.mjs +83 -0
  388. package/dist/stall.mjs.map +1 -0
  389. package/dist/storage.d.mts +4 -0
  390. package/dist/storage.mjs +4 -0
  391. package/dist/store/driver.d.mts +65 -0
  392. package/dist/store/driver.mjs +42 -0
  393. package/dist/store/driver.mjs.map +1 -0
  394. package/dist/store/engine.d.mts +683 -0
  395. package/dist/store/engine.mjs +2309 -0
  396. package/dist/store/engine.mjs.map +1 -0
  397. package/dist/store/memory.d.mts +24 -0
  398. package/dist/store/memory.mjs +69 -0
  399. package/dist/store/memory.mjs.map +1 -0
  400. package/dist/store/slack-pr-notifications.d.mts +44 -0
  401. package/dist/store/slack-pr-notifications.mjs +121 -0
  402. package/dist/store/slack-pr-notifications.mjs.map +1 -0
  403. package/dist/store/task-effects.d.mts +38 -0
  404. package/dist/store/task-effects.mjs +118 -0
  405. package/dist/store/task-effects.mjs.map +1 -0
  406. package/dist/store/task-graphs.d.mts +60 -0
  407. package/dist/store/task-graphs.mjs +212 -0
  408. package/dist/store/task-graphs.mjs.map +1 -0
  409. package/dist/store/task-messages.d.mts +136 -0
  410. package/dist/store/task-messages.mjs +475 -0
  411. package/dist/store/task-messages.mjs.map +1 -0
  412. package/dist/store/task-work.d.mts +180 -0
  413. package/dist/store/task-work.mjs +137 -0
  414. package/dist/store/task-work.mjs.map +1 -0
  415. package/dist/store/work-notifications.d.mts +19 -0
  416. package/dist/store/work-notifications.mjs +48 -0
  417. package/dist/store/work-notifications.mjs.map +1 -0
  418. package/dist/sweep.d.mts +79 -0
  419. package/dist/sweep.mjs +171 -0
  420. package/dist/sweep.mjs.map +1 -0
  421. package/dist/task-communication.d.mts +35 -0
  422. package/dist/task-communication.mjs +47 -0
  423. package/dist/task-communication.mjs.map +1 -0
  424. package/dist/task-graph-view.d.mts +267 -0
  425. package/dist/task-graph-view.mjs +17 -0
  426. package/dist/task-graph-view.mjs.map +1 -0
  427. package/dist/task-message-processing.d.mts +60 -0
  428. package/dist/task-message-processing.mjs +200 -0
  429. package/dist/task-message-processing.mjs.map +1 -0
  430. package/dist/task-protocols.d.mts +80 -0
  431. package/dist/task-protocols.mjs +47 -0
  432. package/dist/task-protocols.mjs.map +1 -0
  433. package/dist/tasks.d.mts +17 -0
  434. package/dist/tasks.mjs +17 -0
  435. package/dist/vercel-git.d.mts +53 -0
  436. package/dist/vercel-git.mjs +344 -0
  437. package/dist/vercel-git.mjs.map +1 -0
  438. package/dist/vercel-github-api.d.mts +103 -0
  439. package/dist/vercel-github-api.mjs +363 -0
  440. package/dist/vercel-github-api.mjs.map +1 -0
  441. package/dist/vercel.d.mts +34 -2
  442. package/dist/vercel.mjs +49 -3
  443. package/dist/vercel.mjs.map +1 -1
  444. package/dist/work-triage/eve-tool.d.mts +29 -0
  445. package/dist/work-triage/eve-tool.mjs +32 -0
  446. package/dist/work-triage/eve-tool.mjs.map +1 -0
  447. package/dist/work-triage/find-existing-work.d.mts +32 -0
  448. package/dist/work-triage/find-existing-work.mjs +31 -0
  449. package/dist/work-triage/find-existing-work.mjs.map +1 -0
  450. package/dist/work-triage/github.d.mts +15 -0
  451. package/dist/work-triage/github.mjs +14 -0
  452. package/dist/work-triage/github.mjs.map +1 -0
  453. package/dist/work-triage.d.mts +4 -0
  454. package/dist/work-triage.mjs +3 -0
  455. package/dist/workflows.d.mts +146 -0
  456. package/dist/workflows.mjs +139 -0
  457. package/dist/workflows.mjs.map +1 -0
  458. package/dist/workspace-diff-assembly.d.mts +33 -0
  459. package/dist/workspace-diff-assembly.mjs +95 -0
  460. package/dist/workspace-diff-assembly.mjs.map +1 -0
  461. package/dist/workspace-diff.d.mts +90 -0
  462. package/dist/workspace-diff.mjs +61 -0
  463. package/dist/workspace-diff.mjs.map +1 -0
  464. package/dist/workspace-files-git.d.mts +15 -0
  465. package/dist/workspace-files-git.mjs +61 -0
  466. package/dist/workspace-files-git.mjs.map +1 -0
  467. package/dist/workspace-files.d.mts +107 -0
  468. package/dist/workspace-files.mjs +74 -0
  469. package/dist/workspace-files.mjs.map +1 -0
  470. package/dist/workspace-snapshot.d.mts +26 -0
  471. package/dist/workspace-snapshot.mjs +80 -0
  472. package/dist/workspace-snapshot.mjs.map +1 -0
  473. package/docs/getting-started.md +104 -0
  474. package/docs/index.md +100 -0
  475. package/docs/recipes/cancellation.md +215 -0
  476. package/docs/recipes/custom-workflow.md +153 -0
  477. package/docs/recipes/dependent-tasks.md +207 -0
  478. package/docs/recipes/eve-agent.md +277 -0
  479. package/docs/recipes/human-input.md +204 -0
  480. package/docs/recipes/persistence-recovery.md +268 -0
  481. package/docs/recipes/retry-recovery.md +241 -0
  482. package/docs/recipes/task-messaging.md +215 -0
  483. package/docs/recipes/typed-eve-result.md +161 -0
  484. package/docs/runtime-integration.md +137 -0
  485. package/package.json +142 -46
  486. package/dist/approval-JX2Px9IC.mjs +0 -132
  487. package/dist/approval-JX2Px9IC.mjs.map +0 -1
  488. package/dist/budget-DzSiIA4t.mjs +0 -42
  489. package/dist/budget-DzSiIA4t.mjs.map +0 -1
  490. package/dist/change-D2U6v7Ek.mjs +0 -554
  491. package/dist/change-D2U6v7Ek.mjs.map +0 -1
  492. package/dist/communication-Kd9nU5RP.mjs.map +0 -1
  493. package/dist/coordination-Cq08hb1l.mjs +0 -76
  494. package/dist/coordination-Cq08hb1l.mjs.map +0 -1
  495. package/dist/dispatch-BaZS3PT8.d.mts +0 -76
  496. package/dist/driver-BC0Mt5KG.d.mts +0 -34
  497. package/dist/driver-Bbd25rNM.mjs +0 -23
  498. package/dist/driver-Bbd25rNM.mjs.map +0 -1
  499. package/dist/engine-DFHU2Pe-.d.mts +0 -781
  500. package/dist/engine-WaUM2cGA.mjs +0 -1068
  501. package/dist/engine-WaUM2cGA.mjs.map +0 -1
  502. package/dist/factory-config-BoRXOw43.mjs +0 -50
  503. package/dist/factory-config-BoRXOw43.mjs.map +0 -1
  504. package/dist/factory-config-D2yU3G0c.d.mts +0 -58
  505. package/dist/github-C5HNBN6p.d.mts +0 -279
  506. package/dist/id-BLIkCVue.mjs.map +0 -1
  507. package/dist/index-Bw6hggoH.d.mts +0 -40
  508. package/dist/index.mjs.map +0 -1
  509. package/dist/task-CcOyOJ3k.mjs +0 -154
  510. package/dist/task-CcOyOJ3k.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-messages.mjs","names":[],"sources":["../../src/store/task-messages.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { WorkNotification } from \"./work-notifications\";\nimport type { DateClock } from \"../schema/common\";\nimport { taskAttemptRefSchema, type TaskAttemptRef } from \"../schema/execution\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { z } from \"zod\";\nimport { SCHEMA_VERSION } from \"../schema/common\";\nimport { taskIdSchema, type TaskId } from \"../schema/id\";\nimport type { Task } from \"../schema/task\";\nimport {\n MAX_TASK_INBOX_PENDING,\n sendTaskMessageInputSchema,\n taskInboxSchema,\n taskMessageIdSchema,\n taskMessageClaimSchema,\n taskMessagePrincipalSchema,\n taskMessageProcessingSchema,\n taskMessageReservationSchema,\n taskMessageSchema,\n taskMessageDiscardSchema,\n type SendTaskMessageInput,\n type TaskInbox,\n type TaskMessage,\n type TaskMessageClaim,\n type TaskMessageDiscard,\n type TaskMessageId,\n type TaskMessagePrincipal,\n type TaskMessageProcessing,\n type TaskMessageProtocolBinding,\n type TaskMessageProtocols,\n} from \"../schema/task-message\";\nimport {\n RecordExistsError,\n VersionConflictError,\n type CollectionName,\n type StoreDriver,\n} from \"./driver\";\n\n/** Operation categories evaluated by the Task message authorization boundary. */\nexport type TaskMessageAction = \"send\" | \"send_result\" | \"read\" | \"claim\" | \"complete\" | \"discard\";\n/** Principal, requested action, and validated Task scope for one authorization decision. */\nexport interface TaskMessageAuthorizationInput {\n readonly principal: TaskMessagePrincipal;\n readonly action: TaskMessageAction;\n readonly fromTask?: Task;\n readonly toTask: Task;\n}\n/** Trusted application authorization, NOT HTTP authentication. Only literal true grants access. */\nexport type TaskMessageAuthorize = (\n input: TaskMessageAuthorizationInput,\n) => boolean | Promise<boolean>;\n/** Engine-owned dependencies and deny-by-default policy used to create a Task message store. */\nexport interface CreateTaskMessageStoreOptions {\n readonly driver: StoreDriver;\n readonly now: DateClock;\n /**\n * Main engine supplies schema-validated snapshots. Task reads and inbox CAS are separate:\n * cancellation/retry can race send, claim, and caller effects. The envelope retains expectAttempt;\n * consumers must fence effects at their application boundary, not assume atomic cancellation here.\n */\n readonly getTask: (id: TaskId) => Promise<Task | null>;\n readonly protocols: TaskMessageProtocols;\n readonly authorize: TaskMessageAuthorize;\n readonly notify?: (event: WorkNotification) => Promise<void>;\n}\n\n/** Authenticated principal and immutable message intent used for one send operation. */\nexport interface TaskMessageSendInput<\n Type extends TaskMessageProtocolBinding = TaskMessageProtocolBinding,\n> {\n readonly principal: TaskMessagePrincipal;\n readonly message: SendTaskMessageInput<Type>;\n}\n\n/** Authenticated principal and recipient identifying one Task inbox. */\nexport interface TaskMessageRecipientInput {\n readonly principal: TaskMessagePrincipal;\n readonly toTaskId: TaskId;\n}\n\n/** Authenticated principal, recipient, and immutable message identifying one inbox record. */\nexport interface TaskMessageLookupInput extends TaskMessageRecipientInput {\n readonly messageId: TaskMessageId;\n}\n\n/** Recipient attempt and bounded lease requested when claiming one Task message. */\nexport interface ClaimTaskMessageInput extends Pick<TaskMessageRecipientInput, \"principal\"> {\n readonly task: TaskAttemptRef;\n readonly leaseMs: number;\n readonly recoverCompleted?: boolean;\n}\n\n/** Authenticated lease and committed-effects attestation used to acknowledge one message. */\nexport interface CompleteTaskMessageInput {\n readonly principal: TaskMessagePrincipal;\n readonly claim: TaskMessageClaim;\n readonly effectsCommitted: true;\n}\n\n/** Authenticated lease whose current validity must be checked before an external effect. */\nexport interface AssertTaskMessageClaimInput {\n readonly principal: TaskMessagePrincipal;\n readonly claim: TaskMessageClaim;\n}\n\n/** Authorized reason for discarding one exact pending inbox head. */\nexport interface DiscardTaskMessageInput extends TaskMessageLookupInput {\n readonly reason: string;\n}\n\n/** Message identity and stable operation name used to derive an external-effect key. */\nexport interface TaskMessageEffectKeyInput {\n readonly messageId: TaskMessageId;\n readonly operation: string;\n}\n\n/** Message and lease returned when one pending inbox head is claimed. */\nexport interface ClaimTaskMessageResult {\n readonly claim: TaskMessageClaim;\n readonly message: TaskMessage;\n}\n\n/** Trusted API for immutable Task messages, recipient inboxes, leases, and acknowledgments. */\nexport interface TaskMessageStore {\n send<const Type extends TaskMessageProtocolBinding>(\n input: TaskMessageSendInput<Type>,\n ): Promise<TaskMessage<Type>>;\n /** Trusted workflow delivery after the source outcome is persisted; requires separate send_result authorization. */\n sendResult<const Type extends TaskMessageProtocolBinding>(\n input: TaskMessageSendInput<Type>,\n ): Promise<TaskMessage<Type>>;\n get(input: TaskMessageLookupInput): Promise<TaskMessage | null>;\n pending(input: TaskMessageRecipientInput): Promise<readonly TaskMessage[]>;\n /**\n * A stale attempt-fenced source or cancelled ordinary source raises TaskMessageSourceFenceError\n * and leaves the head pending. Protocols default to attempt fencing; explicitly task-scoped\n * protocols let workflow triggers survive source retries. Authorized discard can unblock the inbox.\n * Source completion alone does not invalidate previously admitted messages from the same attempt.\n * recoverCompleted defaults to false. It is a trusted application recovery capability for a\n * succeeded/failed recipient: the caller must first validate an exact persisted decision for\n * the pending message, then verify the claimed message matches it. It authorizes no new effects,\n * never permits cancellation recovery, and does not bypass the authorization callback.\n */\n claim(input: ClaimTaskMessageInput): Promise<ClaimTaskMessageResult | null>;\n /**\n * Call only after effects commit. A matching recipient attempt may acknowledge in any state,\n * including cancellation; acknowledgment authorizes no new effects. Leases are not exactly-once.\n */\n complete(input: CompleteTaskMessageInput): Promise<TaskMessageProcessing>;\n /** Read-only claim/complete-authorized lease snapshot check, not a lease extension or external effect fence. Completed claims are invalid. */\n assertClaim(input: AssertTaskMessageClaimInput): Promise<void>;\n /** Discard only the pending head with no unexpired recipient lease, under explicit discard authorization. */\n discard(input: DiscardTaskMessageInput): Promise<void>;\n discarded(input: TaskMessageLookupInput): Promise<TaskMessageDiscard | null>;\n processing(input: TaskMessageLookupInput): Promise<TaskMessageProcessing | null>;\n /** Pure key derivation, not a read or an authorization capability. */\n effectKey(input: TaskMessageEffectKeyInput): string;\n}\n/** Base error for Task message admission, authorization, and processing failures. */\nexport class TaskMessageError extends Error {}\n/** Error raised when an idempotency key is reused with different message intent. */\nexport class TaskMessageConflictError extends TaskMessageError {}\n/** Error raised when a configured Task message policy does not grant an operation. */\nexport class TaskMessageAuthorizationError extends TaskMessageError {}\n/** Error raised when a Task inbox claim is expired, replaced, or otherwise invalid. */\nexport class TaskMessageLeaseError extends TaskMessageError {}\n/** Error raised when an inbox head belongs to a stale or cancelled source attempt. */\nexport class TaskMessageSourceFenceError extends TaskMessageError {\n constructor(\n readonly messageId: TaskMessageId,\n readonly source: TaskAttemptRef,\n readonly currentAttempt: number,\n readonly sourceState: Task[\"state\"],\n ) {\n super(\n `Inbox blocked by message ${messageId}: source ${source.taskId} attempt ${source.attempt}, current attempt ${currentAttempt}, state ${sourceState}. Message remains pending; an explicitly authorized discard is required to unblock this inbox.`,\n );\n this.name = \"TaskMessageSourceFenceError\";\n }\n}\n\n/**\n * Authorizes recipient-local operations and direct parent-child sends for a trusted\n * Task-bound principal while denying result delivery and discard.\n */\nexport const taskBoundMessagePolicy: TaskMessageAuthorize = ({\n principal,\n action,\n fromTask,\n toTask,\n}) => {\n if (action === \"discard\" || action === \"send_result\") return false;\n if (action !== \"send\") return principal.taskId === toTask.id;\n if (!fromTask || !principal.taskId) return false;\n return (\n principal.taskId === fromTask.id &&\n (fromTask.parentTaskId === toTask.id || toTask.parentTaskId === fromTask.id)\n );\n};\nconst claimOptionsSchema = z.strictObject({\n leaseMs: z\n .number()\n .int()\n .min(1)\n .max(300_000)\n .describe(\"Processing lease duration, at most five minutes.\"),\n recoverCompleted: z\n .boolean()\n .default(false)\n .describe(\n \"Trusted recovery of an exact existing decision on a succeeded/failed recipient at the same attempt; not permission for new effects or cancelled Tasks.\",\n ),\n});\nconst acknowledgmentSchema = z.strictObject({\n effectsCommitted: z.literal(true).describe(\"Effects committed before this acknowledgment.\"),\n});\nconst hash = (parts: readonly string[]): string =>\n createHash(\"sha256\").update(JSON.stringify(parts)).digest(\"hex\");\nconst messageIdFor = (source: TaskId, operation: string): TaskMessageId =>\n taskMessageIdSchema.parse(`msg_${hash([source, operation])}`);\nconst messageContent = ({ createdAt: _createdAt, ...content }: TaskMessage) => content;\nconst retryable = (error: unknown): boolean =>\n error instanceof VersionConflictError || error instanceof RecordExistsError;\n\n/** Creates the trusted, CAS-backed Task message and recipient-inbox store. */\nexport function createTaskMessageStore(options: CreateTaskMessageStoreOptions): TaskMessageStore {\n const { driver, now, getTask, protocols, authorize } = options;\n if (typeof authorize !== \"function\")\n throw new TaskMessageAuthorizationError(\n \"Task messages require an explicit authorize callback; no access is granted by default\",\n );\n\n async function task(id: TaskId): Promise<Task> {\n const value = await getTask(taskIdSchema.parse(id));\n if (!value || value.id !== id) throw new TaskMessageError(`Missing Task ${id}`);\n taskIdSchema.parse(value.rootTaskId);\n return value;\n }\n async function scope(\n principal: TaskMessagePrincipal,\n action: TaskMessageAction,\n toTaskId: TaskId,\n fromTaskId?: TaskId,\n ) {\n const toTask = await task(toTaskId);\n const fromTask = fromTaskId === undefined ? undefined : await task(fromTaskId);\n if (fromTask && fromTask.rootTaskId !== toTask.rootTaskId)\n throw new TaskMessageAuthorizationError(\"Cross-root Task messages are not permitted\");\n if (\n (action === \"send\" || action === \"send_result\") &&\n principal.taskId !== undefined &&\n principal.taskId !== fromTaskId\n ) {\n throw new TaskMessageAuthorizationError(\"Task-bound sender must equal fromTaskId\");\n }\n if ((await authorize(structuredClone({ principal, action, fromTask, toTask }))) !== true) {\n throw new TaskMessageAuthorizationError(`Task message ${action} denied for ${principal.id}`);\n }\n return { fromTask, toTask };\n }\n function matchingAttempt(value: Task, expected: number): void {\n if (value.attempt !== expected)\n throw new TaskMessageError(\n `Task ${value.id} requires current attempt ${value.attempt}; received ${expected}`,\n );\n }\n function activeAttempt(value: Task, expected: number): void {\n if (value.attempt !== expected || ![\"queued\", \"running\", \"needs_human\"].includes(value.state)) {\n throw new TaskMessageError(\n `Task ${value.id} requires current attempt ${value.attempt} and queued, running, or needs_human state`,\n );\n }\n }\n function resultAttempt(value: Task, expected: number): void {\n matchingAttempt(value, expected);\n if (![\"succeeded\", \"failed\", \"cancelled\"].includes(value.state)) {\n throw new TaskMessageError(\n `Task ${value.id} requires a persisted succeeded, failed, or cancelled outcome for result delivery`,\n );\n }\n }\n function claimableAttempt(value: Task, expected: number, recoverCompleted: boolean): void {\n if (recoverCompleted && (value.state === \"succeeded\" || value.state === \"failed\"))\n matchingAttempt(value, expected);\n else activeAttempt(value, expected);\n }\n function parseMessage(value: unknown): TaskMessage {\n // Zod retains explicit undefined, but JSON drivers omit it from immutable envelopes.\n const { causationId, delivery, ...message } = taskMessageSchema.parse(value);\n if (message.id !== messageIdFor(message.fromTaskId, message.operationId))\n throw new TaskMessageConflictError(\n \"Stored message ID does not match its source and operation\",\n );\n return {\n ...message,\n ...(causationId === undefined ? {} : { causationId }),\n ...(delivery === undefined ? {} : { delivery }),\n payload: protocols.validateStored(message.type, message.payload),\n };\n }\n function correlateMessage<const Type extends TaskMessageProtocolBinding>(\n message: TaskMessage,\n type: Type,\n ): TaskMessage<Type> {\n if (message.type.id !== type.id || message.type.version !== type.version)\n throw new TaskMessageConflictError(\"Message protocol differs from its send intent\");\n const payload = protocols.validateStored(type, message.payload);\n return structuredClone({ ...message, payload }) as TaskMessage<Type>;\n }\n async function deliveredMessage(intent: TaskMessage): Promise<TaskMessage | null> {\n const stored = await driver.get(\"taskMessages\", intent.id);\n if (!stored) return null;\n const delivered = parseMessage(stored.value);\n if (!isDeepStrictEqual(messageContent(delivered), messageContent(intent))) {\n throw new TaskMessageConflictError(\n `Operation ${intent.operationId} was reused with different content or attempt`,\n );\n }\n return delivered;\n }\n async function immutable<T>(\n collection: CollectionName,\n id: string,\n value: T,\n parse: (value: unknown) => T,\n ): Promise<T> {\n const validated = parse(value);\n try {\n await driver.insert({ collection, id, value: validated });\n } catch (error) {\n if (!(error instanceof RecordExistsError)) throw error;\n const stored = await driver.get(collection, id);\n if (!stored || !isDeepStrictEqual(parse(stored.value), validated))\n throw new TaskMessageConflictError(`Immutable record ${id} has different content`);\n }\n return validated;\n }\n async function inbox(toTaskId: TaskId) {\n const stored = await driver.get(\"taskInboxes\", toTaskId);\n const value = stored\n ? taskInboxSchema.parse(stored.value)\n : taskInboxSchema.parse({\n schemaVersion: SCHEMA_VERSION,\n toTaskId,\n generation: 0,\n pending: [],\n });\n if (value.toTaskId !== toTaskId) throw new TaskMessageError(\"Stored inbox recipient mismatch\");\n value.pending = value.pending.map(parseMessage);\n return { value, version: stored?.version };\n }\n async function saveInbox(value: TaskInbox, version: number | undefined): Promise<boolean> {\n const validated = taskInboxSchema.parse(value);\n try {\n if (version === undefined)\n await driver.insert({ collection: \"taskInboxes\", id: value.toTaskId, value: validated });\n else\n await driver.update({\n collection: \"taskInboxes\",\n id: value.toTaskId,\n value: validated,\n expectedVersion: version,\n });\n return true;\n } catch (error) {\n if (retryable(error)) return false;\n throw error;\n }\n }\n async function repair(\n principal: TaskMessagePrincipal,\n toTaskId: TaskId,\n action: TaskMessageAction,\n targetId?: TaskMessageId,\n ) {\n for (;;) {\n await scope(principal, action, toTaskId);\n const current = await inbox(toTaskId);\n // Repair only projects validated, previously admitted intents and CAS-accepted resolutions.\n // Callers must authorize each message they return or act on, not unrelated repair records.\n for (const message of current.value.pending) {\n if (targetId !== undefined && message.id !== targetId) continue;\n await immutable(\"taskMessages\", message.id, message, parseMessage);\n }\n const { completion, rejection } = current.value;\n const resolved = completion ?? rejection;\n if (!resolved || (targetId !== undefined && resolved.messageId !== targetId)) return current;\n if (completion)\n await immutable(\"taskMessageProcessing\", completion.messageId, completion, (value) =>\n taskMessageProcessingSchema.parse(value),\n );\n if (rejection)\n await immutable(\"taskMessageDiscards\", rejection.messageId, rejection, (value) =>\n taskMessageDiscardSchema.parse(value),\n );\n const next = {\n ...current.value,\n pending: current.value.pending.filter((message) => message.id !== resolved.messageId),\n lease: undefined,\n completion: undefined,\n rejection: undefined,\n };\n if (await saveInbox(next, current.version)) continue;\n }\n }\n async function reserve(message: TaskMessage, expectAttempt: number): Promise<TaskMessage> {\n const key = `reservation_${message.id}`;\n const reservation = taskMessageReservationSchema.parse({\n schemaVersion: SCHEMA_VERSION,\n message,\n expectAttempt,\n });\n try {\n await driver.insert({ collection: \"taskMessageProcessing\", id: key, value: reservation });\n return message;\n } catch (error) {\n if (!(error instanceof RecordExistsError)) throw error;\n const stored = await driver.get(\"taskMessageProcessing\", key);\n if (!stored)\n throw new TaskMessageConflictError(`Missing operation reservation ${message.id}`);\n const existing = taskMessageReservationSchema.parse(stored.value);\n const original = parseMessage(existing.message);\n if (\n existing.expectAttempt !== expectAttempt ||\n !isDeepStrictEqual(messageContent(original), messageContent(message))\n ) {\n throw new TaskMessageConflictError(\n `Operation ${message.operationId} was reused with different content or attempt`,\n );\n }\n return original;\n }\n }\n async function readMessage(\n principal: TaskMessagePrincipal,\n toTaskId: TaskId,\n messageId: TaskMessageId,\n action: TaskMessageAction,\n ): Promise<TaskMessage | null> {\n taskMessageIdSchema.parse(messageId);\n await scope(principal, action, toTaskId);\n await repair(principal, toTaskId, action, messageId);\n const stored = await driver.get(\"taskMessages\", messageId);\n if (!stored) return null;\n const message = parseMessage(stored.value);\n if (message.id !== messageId || message.toTaskId !== toTaskId)\n throw new TaskMessageAuthorizationError(\"Message does not belong to this recipient\");\n await scope(principal, action, toTaskId, message.fromTaskId);\n return message;\n }\n async function processingRecord(messageId: TaskMessageId): Promise<TaskMessageProcessing | null> {\n const stored = await driver.get(\"taskMessageProcessing\", messageId);\n if (!stored) return null;\n const record = taskMessageProcessingSchema.parse(stored.value);\n if (record.messageId !== messageId)\n throw new TaskMessageError(\"Processing record identity mismatch\");\n return record;\n }\n async function discardRecord(messageId: TaskMessageId): Promise<TaskMessageDiscard | null> {\n const stored = await driver.get(\"taskMessageDiscards\", messageId);\n if (!stored) return null;\n const record = taskMessageDiscardSchema.parse(stored.value);\n if (record.messageId !== messageId)\n throw new TaskMessageError(\"Discard record identity mismatch\");\n return record;\n }\n async function requireLiveClaim(\n principal: TaskMessagePrincipal,\n claim: TaskMessageClaim,\n current: TaskInbox,\n ): Promise<Date> {\n if (principal.id !== claim.principalId)\n throw new TaskMessageAuthorizationError(\n \"Only the claiming principal may validate this lease\",\n );\n matchingAttempt(await task(claim.toTaskId), claim.attempt);\n const time = now();\n if (\n current.completion ||\n current.rejection ||\n current.generation !== claim.generation ||\n !isDeepStrictEqual(current.lease, claim) ||\n Date.parse(claim.expiresAt) <= time.getTime()\n ) {\n throw new TaskMessageLeaseError(\n \"Lease expired, resolved, or was replaced; claim again before processing\",\n );\n }\n return time;\n }\n function requireClaim(\n record: TaskMessageProcessing,\n claim: TaskMessageClaim,\n ): TaskMessageProcessing {\n const {\n schemaVersion: _schemaVersion,\n completedAt: _completedAt,\n effectsCommitted: _effectsCommitted,\n ...accepted\n } = record;\n if (!isDeepStrictEqual(accepted, claim))\n throw new TaskMessageLeaseError(\n \"Processing acknowledgment belongs to a different lease generation\",\n );\n return record;\n }\n\n async function send<const Type extends TaskMessageProtocolBinding>(\n context: TaskMessagePrincipal,\n input: SendTaskMessageInput<Type>,\n delivery?: \"result\",\n ): Promise<TaskMessage<Type>> {\n const principal = taskMessagePrincipalSchema.parse(context);\n const parsed = sendTaskMessageInputSchema.parse(input);\n const payload = protocols.validate(input.type, parsed.payload);\n const { expectAttempt } = parsed;\n const action = delivery === \"result\" ? \"send_result\" : \"send\";\n await scope(principal, action, parsed.toTaskId, parsed.fromTaskId);\n const intent = correlateMessage(\n parseMessage({\n ...parsed,\n payload,\n delivery,\n schemaVersion: SCHEMA_VERSION,\n id: messageIdFor(parsed.fromTaskId, parsed.operationId),\n createdAt: now().toISOString(),\n }),\n input.type,\n );\n const delivered = await deliveredMessage(intent);\n if (delivery === \"result\") resultAttempt(await task(parsed.fromTaskId), expectAttempt);\n if (delivered) return correlateMessage(delivered, input.type);\n if (delivery !== \"result\") activeAttempt(await task(parsed.fromTaskId), expectAttempt);\n const recipient = await task(parsed.toTaskId);\n activeAttempt(recipient, recipient.attempt);\n if (parsed.causationId) {\n const stored = await driver.get(\"taskMessages\", parsed.causationId);\n if (!stored)\n throw new TaskMessageError(\"Causation message must already be durably delivered\");\n const cause = parseMessage(stored.value);\n await scope(principal, \"read\", cause.toTaskId, cause.fromTaskId);\n if ((await task(cause.toTaskId)).rootTaskId !== recipient.rootTaskId)\n throw new TaskMessageAuthorizationError(\"Causation must stay within the Task root\");\n }\n const message = correlateMessage(await reserve(intent, expectAttempt), input.type);\n for (;;) {\n await scope(principal, action, message.toTaskId, message.fromTaskId);\n const current = await inbox(message.toTaskId);\n const delivered = await deliveredMessage(message);\n if (delivery === \"result\") resultAttempt(await task(message.fromTaskId), expectAttempt);\n if (delivered) return correlateMessage(delivered, input.type);\n if (delivery !== \"result\") activeAttempt(await task(message.fromTaskId), expectAttempt);\n const recipient = await task(message.toTaskId);\n activeAttempt(recipient, recipient.attempt);\n const pending = current.value.pending.find((entry) => entry.id === message.id);\n if (pending) {\n if (!isDeepStrictEqual(pending, message))\n throw new TaskMessageConflictError(\"Inbox message differs from reserved intent\");\n } else {\n if (current.value.pending.length >= MAX_TASK_INBOX_PENDING)\n throw new TaskMessageError(\n `Recipient inbox is full; maximum ${MAX_TASK_INBOX_PENDING} pending messages`,\n );\n if (\n !(await saveInbox(\n { ...current.value, pending: [...current.value.pending, message] },\n current.version,\n ))\n )\n continue;\n }\n return correlateMessage(\n await immutable(\"taskMessages\", message.id, message, parseMessage),\n input.type,\n );\n }\n }\n\n async function sendAndNotify<const Type extends TaskMessageProtocolBinding>(\n principal: TaskMessagePrincipal,\n input: SendTaskMessageInput<Type>,\n delivery?: \"result\",\n ): Promise<TaskMessage<Type>> {\n const message = await send(principal, input, delivery);\n if (options.notify) {\n const recipient = await task(message.toTaskId);\n await options.notify({ rootTaskId: recipient.rootTaskId, key: `message:${message.id}` });\n }\n return message;\n }\n\n return {\n send: ({ principal, message }) => sendAndNotify(principal, message),\n sendResult: ({ principal, message }) => sendAndNotify(principal, message, \"result\"),\n async get({ principal: context, toTaskId, messageId }) {\n return readMessage(taskMessagePrincipalSchema.parse(context), toTaskId, messageId, \"read\");\n },\n async pending({ principal: context, toTaskId }) {\n const principal = taskMessagePrincipalSchema.parse(context);\n const current = await repair(principal, toTaskId, \"read\");\n for (const message of current.value.pending)\n await scope(principal, \"read\", toTaskId, message.fromTaskId);\n return current.value.pending;\n },\n async claim({ principal: context, task: inputTask, ...input }) {\n const principal = taskMessagePrincipalSchema.parse(context);\n const { taskId: toTaskId, attempt } = taskAttemptRefSchema.parse(inputTask);\n const { leaseMs, recoverCompleted } = claimOptionsSchema.parse(input);\n for (;;) {\n const current = await repair(principal, toTaskId, \"claim\");\n const message = current.value.pending[0];\n if (message) await scope(principal, \"claim\", toTaskId, message.fromTaskId);\n const recipient = await task(toTaskId);\n claimableAttempt(recipient, attempt, recoverCompleted);\n if (\n current.value.lease &&\n current.value.lease.attempt === recipient.attempt &&\n Date.parse(current.value.lease.expiresAt) > now().getTime()\n )\n return null;\n if (!message) return null;\n const source = await task(message.fromTaskId);\n const attemptFenced = protocols.sourceFence(message.type) === \"attempt\";\n if (\n (attemptFenced && source.attempt !== message.expectAttempt) ||\n (source.state === \"cancelled\" && message.delivery !== \"result\")\n ) {\n throw new TaskMessageSourceFenceError(\n message.id,\n { taskId: source.id, attempt: message.expectAttempt },\n source.attempt,\n source.state,\n );\n }\n claimableAttempt(await task(toTaskId), attempt, recoverCompleted);\n const time = now();\n const claim = taskMessageClaimSchema.parse({\n messageId: message.id,\n toTaskId,\n generation: current.value.generation + 1,\n principalId: principal.id,\n attempt,\n expiresAt: new Date(time.getTime() + leaseMs).toISOString(),\n });\n if (\n await saveInbox(\n { ...current.value, generation: claim.generation, lease: claim },\n current.version,\n )\n )\n return { claim, message };\n }\n },\n async complete({ principal: context, claim: input, effectsCommitted }) {\n const principal = taskMessagePrincipalSchema.parse(context);\n const claim = taskMessageClaimSchema.parse(input);\n acknowledgmentSchema.parse({ effectsCommitted });\n if (principal.id !== claim.principalId)\n throw new TaskMessageAuthorizationError(\n \"Only the claiming principal may acknowledge processing\",\n );\n const message = await readMessage(principal, claim.toTaskId, claim.messageId, \"complete\");\n if (!message) throw new TaskMessageLeaseError(\"Claimed message does not exist\");\n for (;;) {\n await scope(principal, \"complete\", claim.toTaskId, message.fromTaskId);\n const current = await inbox(claim.toTaskId);\n const completed = await processingRecord(claim.messageId);\n if (completed) return requireClaim(completed, claim);\n if (current.value.completion) {\n requireClaim(current.value.completion, claim);\n await repair(principal, claim.toTaskId, \"complete\", claim.messageId);\n continue;\n }\n const time = await requireLiveClaim(principal, claim, current.value);\n const completion = taskMessageProcessingSchema.parse({\n ...claim,\n schemaVersion: SCHEMA_VERSION,\n effectsCommitted: true,\n completedAt: time.toISOString(),\n });\n // The inbox CAS accepts the acknowledgment before its immutable record is written.\n // A replaced generation cannot commit here, even if its earlier read was valid.\n if (!(await saveInbox({ ...current.value, completion }, current.version))) continue;\n await repair(principal, claim.toTaskId, \"complete\", claim.messageId);\n return completion;\n }\n },\n async assertClaim({ principal: context, claim: input }) {\n const principal = taskMessagePrincipalSchema.parse(context);\n const claim = taskMessageClaimSchema.parse(input);\n if (principal.id !== claim.principalId)\n throw new TaskMessageAuthorizationError(\n \"Only the claiming principal may validate this lease\",\n );\n await scope(principal, \"claim\", claim.toTaskId);\n const stored = await driver.get(\"taskMessages\", claim.messageId);\n if (!stored) throw new TaskMessageLeaseError(\"Claimed message does not exist\");\n const message = parseMessage(stored.value);\n if (message.id !== claim.messageId || message.toTaskId !== claim.toTaskId)\n throw new TaskMessageAuthorizationError(\"Claim does not belong to this recipient\");\n await scope(principal, \"claim\", claim.toTaskId, message.fromTaskId);\n await scope(principal, \"complete\", claim.toTaskId, message.fromTaskId);\n const completed = await processingRecord(claim.messageId);\n if (completed) {\n requireClaim(completed, claim);\n throw new TaskMessageLeaseError(\n \"Message processing is already complete; the claim is no longer active\",\n );\n }\n await requireLiveClaim(principal, claim, (await inbox(claim.toTaskId)).value);\n },\n async discard({ principal: context, toTaskId, messageId, reason: inputReason }) {\n const principal = taskMessagePrincipalSchema.parse(context);\n const reason = taskMessageDiscardSchema.shape.reason.parse(inputReason);\n const message = await readMessage(principal, toTaskId, messageId, \"discard\");\n if (!message) throw new TaskMessageError(\"Cannot discard a missing message\");\n for (;;) {\n await scope(principal, \"discard\", toTaskId, message.fromTaskId);\n const current = await repair(principal, toTaskId, \"discard\", messageId);\n const discarded = await discardRecord(messageId);\n if (discarded) {\n if (\n discarded.toTaskId !== toTaskId ||\n discarded.reason !== reason ||\n !isDeepStrictEqual(discarded.by, principal)\n )\n throw new TaskMessageConflictError(\"Message already has a different discard decision\");\n return;\n }\n if (await processingRecord(messageId))\n throw new TaskMessageConflictError(\"Processed messages cannot be discarded\");\n if (current.value.pending[0]?.id !== messageId)\n throw new TaskMessageError(\"Only the pending inbox head may be discarded\");\n const time = now();\n if (current.value.lease && Date.parse(current.value.lease.expiresAt) > time.getTime())\n throw new TaskMessageLeaseError(\n \"Cannot discard while the recipient has an unexpired lease, including a prior Task attempt\",\n );\n const rejection = taskMessageDiscardSchema.parse({\n schemaVersion: SCHEMA_VERSION,\n messageId,\n toTaskId,\n reason,\n by: principal,\n discardedAt: time.toISOString(),\n });\n if (!(await saveInbox({ ...current.value, lease: undefined, rejection }, current.version)))\n continue;\n await repair(principal, toTaskId, \"discard\", messageId);\n return;\n }\n },\n async discarded({ principal: context, toTaskId, messageId }) {\n const principal = taskMessagePrincipalSchema.parse(context);\n if (!(await readMessage(principal, toTaskId, messageId, \"read\"))) return null;\n const record = await discardRecord(messageId);\n if (record && record.toTaskId !== toTaskId)\n throw new TaskMessageError(\"Discard record recipient mismatch\");\n return record;\n },\n async processing({ principal: context, toTaskId, messageId }) {\n const principal = taskMessagePrincipalSchema.parse(context);\n if (!(await readMessage(principal, toTaskId, messageId, \"read\"))) return null;\n const record = await processingRecord(messageId);\n if (record && record.toTaskId !== toTaskId)\n throw new TaskMessageError(\"Processing record recipient mismatch\");\n return record;\n },\n effectKey({ messageId, operation }) {\n taskMessageIdSchema.parse(messageId);\n z.string().min(1).max(256).parse(operation);\n return `effect_${hash([messageId, operation])}`;\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,180 @@
1
+ import { TaskId } from "../schema/id.mjs";
2
+ import { JsonValue, WorkflowBinding } from "../schema/work.mjs";
3
+ import { ExecutionReference, Task, TaskState } from "../schema/task.mjs";
4
+ import { WorkflowRegistry } from "../workflows.mjs";
5
+ import { IsoDateTimeClock } from "../schema/common.mjs";
6
+ import { TaskAttemptRef } from "../schema/execution.mjs";
7
+ import { StoreDriver } from "./driver.mjs";
8
+ import { FactoryStores } from "./engine.mjs";
9
+ //#region src/store/task-work.d.ts
10
+ /** Workflow-facing Task operations for completion, message waiting, recovery, and usage aggregation. */
11
+ interface TaskWorkStore {
12
+ /**
13
+ * Completes through the dynamic registry boundary, which validates unknown output at runtime.
14
+ *
15
+ * @remarks
16
+ * The exact Task attempt is mandatory. The engine validates output against the Task's stored
17
+ * workflow, persists it with the `succeeded` transition, and returns only after that write. A
18
+ * replay with the same validated output returns the existing succeeded Task; different output
19
+ * is refused. This method does not authenticate a provider callback—use a fence and establish
20
+ * caller authority before invoking it.
21
+ *
22
+ * @param input - Exact Task attempt, unknown candidate output, and optional execution fence.
23
+ * @returns The durably succeeded Task containing its validated `workResult`.
24
+ * @throws When the attempt, lifecycle state, execution fence, or runtime output validation fails.
25
+ */
26
+ complete(input: CompleteTaskWorkInput): Promise<Task>;
27
+ /**
28
+ * Completes work while statically checking output against its exact workflow binding.
29
+ *
30
+ * @remarks
31
+ * In addition to `complete` semantics, the supplied binding must equal the Task's persisted
32
+ * workflow ID and version. Retain historical workflow definitions in the registry while stored
33
+ * Tasks may still use them. For Eve tools, authenticate first with `requireTaskExecution` and
34
+ * pass its attempt and execution as the completion fence.
35
+ *
36
+ * @param input - Exact Task attempt, typed workflow binding and output, and optional fence.
37
+ * @returns The durably succeeded Task containing its validated `workResult`.
38
+ * @throws When the workflow, attempt, lifecycle state, execution fence, or output is invalid.
39
+ */
40
+ completeWorkflow<Output extends JsonValue>(input: CompleteWorkflowTaskWorkInput<Output>): Promise<Task>;
41
+ /**
42
+ * Marks a running exact Task attempt as intentionally inactive while awaiting messages.
43
+ *
44
+ * @remarks
45
+ * This keeps the Task in `running`; it does not stall, cancel, or create a new attempt. The
46
+ * waiting marker and optional workflow phase are durable when the promise resolves. Repeating
47
+ * the same target state is a no-op. A stale attempt or non-running Task is refused, so callers
48
+ * should reread the Task before deciding whether a later attempt still needs the message.
49
+ *
50
+ * @param input - Exact running attempt and optional workflow phase.
51
+ * @returns The updated running Task with `waitingForMessages` set.
52
+ * @throws When the Task is absent, no longer running, or on a different attempt.
53
+ */
54
+ waitForMessages(input: WaitForTaskMessagesInput): Promise<Task>;
55
+ /**
56
+ * Resumes an exact message-waiting Task attempt and records fresh progress.
57
+ *
58
+ * @remarks
59
+ * The Task remains `running`, its waiting marker is cleared, and `lastProgressAt` advances. The
60
+ * write is durable when the promise resolves and repeating it for an already-resumed attempt is
61
+ * a no-op. Resuming does not claim or acknowledge messages; the workflow owns that ordering.
62
+ *
63
+ * @param input - Exact running attempt to resume.
64
+ * @returns The updated running Task with message waiting cleared.
65
+ * @throws When the Task is absent, no longer running, or on a different attempt.
66
+ */
67
+ resume(input: ResumeTaskWorkInput): Promise<Task>;
68
+ /**
69
+ * Repairs admitted creation snapshots by direct graph IDs, never by scanning the bucket.
70
+ *
71
+ * @remarks
72
+ * The canonical graph contains immutable admission snapshots. Recovery validates every
73
+ * admission against the exact registered workflow, restores only missing Task records, and
74
+ * returns existing records with their current mutable progress. It is safe to repeat after an
75
+ * interrupted Task creation.
76
+ *
77
+ * This operation repairs Factory persistence only. It does not start or reattach a provider
78
+ * execution, rerun workflow code, retry a Task, or migrate old Task JSON. After recovery, the
79
+ * caller must inspect each Task's lifecycle and recorded execution and apply workflow-owned
80
+ * reconciliation policy.
81
+ *
82
+ * @param rootTaskId - Root of the canonical Task graph to repair and read.
83
+ * @returns Every validated Task admitted to that graph.
84
+ * @throws When the graph is absent, a stored workflow version is not registered, persisted data
85
+ * is invalid, or a current Task no longer matches its immutable admission identity.
86
+ */
87
+ recover(rootTaskId: TaskId): Promise<readonly Task[]>;
88
+ /**
89
+ * Aggregates Task-local measured usage once without charging parent roll-ups again.
90
+ *
91
+ * @remarks
92
+ * This first performs the same persistence repair and validation as {@link recover}. For each
93
+ * Task, recorded step usage is authoritative; otherwise a settled amount is used, then zero.
94
+ * The result is a current snapshot, not a reservation or billing transaction, and calling it
95
+ * does not write settlement receipts.
96
+ *
97
+ * @param rootTaskId - Root of the canonical Task graph to aggregate.
98
+ * @returns Cost, token, and Task counts for the recovered graph.
99
+ * @throws The same persistence and validation errors as {@link recover}.
100
+ */
101
+ usage(rootTaskId: TaskId): Promise<TaskWorkUsage>;
102
+ }
103
+ /** Exact Task attempt and candidate workflow output used to complete work. */
104
+ interface CompleteTaskWorkInput {
105
+ /** Task ID and current positive attempt; stale attempts are refused. */
106
+ task: TaskAttemptRef;
107
+ /** Candidate value validated against the Task's exact registered output schema. */
108
+ output: unknown;
109
+ /**
110
+ * Optional source-state and execution fence for provider callbacks. Omit only when trusted
111
+ * workflow code already owns lifecycle authority.
112
+ */
113
+ fence?: TaskWorkCompletionFence;
114
+ }
115
+ /** Exact Task attempt, workflow contract, and statically checked output used to complete work. */
116
+ interface CompleteWorkflowTaskWorkInput<Output extends JsonValue = JsonValue> {
117
+ /** Task ID and current positive attempt; stale attempts are refused. */
118
+ task: TaskAttemptRef;
119
+ /** Exact binding required to match the Task's persisted workflow. */
120
+ workflow: WorkflowBinding<JsonValue, Output>;
121
+ /** Candidate output statically carried by the binding and validated again at runtime. */
122
+ output: NoInfer<Output>;
123
+ /**
124
+ * Optional source-state and execution fence for provider callbacks. Omit only when trusted
125
+ * workflow code already owns lifecycle authority.
126
+ */
127
+ fence?: TaskWorkCompletionFence;
128
+ }
129
+ /** Atomic source-state and provider-execution conditions for a workflow completion write. */
130
+ interface TaskWorkCompletionFence {
131
+ /** Lifecycle state required atomically with completion, normally `running`. */
132
+ readonly from: TaskState;
133
+ /** Provider execution reference required to remain current at the completion write. */
134
+ readonly execution: ExecutionReference;
135
+ }
136
+ /** Aggregated measured usage across one canonical Task graph. */
137
+ interface TaskWorkUsage {
138
+ /** Sum of measured Task usage, falling back to settlement only when no usage is recorded. */
139
+ costUsd: number;
140
+ /** Sum of recorded provider input tokens across Tasks. */
141
+ inputTokens: number;
142
+ /** Sum of recorded provider output tokens across Tasks. */
143
+ outputTokens: number;
144
+ /** Number of Tasks admitted to the recovered canonical graph. */
145
+ taskCount: number;
146
+ }
147
+ /** Exact running Task attempt and optional workflow phase used to await messages. */
148
+ interface WaitForTaskMessagesInput {
149
+ /** Task ID and current positive attempt; stale attempts are refused. */
150
+ task: TaskAttemptRef;
151
+ /** Optional durable workflow-owned phase label retained across waiting and resumption. */
152
+ phase?: string;
153
+ }
154
+ /** Exact running Task attempt to resume after message delivery. */
155
+ interface ResumeTaskWorkInput {
156
+ /** Task ID and current positive attempt; stale attempts are refused. */
157
+ task: TaskAttemptRef;
158
+ }
159
+ /** Canonical Task graph, receipt, and Task capabilities used by workflow-facing operations. */
160
+ type TaskWorkStores = Pick<FactoryStores, "graphs" | "receipts" | "tasks">;
161
+ /** Engine-owned dependencies used to construct workflow-facing Task operations. */
162
+ interface CreateTaskWorkStoreOptions {
163
+ /** Policy-free persistence driver used for direct canonical Task reads. */
164
+ driver: StoreDriver;
165
+ /** ISO timestamp source shared with the surrounding store engine. */
166
+ now: IsoDateTimeClock;
167
+ /** Lazily resolves graph, receipt, and Task operations after engine construction. */
168
+ stores: () => TaskWorkStores;
169
+ /** Exact workflow versions used to validate stored input and completion output. */
170
+ workflows: WorkflowRegistry;
171
+ /** Persists a validated Task with compare-and-swap semantics. */
172
+ update(task: Task, version: number): Promise<void>;
173
+ /** Recreates a missing canonical Task snapshot from its immutable graph admission. */
174
+ restore(task: Task): Promise<Task>;
175
+ }
176
+ /** Creates workflow-facing Task operations backed by canonical graph and Task stores. */
177
+ declare function createTaskWorkStore(options: CreateTaskWorkStoreOptions): TaskWorkStore;
178
+ //#endregion
179
+ export { CompleteTaskWorkInput, CompleteWorkflowTaskWorkInput, CreateTaskWorkStoreOptions, ResumeTaskWorkInput, TaskWorkCompletionFence, TaskWorkStore, TaskWorkStores, TaskWorkUsage, WaitForTaskMessagesInput, createTaskWorkStore };
180
+ //# sourceMappingURL=task-work.d.mts.map
@@ -0,0 +1,137 @@
1
+ import { taskSchema } from "../schema/task.mjs";
2
+ import { InvalidTransitionError } from "../schema/transitions.mjs";
3
+ import { RecordNotFoundError, VersionConflictError } from "./driver.mjs";
4
+ import { assertTaskAdmission } from "./task-graphs.mjs";
5
+ import { z } from "zod";
6
+ import { isDeepStrictEqual } from "node:util";
7
+ //#region src/store/task-work.ts
8
+ /** Creates workflow-facing Task operations backed by canonical graph and Task stores. */
9
+ function createTaskWorkStore(options) {
10
+ const { driver, now, stores, workflows, update, restore } = options;
11
+ function parseTask(value) {
12
+ const task = taskSchema.parse(value);
13
+ workflows.validateStoredInput(task.work.workflow, task.work.input);
14
+ if (task.workResult) workflows.validateStoredOutput(task.work.workflow, task.workResult.output);
15
+ return task;
16
+ }
17
+ async function read(id) {
18
+ const record = await driver.get("tasks", id);
19
+ if (!record) throw new RecordNotFoundError("tasks", id);
20
+ const task = parseTask(record.value);
21
+ if (task.id !== id) throw new Error(`Task ${id} does not match its storage key`);
22
+ return {
23
+ task,
24
+ version: record.version,
25
+ work: task.work
26
+ };
27
+ }
28
+ async function recover(rootTaskId) {
29
+ const graph = await stores().graphs.get(rootTaskId);
30
+ if (!graph) throw new RecordNotFoundError("taskGraphs", rootTaskId);
31
+ const tasks = [];
32
+ for (const node of graph.nodes) {
33
+ const admission = parseTask(node.admission);
34
+ const task = parseTask(await stores().tasks.get(node.taskId) ?? await restore(admission));
35
+ assertTaskAdmission({
36
+ task,
37
+ admission
38
+ });
39
+ tasks.push(task);
40
+ }
41
+ return tasks;
42
+ }
43
+ function assertAttempt(task, expectAttempt) {
44
+ z.number().int().positive().parse(expectAttempt);
45
+ if (task.attempt !== expectAttempt) throw new Error(`Task ${task.id} is on attempt ${task.attempt}, not ${expectAttempt}`);
46
+ }
47
+ async function setWaiting(id, expectAttempt, waiting, phase) {
48
+ for (;;) {
49
+ const { task, version } = await read(id);
50
+ assertAttempt(task, expectAttempt);
51
+ if (task.state !== "running") throw new Error(`Task ${id} must be running to ${waiting ? "wait" : "resume"}`);
52
+ const next = taskSchema.parse({
53
+ ...task,
54
+ waitingForMessages: waiting,
55
+ workflowPhase: phase ?? task.workflowPhase,
56
+ lastProgressAt: waiting ? task.lastProgressAt : now(),
57
+ updatedAt: now()
58
+ });
59
+ if (task.waitingForMessages === waiting && next.workflowPhase === task.workflowPhase) return task;
60
+ await stores().receipts.append({
61
+ taskId: id,
62
+ repositoryIds: task.repositoryIds,
63
+ kind: task.kind,
64
+ state: waiting ? "waiting" : "resumed",
65
+ phase: "workflow",
66
+ attempt: task.attempt,
67
+ reason: waiting ? "Workflow is waiting for Task messages" : "Workflow resumed message processing",
68
+ dedupeKey: `work:${id}:${version}:${waiting ? "wait" : "resume"}`
69
+ });
70
+ try {
71
+ await update(next, version);
72
+ return next;
73
+ } catch (error) {
74
+ if (!(error instanceof VersionConflictError)) throw error;
75
+ }
76
+ }
77
+ }
78
+ async function complete(input, expectedWorkflow) {
79
+ const { task: { taskId: id, attempt: expectAttempt }, output: value, fence } = input;
80
+ for (;;) {
81
+ const { task, work } = await read(id);
82
+ assertAttempt(task, expectAttempt);
83
+ if (fence !== void 0 && !isDeepStrictEqual(task.execution, fence.execution)) throw new Error(`Task ${id} execution has been replaced`);
84
+ if (expectedWorkflow !== void 0 && !isDeepStrictEqual(work.workflow, expectedWorkflow)) throw new Error(`Task ${id} uses workflow ${work.workflow.id}@${work.workflow.version}, not ${expectedWorkflow.id}@${expectedWorkflow.version}`);
85
+ if (task.state === "succeeded") {
86
+ const output = workflows.validateOutput(work.workflow, value);
87
+ if (!isDeepStrictEqual(task.workResult?.output, output)) throw new Error(`Task ${id} already recorded a different workflow output`);
88
+ return task;
89
+ }
90
+ try {
91
+ return await stores().tasks.transition(id, "succeeded", {
92
+ output: value,
93
+ expectAttempt,
94
+ expectFrom: fence?.from ?? task.state,
95
+ ...fence === void 0 ? {} : { expectExecution: fence.execution },
96
+ phase: "workflow"
97
+ });
98
+ } catch (error) {
99
+ if (error instanceof VersionConflictError) continue;
100
+ if (error instanceof InvalidTransitionError && (await read(id)).task.state === "succeeded") continue;
101
+ throw error;
102
+ }
103
+ }
104
+ }
105
+ return {
106
+ complete,
107
+ completeWorkflow: ({ task, workflow, output, fence }) => complete({
108
+ task,
109
+ output,
110
+ fence
111
+ }, workflow),
112
+ waitForMessages: ({ task: { taskId, attempt }, phase }) => setWaiting(taskId, attempt, true, phase),
113
+ resume: ({ task: { taskId, attempt } }) => setWaiting(taskId, attempt, false),
114
+ recover,
115
+ async usage(rootTaskId) {
116
+ const tasks = await recover(rootTaskId);
117
+ let micros = 0;
118
+ let inputTokens = 0;
119
+ let outputTokens = 0;
120
+ for (const task of tasks) {
121
+ micros += Math.round((task.usage?.costUsd ?? task.settledUsd ?? 0) * 1e6);
122
+ inputTokens += task.usage?.inputTokens ?? 0;
123
+ outputTokens += task.usage?.outputTokens ?? 0;
124
+ }
125
+ return {
126
+ costUsd: micros / 1e6,
127
+ inputTokens,
128
+ outputTokens,
129
+ taskCount: tasks.length
130
+ };
131
+ }
132
+ };
133
+ }
134
+ //#endregion
135
+ export { createTaskWorkStore };
136
+
137
+ //# sourceMappingURL=task-work.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-work.mjs","names":[],"sources":["../../src/store/task-work.ts"],"sourcesContent":["import { isDeepStrictEqual } from \"node:util\";\nimport { z } from \"zod\";\nimport type { IsoDateTimeClock } from \"../schema/common\";\nimport type { TaskAttemptRef } from \"../schema/execution\";\nimport type { TaskId } from \"../schema/id\";\nimport { taskSchema, type ExecutionReference, type Task, type TaskState } from \"../schema/task\";\nimport { InvalidTransitionError } from \"../schema/transitions\";\nimport type { JsonValue, WorkflowBinding } from \"../schema/work\";\nimport type { WorkflowRegistry } from \"../workflows\";\nimport { RecordNotFoundError, VersionConflictError, type StoreDriver } from \"./driver\";\nimport type { FactoryStores } from \"./engine\";\nimport { assertTaskAdmission } from \"./task-graphs\";\n\n/** Workflow-facing Task operations for completion, message waiting, recovery, and usage aggregation. */\nexport interface TaskWorkStore {\n /**\n * Completes through the dynamic registry boundary, which validates unknown output at runtime.\n *\n * @remarks\n * The exact Task attempt is mandatory. The engine validates output against the Task's stored\n * workflow, persists it with the `succeeded` transition, and returns only after that write. A\n * replay with the same validated output returns the existing succeeded Task; different output\n * is refused. This method does not authenticate a provider callback—use a fence and establish\n * caller authority before invoking it.\n *\n * @param input - Exact Task attempt, unknown candidate output, and optional execution fence.\n * @returns The durably succeeded Task containing its validated `workResult`.\n * @throws When the attempt, lifecycle state, execution fence, or runtime output validation fails.\n */\n complete(input: CompleteTaskWorkInput): Promise<Task>;\n /**\n * Completes work while statically checking output against its exact workflow binding.\n *\n * @remarks\n * In addition to `complete` semantics, the supplied binding must equal the Task's persisted\n * workflow ID and version. Retain historical workflow definitions in the registry while stored\n * Tasks may still use them. For Eve tools, authenticate first with `requireTaskExecution` and\n * pass its attempt and execution as the completion fence.\n *\n * @param input - Exact Task attempt, typed workflow binding and output, and optional fence.\n * @returns The durably succeeded Task containing its validated `workResult`.\n * @throws When the workflow, attempt, lifecycle state, execution fence, or output is invalid.\n */\n completeWorkflow<Output extends JsonValue>(\n input: CompleteWorkflowTaskWorkInput<Output>,\n ): Promise<Task>;\n /**\n * Marks a running exact Task attempt as intentionally inactive while awaiting messages.\n *\n * @remarks\n * This keeps the Task in `running`; it does not stall, cancel, or create a new attempt. The\n * waiting marker and optional workflow phase are durable when the promise resolves. Repeating\n * the same target state is a no-op. A stale attempt or non-running Task is refused, so callers\n * should reread the Task before deciding whether a later attempt still needs the message.\n *\n * @param input - Exact running attempt and optional workflow phase.\n * @returns The updated running Task with `waitingForMessages` set.\n * @throws When the Task is absent, no longer running, or on a different attempt.\n */\n waitForMessages(input: WaitForTaskMessagesInput): Promise<Task>;\n /**\n * Resumes an exact message-waiting Task attempt and records fresh progress.\n *\n * @remarks\n * The Task remains `running`, its waiting marker is cleared, and `lastProgressAt` advances. The\n * write is durable when the promise resolves and repeating it for an already-resumed attempt is\n * a no-op. Resuming does not claim or acknowledge messages; the workflow owns that ordering.\n *\n * @param input - Exact running attempt to resume.\n * @returns The updated running Task with message waiting cleared.\n * @throws When the Task is absent, no longer running, or on a different attempt.\n */\n resume(input: ResumeTaskWorkInput): Promise<Task>;\n /**\n * Repairs admitted creation snapshots by direct graph IDs, never by scanning the bucket.\n *\n * @remarks\n * The canonical graph contains immutable admission snapshots. Recovery validates every\n * admission against the exact registered workflow, restores only missing Task records, and\n * returns existing records with their current mutable progress. It is safe to repeat after an\n * interrupted Task creation.\n *\n * This operation repairs Factory persistence only. It does not start or reattach a provider\n * execution, rerun workflow code, retry a Task, or migrate old Task JSON. After recovery, the\n * caller must inspect each Task's lifecycle and recorded execution and apply workflow-owned\n * reconciliation policy.\n *\n * @param rootTaskId - Root of the canonical Task graph to repair and read.\n * @returns Every validated Task admitted to that graph.\n * @throws When the graph is absent, a stored workflow version is not registered, persisted data\n * is invalid, or a current Task no longer matches its immutable admission identity.\n */\n recover(rootTaskId: TaskId): Promise<readonly Task[]>;\n /**\n * Aggregates Task-local measured usage once without charging parent roll-ups again.\n *\n * @remarks\n * This first performs the same persistence repair and validation as {@link recover}. For each\n * Task, recorded step usage is authoritative; otherwise a settled amount is used, then zero.\n * The result is a current snapshot, not a reservation or billing transaction, and calling it\n * does not write settlement receipts.\n *\n * @param rootTaskId - Root of the canonical Task graph to aggregate.\n * @returns Cost, token, and Task counts for the recovered graph.\n * @throws The same persistence and validation errors as {@link recover}.\n */\n usage(rootTaskId: TaskId): Promise<TaskWorkUsage>;\n}\n\n/** Exact Task attempt and candidate workflow output used to complete work. */\nexport interface CompleteTaskWorkInput {\n /** Task ID and current positive attempt; stale attempts are refused. */\n task: TaskAttemptRef;\n /** Candidate value validated against the Task's exact registered output schema. */\n output: unknown;\n /**\n * Optional source-state and execution fence for provider callbacks. Omit only when trusted\n * workflow code already owns lifecycle authority.\n */\n fence?: TaskWorkCompletionFence;\n}\n\n/** Exact Task attempt, workflow contract, and statically checked output used to complete work. */\nexport interface CompleteWorkflowTaskWorkInput<Output extends JsonValue = JsonValue> {\n /** Task ID and current positive attempt; stale attempts are refused. */\n task: TaskAttemptRef;\n /** Exact binding required to match the Task's persisted workflow. */\n workflow: WorkflowBinding<JsonValue, Output>;\n /** Candidate output statically carried by the binding and validated again at runtime. */\n output: NoInfer<Output>;\n /**\n * Optional source-state and execution fence for provider callbacks. Omit only when trusted\n * workflow code already owns lifecycle authority.\n */\n fence?: TaskWorkCompletionFence;\n}\n\n/** Atomic source-state and provider-execution conditions for a workflow completion write. */\nexport interface TaskWorkCompletionFence {\n /** Lifecycle state required atomically with completion, normally `running`. */\n readonly from: TaskState;\n /** Provider execution reference required to remain current at the completion write. */\n readonly execution: ExecutionReference;\n}\n\n/** Aggregated measured usage across one canonical Task graph. */\nexport interface TaskWorkUsage {\n /** Sum of measured Task usage, falling back to settlement only when no usage is recorded. */\n costUsd: number;\n /** Sum of recorded provider input tokens across Tasks. */\n inputTokens: number;\n /** Sum of recorded provider output tokens across Tasks. */\n outputTokens: number;\n /** Number of Tasks admitted to the recovered canonical graph. */\n taskCount: number;\n}\n\n/** Exact running Task attempt and optional workflow phase used to await messages. */\nexport interface WaitForTaskMessagesInput {\n /** Task ID and current positive attempt; stale attempts are refused. */\n task: TaskAttemptRef;\n /** Optional durable workflow-owned phase label retained across waiting and resumption. */\n phase?: string;\n}\n\n/** Exact running Task attempt to resume after message delivery. */\nexport interface ResumeTaskWorkInput {\n /** Task ID and current positive attempt; stale attempts are refused. */\n task: TaskAttemptRef;\n}\n\n/** Canonical Task graph, receipt, and Task capabilities used by workflow-facing operations. */\nexport type TaskWorkStores = Pick<FactoryStores, \"graphs\" | \"receipts\" | \"tasks\">;\n\n/** Engine-owned dependencies used to construct workflow-facing Task operations. */\nexport interface CreateTaskWorkStoreOptions {\n /** Policy-free persistence driver used for direct canonical Task reads. */\n driver: StoreDriver;\n /** ISO timestamp source shared with the surrounding store engine. */\n now: IsoDateTimeClock;\n /** Lazily resolves graph, receipt, and Task operations after engine construction. */\n stores: () => TaskWorkStores;\n /** Exact workflow versions used to validate stored input and completion output. */\n workflows: WorkflowRegistry;\n /** Persists a validated Task with compare-and-swap semantics. */\n update(task: Task, version: number): Promise<void>;\n /** Recreates a missing canonical Task snapshot from its immutable graph admission. */\n restore(task: Task): Promise<Task>;\n}\n\n/** Creates workflow-facing Task operations backed by canonical graph and Task stores. */\nexport function createTaskWorkStore(options: CreateTaskWorkStoreOptions): TaskWorkStore {\n const { driver, now, stores, workflows, update, restore } = options;\n function parseTask(value: unknown): Task {\n const task = taskSchema.parse(value);\n workflows.validateStoredInput(task.work.workflow, task.work.input);\n if (task.workResult) workflows.validateStoredOutput(task.work.workflow, task.workResult.output);\n return task;\n }\n async function read(id: TaskId) {\n const record = await driver.get(\"tasks\", id);\n if (!record) throw new RecordNotFoundError(\"tasks\", id);\n const task = parseTask(record.value);\n if (task.id !== id) throw new Error(`Task ${id} does not match its storage key`);\n return { task, version: record.version, work: task.work };\n }\n async function recover(rootTaskId: TaskId): Promise<readonly Task[]> {\n const graph = await stores().graphs.get(rootTaskId);\n if (!graph) throw new RecordNotFoundError(\"taskGraphs\", rootTaskId);\n const tasks: Task[] = [];\n for (const node of graph.nodes) {\n const admission = parseTask(node.admission);\n const existing = await stores().tasks.get(node.taskId);\n const task = parseTask(existing ?? (await restore(admission)));\n assertTaskAdmission({ task, admission });\n tasks.push(task);\n }\n return tasks;\n }\n function assertAttempt(task: Task, expectAttempt: number) {\n z.number().int().positive().parse(expectAttempt);\n if (task.attempt !== expectAttempt)\n throw new Error(`Task ${task.id} is on attempt ${task.attempt}, not ${expectAttempt}`);\n }\n async function setWaiting(\n id: TaskId,\n expectAttempt: number,\n waiting: boolean,\n phase?: string,\n ): Promise<Task> {\n for (;;) {\n const { task, version } = await read(id);\n assertAttempt(task, expectAttempt);\n if (task.state !== \"running\")\n throw new Error(`Task ${id} must be running to ${waiting ? \"wait\" : \"resume\"}`);\n const next = taskSchema.parse({\n ...task,\n waitingForMessages: waiting,\n workflowPhase: phase ?? task.workflowPhase,\n lastProgressAt: waiting ? task.lastProgressAt : now(),\n updatedAt: now(),\n });\n if (task.waitingForMessages === waiting && next.workflowPhase === task.workflowPhase)\n return task;\n await stores().receipts.append({\n taskId: id,\n repositoryIds: task.repositoryIds,\n kind: task.kind,\n state: waiting ? \"waiting\" : \"resumed\",\n phase: \"workflow\",\n attempt: task.attempt,\n reason: waiting\n ? \"Workflow is waiting for Task messages\"\n : \"Workflow resumed message processing\",\n dedupeKey: `work:${id}:${version}:${waiting ? \"wait\" : \"resume\"}`,\n });\n try {\n await update(next, version);\n return next;\n } catch (error) {\n if (!(error instanceof VersionConflictError)) throw error;\n }\n }\n }\n async function complete(\n input: CompleteTaskWorkInput,\n expectedWorkflow?: WorkflowBinding,\n ): Promise<Task> {\n const {\n task: { taskId: id, attempt: expectAttempt },\n output: value,\n fence,\n } = input;\n for (;;) {\n const { task, work } = await read(id);\n assertAttempt(task, expectAttempt);\n if (fence !== undefined && !isDeepStrictEqual(task.execution, fence.execution)) {\n throw new Error(`Task ${id} execution has been replaced`);\n }\n if (expectedWorkflow !== undefined && !isDeepStrictEqual(work.workflow, expectedWorkflow)) {\n throw new Error(\n `Task ${id} uses workflow ${work.workflow.id}@${work.workflow.version}, not ${expectedWorkflow.id}@${expectedWorkflow.version}`,\n );\n }\n if (task.state === \"succeeded\") {\n const output = workflows.validateOutput(work.workflow, value);\n if (!isDeepStrictEqual(task.workResult?.output, output)) {\n throw new Error(`Task ${id} already recorded a different workflow output`);\n }\n return task;\n }\n try {\n return await stores().tasks.transition(id, \"succeeded\", {\n output: value,\n expectAttempt,\n expectFrom: fence?.from ?? task.state,\n ...(fence === undefined ? {} : { expectExecution: fence.execution }),\n phase: \"workflow\",\n });\n } catch (error) {\n if (error instanceof VersionConflictError) continue;\n if (error instanceof InvalidTransitionError && (await read(id)).task.state === \"succeeded\")\n continue;\n throw error;\n }\n }\n }\n return {\n complete,\n completeWorkflow: ({ task, workflow, output, fence }) =>\n complete({ task, output, fence }, workflow),\n waitForMessages: ({ task: { taskId, attempt }, phase }) =>\n setWaiting(taskId, attempt, true, phase),\n resume: ({ task: { taskId, attempt } }) => setWaiting(taskId, attempt, false),\n recover,\n async usage(rootTaskId) {\n const tasks = await recover(rootTaskId);\n let micros = 0;\n let inputTokens = 0;\n let outputTokens = 0;\n for (const task of tasks) {\n micros += Math.round((task.usage?.costUsd ?? task.settledUsd ?? 0) * 1_000_000);\n inputTokens += task.usage?.inputTokens ?? 0;\n outputTokens += task.usage?.outputTokens ?? 0;\n }\n return { costUsd: micros / 1_000_000, inputTokens, outputTokens, taskCount: tasks.length };\n },\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import "../schema/task.mjs";
2
+ import { z } from "zod";
3
+ //#region src/store/work-notifications.d.ts
4
+ /** Validates a stable wakeup that addresses canonical work by root graph. */
5
+ declare const workNotificationSchema: z.ZodObject<{
6
+ rootTaskId: z.ZodType<`task_${string}`, string, z.core.$ZodTypeInternals<`task_${string}`, string>>;
7
+ key: z.ZodString;
8
+ }, z.core.$strict>;
9
+ /** Retry-safe notification telling a consumer to reread one canonical Task graph. */
10
+ type WorkNotification = z.infer<typeof workNotificationSchema>;
11
+ /** Application transport for post-commit work wakeups and delivery-failure reporting. */
12
+ interface WorkNotifications {
13
+ publish(event: WorkNotification): Promise<void>;
14
+ /** The source write already committed. Report transport failure without pretending it rolled back. */
15
+ onError(error: unknown, event: WorkNotification): void;
16
+ }
17
+ //#endregion
18
+ export { WorkNotification, WorkNotifications, workNotificationSchema };
19
+ //# sourceMappingURL=work-notifications.d.mts.map
@@ -0,0 +1,48 @@
1
+ import { taskIdSchema } from "../schema/id.mjs";
2
+ import { z } from "zod";
3
+ import { isDeepStrictEqual } from "node:util";
4
+ //#region src/store/work-notifications.ts
5
+ /** Validates a stable wakeup that addresses canonical work by root graph. */
6
+ const workNotificationSchema = z.strictObject({
7
+ rootTaskId: taskIdSchema.describe("Canonical graph to reconcile; never an execution authorization."),
8
+ key: z.string().min(1).max(256).describe("Stable identity of the committed source change.")
9
+ }).describe("Durable work wakeup. Consumers reread canonical state and tolerate duplicate delivery.");
10
+ /** Creates a best-effort post-commit notifier whose failures never roll back source writes. */
11
+ function createWorkNotifier(options) {
12
+ async function publish(event) {
13
+ if (!options) return;
14
+ try {
15
+ await options.publish(event);
16
+ } catch (error) {
17
+ try {
18
+ options.onError(error, event);
19
+ } catch {}
20
+ }
21
+ }
22
+ function schedulingState(task) {
23
+ return [
24
+ task.state,
25
+ task.attempt,
26
+ task.approval,
27
+ task.waitingForMessages,
28
+ task.workflowPhase,
29
+ task.changeId,
30
+ task.questionTaskId,
31
+ task.answerEventIds
32
+ ];
33
+ }
34
+ return {
35
+ publish,
36
+ async task(task, previous, version) {
37
+ if (previous && isDeepStrictEqual(schedulingState(task), schedulingState(previous))) return;
38
+ await publish({
39
+ rootTaskId: task.rootTaskId,
40
+ key: `task:${task.id}:${version}`
41
+ });
42
+ }
43
+ };
44
+ }
45
+ //#endregion
46
+ export { createWorkNotifier, workNotificationSchema };
47
+
48
+ //# sourceMappingURL=work-notifications.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-notifications.mjs","names":[],"sources":["../../src/store/work-notifications.ts"],"sourcesContent":["import { isDeepStrictEqual } from \"node:util\";\nimport { z } from \"zod\";\nimport { taskIdSchema } from \"../schema/id\";\nimport type { Task } from \"../schema/task\";\n\n/** Validates a stable wakeup that addresses canonical work by root graph. */\nexport const workNotificationSchema = z\n .strictObject({\n rootTaskId: taskIdSchema.describe(\n \"Canonical graph to reconcile; never an execution authorization.\",\n ),\n key: z.string().min(1).max(256).describe(\"Stable identity of the committed source change.\"),\n })\n .describe(\n \"Durable work wakeup. Consumers reread canonical state and tolerate duplicate delivery.\",\n );\n/** Retry-safe notification telling a consumer to reread one canonical Task graph. */\nexport type WorkNotification = z.infer<typeof workNotificationSchema>;\n/** Application transport for post-commit work wakeups and delivery-failure reporting. */\nexport interface WorkNotifications {\n publish(event: WorkNotification): Promise<void>;\n /** The source write already committed. Report transport failure without pretending it rolled back. */\n onError(error: unknown, event: WorkNotification): void;\n}\n\n/** Creates a best-effort post-commit notifier whose failures never roll back source writes. */\nexport function createWorkNotifier(options?: WorkNotifications) {\n async function publish(event: WorkNotification): Promise<void> {\n if (!options) return;\n try {\n await options.publish(event);\n } catch (error) {\n // Reporting must not turn a committed CAS write into an apparent write failure.\n try {\n options.onError(error, event);\n } catch {\n /* Recovery rediscovers canonical work. */\n }\n }\n }\n function schedulingState(task: Task) {\n return [\n task.state,\n task.attempt,\n task.approval,\n task.waitingForMessages,\n task.workflowPhase,\n task.changeId,\n task.questionTaskId,\n task.answerEventIds,\n ];\n }\n return {\n publish,\n async task(task: Task, previous: Task | null, version: number) {\n if (previous && isDeepStrictEqual(schedulingState(task), schedulingState(previous))) return;\n await publish({ rootTaskId: task.rootTaskId, key: `task:${task.id}:${version}` });\n },\n };\n}\n"],"mappings":";;;;;AAMA,MAAa,yBAAyB,EACnC,aAAa;CACZ,YAAY,aAAa,SACvB,iEACF;CACA,KAAK,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,SAAS,iDAAiD;AAC5F,CAAC,CAAC,CACD,SACC,wFACF;;AAWF,SAAgB,mBAAmB,SAA6B;CAC9D,eAAe,QAAQ,OAAwC;EAC7D,IAAI,CAAC,SAAS;EACd,IAAI;GACF,MAAM,QAAQ,QAAQ,KAAK;EAC7B,SAAS,OAAO;GAEd,IAAI;IACF,QAAQ,QAAQ,OAAO,KAAK;GAC9B,QAAQ,CAER;EACF;CACF;CACA,SAAS,gBAAgB,MAAY;EACnC,OAAO;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;EACP;CACF;CACA,OAAO;EACL;EACA,MAAM,KAAK,MAAY,UAAuB,SAAiB;GAC7D,IAAI,YAAY,kBAAkB,gBAAgB,IAAI,GAAG,gBAAgB,QAAQ,CAAC,GAAG;GACrF,MAAM,QAAQ;IAAE,YAAY,KAAK;IAAY,KAAK,QAAQ,KAAK,GAAG,GAAG;GAAU,CAAC;EAClF;CACF;AACF"}
@@ -0,0 +1,79 @@
1
+ import { TaskId } from "./schema/id.mjs";
2
+ import { Repository } from "./schema/repository.mjs";
3
+ import { ExecutionReference, Task } from "./schema/task.mjs";
4
+ import { AgentRouteKey } from "./agent-routes.mjs";
5
+ import { FactoryStores } from "./store/engine.mjs";
6
+ import { DispatchBudget, DispatchRefusalCode } from "./dispatch.mjs";
7
+ //#region src/sweep.d.ts
8
+ /** Graph, receipt, repository, and Task capabilities required by queued-work dispatch. */
9
+ type SweepQueuedStores = Pick<FactoryStores, "graphs" | "receipts" | "repositories" | "tasks">;
10
+ /**
11
+ * Single-repository adapter for an exact agent route. Supplied by the app, which knows its
12
+ * agents' addresses. Returns the provider's execution reference when it has one.
13
+ *
14
+ * @param task - Running Task already admitted by the dispatch gate.
15
+ * @param repository - Exact enabled repository selected from the Task scope.
16
+ * @returns Provider execution reference that dispatch can persist for recovery.
17
+ */
18
+ type TaskLauncher = (task: Task, repository: Repository) => Promise<ExecutionReference>;
19
+ /** Exact-route launchers, budget gate, and pass bounds for queued Task dispatch. */
20
+ interface SweepQueuedOptions {
21
+ /** Single-repository agent adapters keyed by routeKey(binding), e.g. code-change@1. */
22
+ launchers: Readonly<Partial<Record<AgentRouteKey, TaskLauncher>>>;
23
+ /** Reserve-before-execution limits, passed through to every dispatch. */
24
+ budget?: DispatchBudget;
25
+ /** Maximum task launches attempted in one pass; omitted means no limit. */
26
+ maxDispatches?: number;
27
+ /** A dispatcher-wide snapshot avoids another complete task read. */
28
+ tasks?: readonly Task[];
29
+ }
30
+ /** Tasks dispatched, deferred by a gate, or failed by one queued-work pass. */
31
+ interface SweepQueuedResult {
32
+ /** Task IDs whose provider execution reference was durably recorded. */
33
+ readonly dispatched: readonly TaskId[];
34
+ /** Tasks left in the queue because a declared gate may become eligible later. */
35
+ readonly skipped: readonly {
36
+ readonly taskId: TaskId;
37
+ readonly reasonCode: SweepSkipReasonCode;
38
+ readonly reason: string;
39
+ }[];
40
+ /** Tasks whose routing is invalid or whose launch threw. */
41
+ readonly failed: readonly {
42
+ readonly taskId: TaskId;
43
+ readonly reasonCode: SweepFailureReasonCode;
44
+ readonly reason: string;
45
+ }[];
46
+ }
47
+ /** Stable reason a queued Task remained eligible for a later dispatch pass. */
48
+ type SweepSkipReasonCode = DispatchRefusalCode | "workflow_owned" | "awaiting_approval" | "dispatch_limit" | "task_changed";
49
+ /** Stable reason a queued Task could not be routed or launched. */
50
+ type SweepFailureReasonCode = "invalid_repository_scope" | "repository_not_found" | "launcher_not_registered" | "launch_failed";
51
+ /**
52
+ * Runs one bounded pass over queued Tasks and dispatches each eligible exact route.
53
+ *
54
+ * @remarks
55
+ * Candidates are ordered by newest attempt first and then creation time. Route-less work remains
56
+ * queued for its workflow owner; unmet dependencies, approvals, and pass limits appear in
57
+ * `skipped`. Invalid repository scope, missing repositories or launchers, and launch failures
58
+ * appear in `failed`, with unrouteable Tasks transitioned to `failed` when this sweep wins the
59
+ * race. A result entry describes this pass rather than guaranteeing the Task's lifecycle state:
60
+ * an ambiguously accepted launch is reported as `launch_failed` while its Task intentionally stays
61
+ * running for recovery. Callers should surface every failure, reread those Tasks before deciding
62
+ * remediation, and schedule another pass for skipped work.
63
+ *
64
+ * Overlapping passes are safe: {@link dispatchTask} atomically admits one winner before invoking a
65
+ * launcher. A supplied `tasks` snapshot bounds reads and candidate selection for this pass; it can
66
+ * become stale, and corresponding races are returned as `task_changed` rather than hidden.
67
+ * `maxDispatches` counts provider launches started during the pass, including launches that later
68
+ * fail, so `dispatched.length` may be smaller than the limit.
69
+ *
70
+ * @param stores - Graph, receipt, repository, and Task stores used during the pass.
71
+ * @param options - Exact-route launchers plus optional budget, Task snapshot, and dispatch limit.
72
+ * @returns IDs dispatched and structured skipped/failed outcomes for every considered candidate.
73
+ * @throws When `maxDispatches` is not a positive integer or an unexpected persistence error occurs.
74
+ * @see The shipped `docs/recipes/retry-recovery.md` recipe for scheduled recovery.
75
+ */
76
+ declare function sweepQueued(stores: SweepQueuedStores, options: SweepQueuedOptions): Promise<SweepQueuedResult>;
77
+ //#endregion
78
+ export { SweepFailureReasonCode, SweepQueuedOptions, SweepQueuedResult, SweepQueuedStores, SweepSkipReasonCode, TaskLauncher, sweepQueued };
79
+ //# sourceMappingURL=sweep.d.mts.map