@vercel/factory 0.0.14 → 0.0.15

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 (467) hide show
  1. package/README.md +306 -0
  2. package/dist/agent-routes.d.mts +69 -0
  3. package/dist/agent-routes.mjs +64 -0
  4. package/dist/agent-routes.mjs.map +1 -0
  5. package/dist/api-contracts.d.mts +1749 -0
  6. package/dist/api-contracts.mjs +118 -0
  7. package/dist/api-contracts.mjs.map +1 -0
  8. package/dist/api-images.d.mts +30 -0
  9. package/dist/api-images.mjs +28 -0
  10. package/dist/api-images.mjs.map +1 -0
  11. package/dist/api-task-graph.mjs +57 -0
  12. package/dist/api-task-graph.mjs.map +1 -0
  13. package/dist/api.d.mts +68 -216
  14. package/dist/api.mjs +872 -97
  15. package/dist/api.mjs.map +1 -1
  16. package/dist/approval-access.d.mts +39 -0
  17. package/dist/approval-access.mjs +62 -0
  18. package/dist/approval-access.mjs.map +1 -0
  19. package/dist/approval-contracts.d.mts +692 -0
  20. package/dist/approval-contracts.mjs +27 -0
  21. package/dist/approval-contracts.mjs.map +1 -0
  22. package/dist/approval.d.mts +49 -0
  23. package/dist/approval.mjs +39 -0
  24. package/dist/approval.mjs.map +1 -0
  25. package/dist/blob/artifacts.d.mts +37 -0
  26. package/dist/blob/artifacts.mjs +45 -0
  27. package/dist/blob/artifacts.mjs.map +1 -0
  28. package/dist/blob/index.d.mts +41 -6
  29. package/dist/blob/index.mjs +158 -40
  30. package/dist/blob/index.mjs.map +1 -1
  31. package/dist/budget.d.mts +108 -0
  32. package/dist/budget.mjs +141 -0
  33. package/dist/budget.mjs.map +1 -0
  34. package/dist/budgets.d.mts +4 -0
  35. package/dist/budgets.mjs +4 -0
  36. package/dist/build-factory.d.mts +6 -4
  37. package/dist/build-factory.mjs +2 -1
  38. package/dist/build-factory.mjs.map +1 -1
  39. package/dist/change-verification/brief.d.mts +9 -0
  40. package/dist/change-verification/brief.mjs +13 -0
  41. package/dist/change-verification/brief.mjs.map +1 -0
  42. package/dist/change-verification/dispatch.d.mts +24 -0
  43. package/dist/change-verification/dispatch.mjs +45 -0
  44. package/dist/change-verification/dispatch.mjs.map +1 -0
  45. package/dist/change-verification/eve-tool.d.mts +60 -0
  46. package/dist/change-verification/eve-tool.mjs +101 -0
  47. package/dist/change-verification/eve-tool.mjs.map +1 -0
  48. package/dist/changes/eve-record-change.d.mts +56 -0
  49. package/dist/changes/eve-record-change.mjs +97 -0
  50. package/dist/changes/eve-record-change.mjs.map +1 -0
  51. package/dist/changes/presentation.d.mts +14 -0
  52. package/dist/changes.d.mts +23 -0
  53. package/dist/changes.mjs +29 -0
  54. package/dist/changes.mjs.map +1 -0
  55. package/dist/client-events.d.mts +18 -0
  56. package/dist/client-events.mjs +41 -0
  57. package/dist/client-events.mjs.map +1 -0
  58. package/dist/client-stream.d.mts +28 -0
  59. package/dist/client-stream.mjs +204 -0
  60. package/dist/client-stream.mjs.map +1 -0
  61. package/dist/client-transcript.d.mts +41 -0
  62. package/dist/client-transcript.mjs +229 -0
  63. package/dist/client-transcript.mjs.map +1 -0
  64. package/dist/client.d.mts +234 -0
  65. package/dist/client.mjs +258 -0
  66. package/dist/client.mjs.map +1 -0
  67. package/dist/code-review/contracts.d.mts +26 -0
  68. package/dist/code-review/eve-post-review.d.mts +70 -0
  69. package/dist/code-review/eve-post-review.mjs +183 -0
  70. package/dist/code-review/eve-post-review.mjs.map +1 -0
  71. package/dist/code-review/eve-review-comments.d.mts +64 -0
  72. package/dist/code-review/eve-review-comments.mjs +159 -0
  73. package/dist/code-review/eve-review-comments.mjs.map +1 -0
  74. package/dist/code-review/github-contracts.d.mts +10 -0
  75. package/dist/code-review/github-reporter.d.mts +44 -0
  76. package/dist/code-review/github-reporter.mjs +260 -0
  77. package/dist/code-review/github-reporter.mjs.map +1 -0
  78. package/dist/code-review/preparation.d.mts +34 -0
  79. package/dist/code-review/preparation.mjs +23 -0
  80. package/dist/code-review/preparation.mjs.map +1 -0
  81. package/dist/code-review/stall.d.mts +17 -0
  82. package/dist/code-review/stall.mjs +30 -0
  83. package/dist/code-review/stall.mjs.map +1 -0
  84. package/dist/code-review.d.mts +6 -0
  85. package/dist/code-review.mjs +5 -0
  86. package/dist/communication.d.mts +9 -0
  87. package/dist/communication.mjs +9 -0
  88. package/dist/connectors/github.d.mts +26 -0
  89. package/dist/connectors/github.mjs +55 -0
  90. package/dist/connectors/github.mjs.map +1 -0
  91. package/dist/connectors/index.d.mts +35 -3
  92. package/dist/connectors/index.mjs +3 -52
  93. package/dist/connectors/index.mjs.map +1 -1
  94. package/dist/connectors/outbox.d.mts +34 -0
  95. package/dist/connectors/outbox.mjs +50 -0
  96. package/dist/connectors/outbox.mjs.map +1 -0
  97. package/dist/connectors/slack-approval-blocks.mjs +136 -0
  98. package/dist/connectors/slack-approval-blocks.mjs.map +1 -0
  99. package/dist/connectors/slack-approvals.d.mts +29 -0
  100. package/dist/connectors/slack-approvals.mjs +346 -0
  101. package/dist/connectors/slack-approvals.mjs.map +1 -0
  102. package/dist/connectors/slack.d.mts +35 -52
  103. package/dist/connectors/slack.mjs +13 -85
  104. package/dist/connectors/slack.mjs.map +1 -1
  105. package/dist/deepsec/eve-tool.d.mts +110 -0
  106. package/dist/deepsec/eve-tool.mjs +164 -0
  107. package/dist/deepsec/eve-tool.mjs.map +1 -0
  108. package/dist/deepsec/finding.d.mts +84 -0
  109. package/dist/deepsec/finding.mjs +56 -0
  110. package/dist/deepsec/finding.mjs.map +1 -0
  111. package/dist/deepsec.d.mts +3 -0
  112. package/dist/delivery-metrics/metrics.d.mts +93 -0
  113. package/dist/delivery-metrics/metrics.mjs +200 -0
  114. package/dist/delivery-metrics/metrics.mjs.map +1 -0
  115. package/dist/delivery-metrics.d.mts +2 -0
  116. package/dist/delivery-metrics.mjs +2 -0
  117. package/dist/dispatch.d.mts +81 -0
  118. package/dist/dispatch.mjs +140 -0
  119. package/dist/dispatch.mjs.map +1 -0
  120. package/dist/errors.d.mts +15 -0
  121. package/dist/errors.mjs +38 -0
  122. package/dist/errors.mjs.map +1 -0
  123. package/dist/eve/index.d.mts +143 -1271
  124. package/dist/eve/index.mjs +233 -1065
  125. package/dist/eve/index.mjs.map +1 -1
  126. package/dist/eve/invoke.d.mts +144 -0
  127. package/dist/eve/invoke.mjs +241 -0
  128. package/dist/eve/invoke.mjs.map +1 -0
  129. package/dist/eve/session-client.d.mts +68 -0
  130. package/dist/eve/session-client.mjs +131 -0
  131. package/dist/eve/session-client.mjs.map +1 -0
  132. package/dist/eve/task-execution.mjs +18 -0
  133. package/dist/eve/task-execution.mjs.map +1 -0
  134. package/dist/eve/task-session.d.mts +87 -0
  135. package/dist/eve/task-session.mjs +203 -0
  136. package/dist/eve/task-session.mjs.map +1 -0
  137. package/dist/eve/transcript.d.mts +37 -0
  138. package/dist/eve/transcript.mjs +65 -0
  139. package/dist/eve/transcript.mjs.map +1 -0
  140. package/dist/execution-public.d.mts +8 -0
  141. package/dist/execution-public.mjs +7 -0
  142. package/dist/execution.d.mts +75 -0
  143. package/dist/execution.mjs +153 -0
  144. package/dist/execution.mjs.map +1 -0
  145. package/dist/finding-remediation/admission.d.mts +51 -0
  146. package/dist/finding-remediation/admission.mjs +87 -0
  147. package/dist/finding-remediation/admission.mjs.map +1 -0
  148. package/dist/finding-remediation/brief.d.mts +14 -0
  149. package/dist/finding-remediation/brief.mjs +25 -0
  150. package/dist/finding-remediation/brief.mjs.map +1 -0
  151. package/dist/finding-remediation/eve-tool.d.mts +29 -0
  152. package/dist/finding-remediation/eve-tool.mjs +34 -0
  153. package/dist/finding-remediation/eve-tool.mjs.map +1 -0
  154. package/dist/findings/fingerprint.d.mts +14 -0
  155. package/dist/findings/fingerprint.mjs +28 -0
  156. package/dist/findings/fingerprint.mjs.map +1 -0
  157. package/dist/findings.d.mts +6 -0
  158. package/dist/findings.mjs +6 -0
  159. package/dist/github-app.d.mts +54 -0
  160. package/dist/github-app.mjs +121 -0
  161. package/dist/github-app.mjs.map +1 -0
  162. package/dist/github-publication.d.mts +198 -0
  163. package/dist/github-publication.mjs +429 -0
  164. package/dist/github-publication.mjs.map +1 -0
  165. package/dist/github-transfer.d.mts +72 -0
  166. package/dist/github-transfer.mjs +125 -0
  167. package/dist/github-transfer.mjs.map +1 -0
  168. package/dist/github.d.mts +406 -2
  169. package/dist/github.mjs +239 -40
  170. package/dist/github.mjs.map +1 -1
  171. package/dist/image-input.d.mts +51 -0
  172. package/dist/image-input.mjs +63 -0
  173. package/dist/image-input.mjs.map +1 -0
  174. package/dist/index.d.mts +14 -484
  175. package/dist/index.mjs +14 -522
  176. package/dist/intake-contracts.d.mts +56 -0
  177. package/dist/intake-contracts.mjs +33 -0
  178. package/dist/intake-contracts.mjs.map +1 -0
  179. package/dist/integrations/deepsec.d.mts +4 -0
  180. package/dist/integrations/deepsec.mjs +3 -0
  181. package/dist/integrations/github.d.mts +11 -0
  182. package/dist/integrations/github.mjs +9 -0
  183. package/dist/integrations/slack.d.mts +3 -0
  184. package/dist/integrations/slack.mjs +3 -0
  185. package/dist/integrations/vercel.d.mts +3 -0
  186. package/dist/integrations/vercel.mjs +3 -0
  187. package/dist/merge-resolution/contracts.d.mts +17 -0
  188. package/dist/merge-resolution/contracts.mjs +19 -0
  189. package/dist/merge-resolution/contracts.mjs.map +1 -0
  190. package/dist/merge-resolution/eve-tools.d.mts +46 -0
  191. package/dist/merge-resolution/eve-tools.mjs +117 -0
  192. package/dist/merge-resolution/eve-tools.mjs.map +1 -0
  193. package/dist/multi-repository-changes/coordination.d.mts +49 -0
  194. package/dist/multi-repository-changes/coordination.mjs +115 -0
  195. package/dist/multi-repository-changes/coordination.mjs.map +1 -0
  196. package/dist/planning/cancellation.mjs +82 -0
  197. package/dist/planning/cancellation.mjs.map +1 -0
  198. package/dist/planning/configuration.d.mts +23 -0
  199. package/dist/planning/configuration.mjs +56 -0
  200. package/dist/planning/configuration.mjs.map +1 -0
  201. package/dist/planning/contracts.d.mts +136 -0
  202. package/dist/planning/contracts.mjs +42 -0
  203. package/dist/planning/contracts.mjs.map +1 -0
  204. package/dist/planning/dependencies.mjs +44 -0
  205. package/dist/planning/dependencies.mjs.map +1 -0
  206. package/dist/planning/effects.mjs +122 -0
  207. package/dist/planning/effects.mjs.map +1 -0
  208. package/dist/planning/reconcile.mjs +273 -0
  209. package/dist/planning/reconcile.mjs.map +1 -0
  210. package/dist/planning/runtime.d.mts +27 -0
  211. package/dist/planning/runtime.mjs +25 -0
  212. package/dist/planning/runtime.mjs.map +1 -0
  213. package/dist/planning/state.mjs +92 -0
  214. package/dist/planning/state.mjs.map +1 -0
  215. package/dist/planning/turns.mjs +262 -0
  216. package/dist/planning/turns.mjs.map +1 -0
  217. package/dist/planning/validation.mjs +106 -0
  218. package/dist/planning/validation.mjs.map +1 -0
  219. package/dist/postgres/index.d.mts +7 -1
  220. package/dist/postgres/index.mjs +7 -3
  221. package/dist/postgres/index.mjs.map +1 -1
  222. package/dist/presets/software-development/approval.d.mts +14 -0
  223. package/dist/presets/software-development/approval.mjs +21 -0
  224. package/dist/presets/software-development/approval.mjs.map +1 -0
  225. package/dist/presets/software-development/deepsec-brief.d.mts +8 -0
  226. package/dist/presets/software-development/deepsec-brief.mjs +14 -0
  227. package/dist/presets/software-development/deepsec-brief.mjs.map +1 -0
  228. package/dist/presets/software-development/dispatch.d.mts +53 -0
  229. package/dist/presets/software-development/dispatch.mjs +66 -0
  230. package/dist/presets/software-development/dispatch.mjs.map +1 -0
  231. package/dist/presets/software-development/eve-delegation-policy.d.mts +7 -0
  232. package/dist/presets/software-development/eve-delegation-policy.mjs +34 -0
  233. package/dist/presets/software-development/eve-delegation-policy.mjs.map +1 -0
  234. package/dist/presets/software-development/eve.d.mts +18 -0
  235. package/dist/presets/software-development/eve.mjs +19 -0
  236. package/dist/presets/software-development/eve.mjs.map +1 -0
  237. package/dist/presets/software-development/finish-task-policy.d.mts +7 -0
  238. package/dist/presets/software-development/finish-task-policy.mjs +9 -0
  239. package/dist/presets/software-development/finish-task-policy.mjs.map +1 -0
  240. package/dist/presets/software-development/recovery.d.mts +32 -0
  241. package/dist/presets/software-development/recovery.mjs +120 -0
  242. package/dist/presets/software-development/recovery.mjs.map +1 -0
  243. package/dist/presets/software-development/task-communication.d.mts +23 -0
  244. package/dist/presets/software-development/task-communication.mjs +120 -0
  245. package/dist/presets/software-development/task-communication.mjs.map +1 -0
  246. package/dist/presets/software-development.d.mts +9 -0
  247. package/dist/presets/software-development.mjs +9 -0
  248. package/dist/pull-requests/contracts.d.mts +72 -0
  249. package/dist/pull-requests/eve-fetch.d.mts +57 -0
  250. package/dist/pull-requests/eve-fetch.mjs +151 -0
  251. package/dist/pull-requests/eve-fetch.mjs.map +1 -0
  252. package/dist/pull-requests/github-label-manager.d.mts +27 -0
  253. package/dist/pull-requests/github-label-manager.mjs +40 -0
  254. package/dist/pull-requests/github-label-manager.mjs.map +1 -0
  255. package/dist/pull-requests/github-publisher.d.mts +53 -0
  256. package/dist/pull-requests/github-publisher.mjs +345 -0
  257. package/dist/pull-requests/github-publisher.mjs.map +1 -0
  258. package/dist/pull-requests.d.mts +5 -0
  259. package/dist/pull-requests.mjs +4 -0
  260. package/dist/receipts.d.mts +4 -0
  261. package/dist/receipts.mjs +3 -0
  262. package/dist/repositories.d.mts +18 -0
  263. package/dist/repositories.mjs +33 -0
  264. package/dist/repositories.mjs.map +1 -0
  265. package/dist/sandbox/command.d.mts +18 -0
  266. package/dist/sandbox/execution-abort.d.mts +16 -0
  267. package/dist/sandbox/execution-abort.mjs +49 -0
  268. package/dist/sandbox/execution-abort.mjs.map +1 -0
  269. package/dist/sandbox/execution-environment.d.mts +25 -0
  270. package/dist/sandbox/execution-run-ledger.d.mts +115 -0
  271. package/dist/sandbox/execution-run-ledger.mjs +209 -0
  272. package/dist/sandbox/execution-run-ledger.mjs.map +1 -0
  273. package/dist/sandbox/execution.d.mts +54 -0
  274. package/dist/sandbox/execution.mjs +228 -0
  275. package/dist/sandbox/execution.mjs.map +1 -0
  276. package/dist/sandbox/harness-runner.d.mts +79 -0
  277. package/dist/sandbox/harness-runner.mjs +162 -0
  278. package/dist/sandbox/harness-runner.mjs.map +1 -0
  279. package/dist/sandbox/index.d.mts +9 -0
  280. package/dist/sandbox/index.mjs +7 -0
  281. package/dist/sandbox/task-environment.d.mts +50 -0
  282. package/dist/sandbox/task-environment.mjs +140 -0
  283. package/dist/sandbox/task-environment.mjs.map +1 -0
  284. package/dist/sandbox/workspace.d.mts +29 -0
  285. package/dist/sandbox/workspace.mjs +28 -0
  286. package/dist/sandbox/workspace.mjs.map +1 -0
  287. package/dist/schema/agent-route.d.mts +22 -0
  288. package/dist/schema/agent-route.mjs +15 -0
  289. package/dist/schema/agent-route.mjs.map +1 -0
  290. package/dist/schema/answer.d.mts +23 -0
  291. package/dist/schema/answer.mjs +21 -0
  292. package/dist/schema/answer.mjs.map +1 -0
  293. package/dist/schema/budget.d.mts +38 -0
  294. package/dist/schema/budget.mjs +30 -0
  295. package/dist/schema/budget.mjs.map +1 -0
  296. package/dist/schema/catalog.mjs +72 -0
  297. package/dist/schema/catalog.mjs.map +1 -0
  298. package/dist/schema/change.d.mts +117 -0
  299. package/dist/schema/change.mjs +68 -0
  300. package/dist/schema/change.mjs.map +1 -0
  301. package/dist/schema/common.d.mts +33 -0
  302. package/dist/{id-BLIkCVue.mjs → schema/common.mjs} +7 -16
  303. package/dist/schema/common.mjs.map +1 -0
  304. package/dist/schema/communication.d.mts +52 -0
  305. package/dist/{communication-Kd9nU5RP.mjs → schema/communication.mjs} +8 -3
  306. package/dist/schema/communication.mjs.map +1 -0
  307. package/dist/schema/execution.d.mts +101 -0
  308. package/dist/schema/execution.mjs +86 -0
  309. package/dist/schema/execution.mjs.map +1 -0
  310. package/dist/schema/factory-config.d.mts +95 -0
  311. package/dist/schema/factory-config.mjs +60 -0
  312. package/dist/schema/factory-config.mjs.map +1 -0
  313. package/dist/schema/finding.d.mts +125 -0
  314. package/dist/schema/finding.mjs +67 -0
  315. package/dist/schema/finding.mjs.map +1 -0
  316. package/dist/schema/id.d.mts +43 -0
  317. package/dist/schema/id.mjs +32 -0
  318. package/dist/schema/id.mjs.map +1 -0
  319. package/dist/schema/outbox.d.mts +240 -0
  320. package/dist/schema/outbox.mjs +53 -0
  321. package/dist/schema/outbox.mjs.map +1 -0
  322. package/dist/schema/question-route.mjs +16 -0
  323. package/dist/schema/question-route.mjs.map +1 -0
  324. package/dist/schema/receipt.d.mts +81 -0
  325. package/dist/schema/receipt.mjs +94 -0
  326. package/dist/schema/receipt.mjs.map +1 -0
  327. package/dist/schema/repository.d.mts +26 -0
  328. package/dist/schema/repository.mjs +25 -0
  329. package/dist/schema/repository.mjs.map +1 -0
  330. package/dist/schema/session.d.mts +135 -0
  331. package/dist/schema/session.mjs +53 -0
  332. package/dist/schema/session.mjs.map +1 -0
  333. package/dist/schema/signal.d.mts +105 -0
  334. package/dist/schema/signal.mjs +81 -0
  335. package/dist/schema/signal.mjs.map +1 -0
  336. package/dist/schema/stored-session.mjs +10 -0
  337. package/dist/schema/stored-session.mjs.map +1 -0
  338. package/dist/schema/stored-task.mjs +20 -0
  339. package/dist/schema/stored-task.mjs.map +1 -0
  340. package/dist/schema/task-effect.d.mts +39 -0
  341. package/dist/schema/task-effect.mjs +29 -0
  342. package/dist/schema/task-effect.mjs.map +1 -0
  343. package/dist/schema/task-graph.d.mts +3134 -0
  344. package/dist/schema/task-graph.mjs +97 -0
  345. package/dist/schema/task-graph.mjs.map +1 -0
  346. package/dist/schema/task-message.d.mts +254 -0
  347. package/dist/schema/task-message.mjs +189 -0
  348. package/dist/schema/task-message.mjs.map +1 -0
  349. package/dist/schema/task.d.mts +272 -0
  350. package/dist/schema/task.mjs +199 -0
  351. package/dist/schema/task.mjs.map +1 -0
  352. package/dist/schema/transcript.d.mts +170 -0
  353. package/dist/schema/transcript.mjs +86 -0
  354. package/dist/schema/transcript.mjs.map +1 -0
  355. package/dist/schema/transitions.d.mts +50 -0
  356. package/dist/schema/transitions.mjs +303 -0
  357. package/dist/schema/transitions.mjs.map +1 -0
  358. package/dist/schema/work.d.mts +101 -0
  359. package/dist/schema/work.mjs +102 -0
  360. package/dist/schema/work.mjs.map +1 -0
  361. package/dist/signal-triage.d.mts +20 -0
  362. package/dist/signal-triage.mjs +85 -0
  363. package/dist/signal-triage.mjs.map +1 -0
  364. package/dist/signals.d.mts +19 -0
  365. package/dist/signals.mjs +19 -0
  366. package/dist/signals.mjs.map +1 -0
  367. package/dist/stall.d.mts +38 -0
  368. package/dist/stall.mjs +79 -0
  369. package/dist/stall.mjs.map +1 -0
  370. package/dist/storage.d.mts +4 -0
  371. package/dist/storage.mjs +4 -0
  372. package/dist/store/driver.d.mts +65 -0
  373. package/dist/store/driver.mjs +42 -0
  374. package/dist/store/driver.mjs.map +1 -0
  375. package/dist/store/engine.d.mts +485 -0
  376. package/dist/store/engine.mjs +2175 -0
  377. package/dist/store/engine.mjs.map +1 -0
  378. package/dist/store/memory.d.mts +7 -0
  379. package/dist/store/memory.mjs +52 -0
  380. package/dist/store/memory.mjs.map +1 -0
  381. package/dist/store/task-effects.d.mts +38 -0
  382. package/dist/store/task-effects.mjs +118 -0
  383. package/dist/store/task-effects.mjs.map +1 -0
  384. package/dist/store/task-graphs.d.mts +60 -0
  385. package/dist/store/task-graphs.mjs +212 -0
  386. package/dist/store/task-graphs.mjs.map +1 -0
  387. package/dist/store/task-messages.d.mts +136 -0
  388. package/dist/store/task-messages.mjs +475 -0
  389. package/dist/store/task-messages.mjs.map +1 -0
  390. package/dist/store/task-work.d.mts +65 -0
  391. package/dist/store/task-work.mjs +134 -0
  392. package/dist/store/task-work.mjs.map +1 -0
  393. package/dist/store/work-notifications.d.mts +19 -0
  394. package/dist/store/work-notifications.mjs +48 -0
  395. package/dist/store/work-notifications.mjs.map +1 -0
  396. package/dist/sweep.d.mts +57 -0
  397. package/dist/sweep.mjs +143 -0
  398. package/dist/sweep.mjs.map +1 -0
  399. package/dist/task-communication.d.mts +35 -0
  400. package/dist/task-communication.mjs +47 -0
  401. package/dist/task-communication.mjs.map +1 -0
  402. package/dist/task-graph-view.d.mts +264 -0
  403. package/dist/task-graph-view.mjs +17 -0
  404. package/dist/task-graph-view.mjs.map +1 -0
  405. package/dist/task-message-processing.d.mts +60 -0
  406. package/dist/task-message-processing.mjs +200 -0
  407. package/dist/task-message-processing.mjs.map +1 -0
  408. package/dist/task-protocols.d.mts +80 -0
  409. package/dist/task-protocols.mjs +47 -0
  410. package/dist/task-protocols.mjs.map +1 -0
  411. package/dist/tasks.d.mts +17 -0
  412. package/dist/tasks.mjs +17 -0
  413. package/dist/vercel-git.d.mts +21 -0
  414. package/dist/vercel-git.mjs +112 -0
  415. package/dist/vercel-git.mjs.map +1 -0
  416. package/dist/vercel.d.mts +33 -2
  417. package/dist/vercel.mjs +48 -3
  418. package/dist/vercel.mjs.map +1 -1
  419. package/dist/work-triage/eve-tool.d.mts +29 -0
  420. package/dist/work-triage/eve-tool.mjs +32 -0
  421. package/dist/work-triage/eve-tool.mjs.map +1 -0
  422. package/dist/work-triage/find-existing-work.d.mts +32 -0
  423. package/dist/work-triage/find-existing-work.mjs +31 -0
  424. package/dist/work-triage/find-existing-work.mjs.map +1 -0
  425. package/dist/work-triage/github.d.mts +15 -0
  426. package/dist/work-triage/github.mjs +14 -0
  427. package/dist/work-triage/github.mjs.map +1 -0
  428. package/dist/work-triage.d.mts +3 -0
  429. package/dist/work-triage.mjs +3 -0
  430. package/dist/workflows.d.mts +48 -0
  431. package/dist/workflows.mjs +86 -0
  432. package/dist/workflows.mjs.map +1 -0
  433. package/dist/workspace-diff-assembly.d.mts +33 -0
  434. package/dist/workspace-diff-assembly.mjs +95 -0
  435. package/dist/workspace-diff-assembly.mjs.map +1 -0
  436. package/dist/workspace-diff.d.mts +90 -0
  437. package/dist/workspace-diff.mjs +61 -0
  438. package/dist/workspace-diff.mjs.map +1 -0
  439. package/dist/workspace-snapshot.d.mts +26 -0
  440. package/dist/workspace-snapshot.mjs +80 -0
  441. package/dist/workspace-snapshot.mjs.map +1 -0
  442. package/package.json +129 -44
  443. package/dist/approval-JX2Px9IC.mjs +0 -132
  444. package/dist/approval-JX2Px9IC.mjs.map +0 -1
  445. package/dist/budget-DzSiIA4t.mjs +0 -42
  446. package/dist/budget-DzSiIA4t.mjs.map +0 -1
  447. package/dist/change-D2U6v7Ek.mjs +0 -554
  448. package/dist/change-D2U6v7Ek.mjs.map +0 -1
  449. package/dist/communication-Kd9nU5RP.mjs.map +0 -1
  450. package/dist/coordination-Cq08hb1l.mjs +0 -76
  451. package/dist/coordination-Cq08hb1l.mjs.map +0 -1
  452. package/dist/dispatch-BaZS3PT8.d.mts +0 -76
  453. package/dist/driver-BC0Mt5KG.d.mts +0 -34
  454. package/dist/driver-Bbd25rNM.mjs +0 -23
  455. package/dist/driver-Bbd25rNM.mjs.map +0 -1
  456. package/dist/engine-DFHU2Pe-.d.mts +0 -781
  457. package/dist/engine-WaUM2cGA.mjs +0 -1068
  458. package/dist/engine-WaUM2cGA.mjs.map +0 -1
  459. package/dist/factory-config-BoRXOw43.mjs +0 -50
  460. package/dist/factory-config-BoRXOw43.mjs.map +0 -1
  461. package/dist/factory-config-D2yU3G0c.d.mts +0 -58
  462. package/dist/github-C5HNBN6p.d.mts +0 -279
  463. package/dist/id-BLIkCVue.mjs.map +0 -1
  464. package/dist/index-Bw6hggoH.d.mts +0 -40
  465. package/dist/index.mjs.map +0 -1
  466. package/dist/task-CcOyOJ3k.mjs +0 -154
  467. package/dist/task-CcOyOJ3k.mjs.map +0 -1
@@ -0,0 +1,475 @@
1
+ import { taskIdSchema } from "../schema/id.mjs";
2
+ import "../schema/common.mjs";
3
+ import { taskAttemptRefSchema } from "../schema/execution.mjs";
4
+ import { RecordExistsError, VersionConflictError } from "./driver.mjs";
5
+ import { sendTaskMessageInputSchema, taskInboxSchema, taskMessageClaimSchema, taskMessageDiscardSchema, taskMessageIdSchema, taskMessagePrincipalSchema, taskMessageProcessingSchema, taskMessageReservationSchema, taskMessageSchema } from "../schema/task-message.mjs";
6
+ import { createHash } from "node:crypto";
7
+ import { z } from "zod";
8
+ import { isDeepStrictEqual } from "node:util";
9
+ //#region src/store/task-messages.ts
10
+ /** Base error for Task message admission, authorization, and processing failures. */
11
+ var TaskMessageError = class extends Error {};
12
+ /** Error raised when an idempotency key is reused with different message intent. */
13
+ var TaskMessageConflictError = class extends TaskMessageError {};
14
+ /** Error raised when a configured Task message policy does not grant an operation. */
15
+ var TaskMessageAuthorizationError = class extends TaskMessageError {};
16
+ /** Error raised when a Task inbox claim is expired, replaced, or otherwise invalid. */
17
+ var TaskMessageLeaseError = class extends TaskMessageError {};
18
+ /** Error raised when an inbox head belongs to a stale or cancelled source attempt. */
19
+ var TaskMessageSourceFenceError = class extends TaskMessageError {
20
+ messageId;
21
+ source;
22
+ currentAttempt;
23
+ sourceState;
24
+ constructor(messageId, source, currentAttempt, sourceState) {
25
+ super(`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.`);
26
+ this.messageId = messageId;
27
+ this.source = source;
28
+ this.currentAttempt = currentAttempt;
29
+ this.sourceState = sourceState;
30
+ this.name = "TaskMessageSourceFenceError";
31
+ }
32
+ };
33
+ /**
34
+ * Authorizes recipient-local operations and direct parent-child sends for a trusted
35
+ * Task-bound principal while denying result delivery and discard.
36
+ */
37
+ const taskBoundMessagePolicy = ({ principal, action, fromTask, toTask }) => {
38
+ if (action === "discard" || action === "send_result") return false;
39
+ if (action !== "send") return principal.taskId === toTask.id;
40
+ if (!fromTask || !principal.taskId) return false;
41
+ return principal.taskId === fromTask.id && (fromTask.parentTaskId === toTask.id || toTask.parentTaskId === fromTask.id);
42
+ };
43
+ const claimOptionsSchema = z.strictObject({
44
+ leaseMs: z.number().int().min(1).max(3e5).describe("Processing lease duration, at most five minutes."),
45
+ recoverCompleted: z.boolean().default(false).describe("Trusted recovery of an exact existing decision on a succeeded/failed recipient at the same attempt; not permission for new effects or cancelled Tasks.")
46
+ });
47
+ const acknowledgmentSchema = z.strictObject({ effectsCommitted: z.literal(true).describe("Effects committed before this acknowledgment.") });
48
+ const hash = (parts) => createHash("sha256").update(JSON.stringify(parts)).digest("hex");
49
+ const messageIdFor = (source, operation) => taskMessageIdSchema.parse(`msg_${hash([source, operation])}`);
50
+ const messageContent = ({ createdAt: _createdAt, ...content }) => content;
51
+ const retryable = (error) => error instanceof VersionConflictError || error instanceof RecordExistsError;
52
+ /** Creates the trusted, CAS-backed Task message and recipient-inbox store. */
53
+ function createTaskMessageStore(options) {
54
+ const { driver, now, getTask, protocols, authorize } = options;
55
+ if (typeof authorize !== "function") throw new TaskMessageAuthorizationError("Task messages require an explicit authorize callback; no access is granted by default");
56
+ async function task(id) {
57
+ const value = await getTask(taskIdSchema.parse(id));
58
+ if (!value || value.id !== id) throw new TaskMessageError(`Missing Task ${id}`);
59
+ taskIdSchema.parse(value.rootTaskId);
60
+ return value;
61
+ }
62
+ async function scope(principal, action, toTaskId, fromTaskId) {
63
+ const toTask = await task(toTaskId);
64
+ const fromTask = fromTaskId === void 0 ? void 0 : await task(fromTaskId);
65
+ if (fromTask && fromTask.rootTaskId !== toTask.rootTaskId) throw new TaskMessageAuthorizationError("Cross-root Task messages are not permitted");
66
+ if ((action === "send" || action === "send_result") && principal.taskId !== void 0 && principal.taskId !== fromTaskId) throw new TaskMessageAuthorizationError("Task-bound sender must equal fromTaskId");
67
+ if (await authorize(structuredClone({
68
+ principal,
69
+ action,
70
+ fromTask,
71
+ toTask
72
+ })) !== true) throw new TaskMessageAuthorizationError(`Task message ${action} denied for ${principal.id}`);
73
+ return {
74
+ fromTask,
75
+ toTask
76
+ };
77
+ }
78
+ function matchingAttempt(value, expected) {
79
+ if (value.attempt !== expected) throw new TaskMessageError(`Task ${value.id} requires current attempt ${value.attempt}; received ${expected}`);
80
+ }
81
+ function activeAttempt(value, expected) {
82
+ if (value.attempt !== expected || ![
83
+ "queued",
84
+ "running",
85
+ "needs_human"
86
+ ].includes(value.state)) throw new TaskMessageError(`Task ${value.id} requires current attempt ${value.attempt} and queued, running, or needs_human state`);
87
+ }
88
+ function resultAttempt(value, expected) {
89
+ matchingAttempt(value, expected);
90
+ if (![
91
+ "succeeded",
92
+ "failed",
93
+ "cancelled"
94
+ ].includes(value.state)) throw new TaskMessageError(`Task ${value.id} requires a persisted succeeded, failed, or cancelled outcome for result delivery`);
95
+ }
96
+ function claimableAttempt(value, expected, recoverCompleted) {
97
+ if (recoverCompleted && (value.state === "succeeded" || value.state === "failed")) matchingAttempt(value, expected);
98
+ else activeAttempt(value, expected);
99
+ }
100
+ function parseMessage(value) {
101
+ const { causationId, delivery, ...message } = taskMessageSchema.parse(value);
102
+ if (message.id !== messageIdFor(message.fromTaskId, message.operationId)) throw new TaskMessageConflictError("Stored message ID does not match its source and operation");
103
+ return {
104
+ ...message,
105
+ ...causationId === void 0 ? {} : { causationId },
106
+ ...delivery === void 0 ? {} : { delivery },
107
+ payload: protocols.validateStored(message.type, message.payload)
108
+ };
109
+ }
110
+ function correlateMessage(message, type) {
111
+ if (message.type.id !== type.id || message.type.version !== type.version) throw new TaskMessageConflictError("Message protocol differs from its send intent");
112
+ const payload = protocols.validateStored(type, message.payload);
113
+ return structuredClone({
114
+ ...message,
115
+ payload
116
+ });
117
+ }
118
+ async function deliveredMessage(intent) {
119
+ const stored = await driver.get("taskMessages", intent.id);
120
+ if (!stored) return null;
121
+ const delivered = parseMessage(stored.value);
122
+ if (!isDeepStrictEqual(messageContent(delivered), messageContent(intent))) throw new TaskMessageConflictError(`Operation ${intent.operationId} was reused with different content or attempt`);
123
+ return delivered;
124
+ }
125
+ async function immutable(collection, id, value, parse) {
126
+ const validated = parse(value);
127
+ try {
128
+ await driver.insert({
129
+ collection,
130
+ id,
131
+ value: validated
132
+ });
133
+ } catch (error) {
134
+ if (!(error instanceof RecordExistsError)) throw error;
135
+ const stored = await driver.get(collection, id);
136
+ if (!stored || !isDeepStrictEqual(parse(stored.value), validated)) throw new TaskMessageConflictError(`Immutable record ${id} has different content`);
137
+ }
138
+ return validated;
139
+ }
140
+ async function inbox(toTaskId) {
141
+ const stored = await driver.get("taskInboxes", toTaskId);
142
+ const value = stored ? taskInboxSchema.parse(stored.value) : taskInboxSchema.parse({
143
+ schemaVersion: 1,
144
+ toTaskId,
145
+ generation: 0,
146
+ pending: []
147
+ });
148
+ if (value.toTaskId !== toTaskId) throw new TaskMessageError("Stored inbox recipient mismatch");
149
+ value.pending = value.pending.map(parseMessage);
150
+ return {
151
+ value,
152
+ version: stored?.version
153
+ };
154
+ }
155
+ async function saveInbox(value, version) {
156
+ const validated = taskInboxSchema.parse(value);
157
+ try {
158
+ if (version === void 0) await driver.insert({
159
+ collection: "taskInboxes",
160
+ id: value.toTaskId,
161
+ value: validated
162
+ });
163
+ else await driver.update({
164
+ collection: "taskInboxes",
165
+ id: value.toTaskId,
166
+ value: validated,
167
+ expectedVersion: version
168
+ });
169
+ return true;
170
+ } catch (error) {
171
+ if (retryable(error)) return false;
172
+ throw error;
173
+ }
174
+ }
175
+ async function repair(principal, toTaskId, action, targetId) {
176
+ for (;;) {
177
+ await scope(principal, action, toTaskId);
178
+ const current = await inbox(toTaskId);
179
+ for (const message of current.value.pending) {
180
+ if (targetId !== void 0 && message.id !== targetId) continue;
181
+ await immutable("taskMessages", message.id, message, parseMessage);
182
+ }
183
+ const { completion, rejection } = current.value;
184
+ const resolved = completion ?? rejection;
185
+ if (!resolved || targetId !== void 0 && resolved.messageId !== targetId) return current;
186
+ if (completion) await immutable("taskMessageProcessing", completion.messageId, completion, (value) => taskMessageProcessingSchema.parse(value));
187
+ if (rejection) await immutable("taskMessageDiscards", rejection.messageId, rejection, (value) => taskMessageDiscardSchema.parse(value));
188
+ if (await saveInbox({
189
+ ...current.value,
190
+ pending: current.value.pending.filter((message) => message.id !== resolved.messageId),
191
+ lease: void 0,
192
+ completion: void 0,
193
+ rejection: void 0
194
+ }, current.version)) continue;
195
+ }
196
+ }
197
+ async function reserve(message, expectAttempt) {
198
+ const key = `reservation_${message.id}`;
199
+ const reservation = taskMessageReservationSchema.parse({
200
+ schemaVersion: 1,
201
+ message,
202
+ expectAttempt
203
+ });
204
+ try {
205
+ await driver.insert({
206
+ collection: "taskMessageProcessing",
207
+ id: key,
208
+ value: reservation
209
+ });
210
+ return message;
211
+ } catch (error) {
212
+ if (!(error instanceof RecordExistsError)) throw error;
213
+ const stored = await driver.get("taskMessageProcessing", key);
214
+ if (!stored) throw new TaskMessageConflictError(`Missing operation reservation ${message.id}`);
215
+ const existing = taskMessageReservationSchema.parse(stored.value);
216
+ const original = parseMessage(existing.message);
217
+ if (existing.expectAttempt !== expectAttempt || !isDeepStrictEqual(messageContent(original), messageContent(message))) throw new TaskMessageConflictError(`Operation ${message.operationId} was reused with different content or attempt`);
218
+ return original;
219
+ }
220
+ }
221
+ async function readMessage(principal, toTaskId, messageId, action) {
222
+ taskMessageIdSchema.parse(messageId);
223
+ await scope(principal, action, toTaskId);
224
+ await repair(principal, toTaskId, action, messageId);
225
+ const stored = await driver.get("taskMessages", messageId);
226
+ if (!stored) return null;
227
+ const message = parseMessage(stored.value);
228
+ if (message.id !== messageId || message.toTaskId !== toTaskId) throw new TaskMessageAuthorizationError("Message does not belong to this recipient");
229
+ await scope(principal, action, toTaskId, message.fromTaskId);
230
+ return message;
231
+ }
232
+ async function processingRecord(messageId) {
233
+ const stored = await driver.get("taskMessageProcessing", messageId);
234
+ if (!stored) return null;
235
+ const record = taskMessageProcessingSchema.parse(stored.value);
236
+ if (record.messageId !== messageId) throw new TaskMessageError("Processing record identity mismatch");
237
+ return record;
238
+ }
239
+ async function discardRecord(messageId) {
240
+ const stored = await driver.get("taskMessageDiscards", messageId);
241
+ if (!stored) return null;
242
+ const record = taskMessageDiscardSchema.parse(stored.value);
243
+ if (record.messageId !== messageId) throw new TaskMessageError("Discard record identity mismatch");
244
+ return record;
245
+ }
246
+ async function requireLiveClaim(principal, claim, current) {
247
+ if (principal.id !== claim.principalId) throw new TaskMessageAuthorizationError("Only the claiming principal may validate this lease");
248
+ matchingAttempt(await task(claim.toTaskId), claim.attempt);
249
+ const time = now();
250
+ if (current.completion || current.rejection || current.generation !== claim.generation || !isDeepStrictEqual(current.lease, claim) || Date.parse(claim.expiresAt) <= time.getTime()) throw new TaskMessageLeaseError("Lease expired, resolved, or was replaced; claim again before processing");
251
+ return time;
252
+ }
253
+ function requireClaim(record, claim) {
254
+ const { schemaVersion: _schemaVersion, completedAt: _completedAt, effectsCommitted: _effectsCommitted, ...accepted } = record;
255
+ if (!isDeepStrictEqual(accepted, claim)) throw new TaskMessageLeaseError("Processing acknowledgment belongs to a different lease generation");
256
+ return record;
257
+ }
258
+ async function send(context, input, delivery) {
259
+ const principal = taskMessagePrincipalSchema.parse(context);
260
+ const parsed = sendTaskMessageInputSchema.parse(input);
261
+ const payload = protocols.validate(input.type, parsed.payload);
262
+ const { expectAttempt } = parsed;
263
+ const action = delivery === "result" ? "send_result" : "send";
264
+ await scope(principal, action, parsed.toTaskId, parsed.fromTaskId);
265
+ const intent = correlateMessage(parseMessage({
266
+ ...parsed,
267
+ payload,
268
+ delivery,
269
+ schemaVersion: 1,
270
+ id: messageIdFor(parsed.fromTaskId, parsed.operationId),
271
+ createdAt: now().toISOString()
272
+ }), input.type);
273
+ const delivered = await deliveredMessage(intent);
274
+ if (delivery === "result") resultAttempt(await task(parsed.fromTaskId), expectAttempt);
275
+ if (delivered) return correlateMessage(delivered, input.type);
276
+ if (delivery !== "result") activeAttempt(await task(parsed.fromTaskId), expectAttempt);
277
+ const recipient = await task(parsed.toTaskId);
278
+ activeAttempt(recipient, recipient.attempt);
279
+ if (parsed.causationId) {
280
+ const stored = await driver.get("taskMessages", parsed.causationId);
281
+ if (!stored) throw new TaskMessageError("Causation message must already be durably delivered");
282
+ const cause = parseMessage(stored.value);
283
+ await scope(principal, "read", cause.toTaskId, cause.fromTaskId);
284
+ if ((await task(cause.toTaskId)).rootTaskId !== recipient.rootTaskId) throw new TaskMessageAuthorizationError("Causation must stay within the Task root");
285
+ }
286
+ const message = correlateMessage(await reserve(intent, expectAttempt), input.type);
287
+ for (;;) {
288
+ await scope(principal, action, message.toTaskId, message.fromTaskId);
289
+ const current = await inbox(message.toTaskId);
290
+ const delivered = await deliveredMessage(message);
291
+ if (delivery === "result") resultAttempt(await task(message.fromTaskId), expectAttempt);
292
+ if (delivered) return correlateMessage(delivered, input.type);
293
+ if (delivery !== "result") activeAttempt(await task(message.fromTaskId), expectAttempt);
294
+ const recipient = await task(message.toTaskId);
295
+ activeAttempt(recipient, recipient.attempt);
296
+ const pending = current.value.pending.find((entry) => entry.id === message.id);
297
+ if (pending) {
298
+ if (!isDeepStrictEqual(pending, message)) throw new TaskMessageConflictError("Inbox message differs from reserved intent");
299
+ } else {
300
+ if (current.value.pending.length >= 256) throw new TaskMessageError(`Recipient inbox is full; maximum 256 pending messages`);
301
+ if (!await saveInbox({
302
+ ...current.value,
303
+ pending: [...current.value.pending, message]
304
+ }, current.version)) continue;
305
+ }
306
+ return correlateMessage(await immutable("taskMessages", message.id, message, parseMessage), input.type);
307
+ }
308
+ }
309
+ async function sendAndNotify(principal, input, delivery) {
310
+ const message = await send(principal, input, delivery);
311
+ if (options.notify) {
312
+ const recipient = await task(message.toTaskId);
313
+ await options.notify({
314
+ rootTaskId: recipient.rootTaskId,
315
+ key: `message:${message.id}`
316
+ });
317
+ }
318
+ return message;
319
+ }
320
+ return {
321
+ send: ({ principal, message }) => sendAndNotify(principal, message),
322
+ sendResult: ({ principal, message }) => sendAndNotify(principal, message, "result"),
323
+ async get({ principal: context, toTaskId, messageId }) {
324
+ return readMessage(taskMessagePrincipalSchema.parse(context), toTaskId, messageId, "read");
325
+ },
326
+ async pending({ principal: context, toTaskId }) {
327
+ const principal = taskMessagePrincipalSchema.parse(context);
328
+ const current = await repair(principal, toTaskId, "read");
329
+ for (const message of current.value.pending) await scope(principal, "read", toTaskId, message.fromTaskId);
330
+ return current.value.pending;
331
+ },
332
+ async claim({ principal: context, task: inputTask, ...input }) {
333
+ const principal = taskMessagePrincipalSchema.parse(context);
334
+ const { taskId: toTaskId, attempt } = taskAttemptRefSchema.parse(inputTask);
335
+ const { leaseMs, recoverCompleted } = claimOptionsSchema.parse(input);
336
+ for (;;) {
337
+ const current = await repair(principal, toTaskId, "claim");
338
+ const message = current.value.pending[0];
339
+ if (message) await scope(principal, "claim", toTaskId, message.fromTaskId);
340
+ const recipient = await task(toTaskId);
341
+ claimableAttempt(recipient, attempt, recoverCompleted);
342
+ if (current.value.lease && current.value.lease.attempt === recipient.attempt && Date.parse(current.value.lease.expiresAt) > now().getTime()) return null;
343
+ if (!message) return null;
344
+ const source = await task(message.fromTaskId);
345
+ if (protocols.sourceFence(message.type) === "attempt" && source.attempt !== message.expectAttempt || source.state === "cancelled" && message.delivery !== "result") throw new TaskMessageSourceFenceError(message.id, {
346
+ taskId: source.id,
347
+ attempt: message.expectAttempt
348
+ }, source.attempt, source.state);
349
+ claimableAttempt(await task(toTaskId), attempt, recoverCompleted);
350
+ const time = now();
351
+ const claim = taskMessageClaimSchema.parse({
352
+ messageId: message.id,
353
+ toTaskId,
354
+ generation: current.value.generation + 1,
355
+ principalId: principal.id,
356
+ attempt,
357
+ expiresAt: new Date(time.getTime() + leaseMs).toISOString()
358
+ });
359
+ if (await saveInbox({
360
+ ...current.value,
361
+ generation: claim.generation,
362
+ lease: claim
363
+ }, current.version)) return {
364
+ claim,
365
+ message
366
+ };
367
+ }
368
+ },
369
+ async complete({ principal: context, claim: input, effectsCommitted }) {
370
+ const principal = taskMessagePrincipalSchema.parse(context);
371
+ const claim = taskMessageClaimSchema.parse(input);
372
+ acknowledgmentSchema.parse({ effectsCommitted });
373
+ if (principal.id !== claim.principalId) throw new TaskMessageAuthorizationError("Only the claiming principal may acknowledge processing");
374
+ const message = await readMessage(principal, claim.toTaskId, claim.messageId, "complete");
375
+ if (!message) throw new TaskMessageLeaseError("Claimed message does not exist");
376
+ for (;;) {
377
+ await scope(principal, "complete", claim.toTaskId, message.fromTaskId);
378
+ const current = await inbox(claim.toTaskId);
379
+ const completed = await processingRecord(claim.messageId);
380
+ if (completed) return requireClaim(completed, claim);
381
+ if (current.value.completion) {
382
+ requireClaim(current.value.completion, claim);
383
+ await repair(principal, claim.toTaskId, "complete", claim.messageId);
384
+ continue;
385
+ }
386
+ const time = await requireLiveClaim(principal, claim, current.value);
387
+ const completion = taskMessageProcessingSchema.parse({
388
+ ...claim,
389
+ schemaVersion: 1,
390
+ effectsCommitted: true,
391
+ completedAt: time.toISOString()
392
+ });
393
+ if (!await saveInbox({
394
+ ...current.value,
395
+ completion
396
+ }, current.version)) continue;
397
+ await repair(principal, claim.toTaskId, "complete", claim.messageId);
398
+ return completion;
399
+ }
400
+ },
401
+ async assertClaim({ principal: context, claim: input }) {
402
+ const principal = taskMessagePrincipalSchema.parse(context);
403
+ const claim = taskMessageClaimSchema.parse(input);
404
+ if (principal.id !== claim.principalId) throw new TaskMessageAuthorizationError("Only the claiming principal may validate this lease");
405
+ await scope(principal, "claim", claim.toTaskId);
406
+ const stored = await driver.get("taskMessages", claim.messageId);
407
+ if (!stored) throw new TaskMessageLeaseError("Claimed message does not exist");
408
+ const message = parseMessage(stored.value);
409
+ if (message.id !== claim.messageId || message.toTaskId !== claim.toTaskId) throw new TaskMessageAuthorizationError("Claim does not belong to this recipient");
410
+ await scope(principal, "claim", claim.toTaskId, message.fromTaskId);
411
+ await scope(principal, "complete", claim.toTaskId, message.fromTaskId);
412
+ const completed = await processingRecord(claim.messageId);
413
+ if (completed) {
414
+ requireClaim(completed, claim);
415
+ throw new TaskMessageLeaseError("Message processing is already complete; the claim is no longer active");
416
+ }
417
+ await requireLiveClaim(principal, claim, (await inbox(claim.toTaskId)).value);
418
+ },
419
+ async discard({ principal: context, toTaskId, messageId, reason: inputReason }) {
420
+ const principal = taskMessagePrincipalSchema.parse(context);
421
+ const reason = taskMessageDiscardSchema.shape.reason.parse(inputReason);
422
+ const message = await readMessage(principal, toTaskId, messageId, "discard");
423
+ if (!message) throw new TaskMessageError("Cannot discard a missing message");
424
+ for (;;) {
425
+ await scope(principal, "discard", toTaskId, message.fromTaskId);
426
+ const current = await repair(principal, toTaskId, "discard", messageId);
427
+ const discarded = await discardRecord(messageId);
428
+ if (discarded) {
429
+ if (discarded.toTaskId !== toTaskId || discarded.reason !== reason || !isDeepStrictEqual(discarded.by, principal)) throw new TaskMessageConflictError("Message already has a different discard decision");
430
+ return;
431
+ }
432
+ if (await processingRecord(messageId)) throw new TaskMessageConflictError("Processed messages cannot be discarded");
433
+ if (current.value.pending[0]?.id !== messageId) throw new TaskMessageError("Only the pending inbox head may be discarded");
434
+ const time = now();
435
+ if (current.value.lease && Date.parse(current.value.lease.expiresAt) > time.getTime()) throw new TaskMessageLeaseError("Cannot discard while the recipient has an unexpired lease, including a prior Task attempt");
436
+ const rejection = taskMessageDiscardSchema.parse({
437
+ schemaVersion: 1,
438
+ messageId,
439
+ toTaskId,
440
+ reason,
441
+ by: principal,
442
+ discardedAt: time.toISOString()
443
+ });
444
+ if (!await saveInbox({
445
+ ...current.value,
446
+ lease: void 0,
447
+ rejection
448
+ }, current.version)) continue;
449
+ await repair(principal, toTaskId, "discard", messageId);
450
+ return;
451
+ }
452
+ },
453
+ async discarded({ principal: context, toTaskId, messageId }) {
454
+ if (!await readMessage(taskMessagePrincipalSchema.parse(context), toTaskId, messageId, "read")) return null;
455
+ const record = await discardRecord(messageId);
456
+ if (record && record.toTaskId !== toTaskId) throw new TaskMessageError("Discard record recipient mismatch");
457
+ return record;
458
+ },
459
+ async processing({ principal: context, toTaskId, messageId }) {
460
+ if (!await readMessage(taskMessagePrincipalSchema.parse(context), toTaskId, messageId, "read")) return null;
461
+ const record = await processingRecord(messageId);
462
+ if (record && record.toTaskId !== toTaskId) throw new TaskMessageError("Processing record recipient mismatch");
463
+ return record;
464
+ },
465
+ effectKey({ messageId, operation }) {
466
+ taskMessageIdSchema.parse(messageId);
467
+ z.string().min(1).max(256).parse(operation);
468
+ return `effect_${hash([messageId, operation])}`;
469
+ }
470
+ };
471
+ }
472
+ //#endregion
473
+ export { TaskMessageAuthorizationError, TaskMessageConflictError, TaskMessageError, TaskMessageLeaseError, TaskMessageSourceFenceError, createTaskMessageStore, taskBoundMessagePolicy };
474
+
475
+ //# sourceMappingURL=task-messages.mjs.map
@@ -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,65 @@
1
+ import { TaskId } from "../schema/id.mjs";
2
+ import { JsonValue, WorkflowBinding } from "../schema/work.mjs";
3
+ import { Task } 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
+ /** Complete through the dynamic registry boundary, which validates unknown output at runtime. */
13
+ complete(input: CompleteTaskWorkInput): Promise<Task>;
14
+ /** Complete work while statically checking output against its exact workflow binding. */
15
+ completeWorkflow<Output extends JsonValue>(input: CompleteWorkflowTaskWorkInput<Output>): Promise<Task>;
16
+ waitForMessages(input: WaitForTaskMessagesInput): Promise<Task>;
17
+ resume(input: ResumeTaskWorkInput): Promise<Task>;
18
+ /** Repair admitted creation snapshots by direct graph IDs, never by scanning the bucket. */
19
+ recover(rootTaskId: TaskId): Promise<readonly Task[]>;
20
+ /** Each Task contributes local measured usage once; no parent roll-up is charged again. */
21
+ usage(rootTaskId: TaskId): Promise<TaskWorkUsage>;
22
+ }
23
+ /** Exact Task attempt and candidate workflow output used to complete work. */
24
+ interface CompleteTaskWorkInput {
25
+ task: TaskAttemptRef;
26
+ output: unknown;
27
+ }
28
+ /** Exact Task attempt, workflow contract, and statically checked output used to complete work. */
29
+ interface CompleteWorkflowTaskWorkInput<Output extends JsonValue = JsonValue> {
30
+ task: TaskAttemptRef;
31
+ workflow: WorkflowBinding<JsonValue, Output>;
32
+ output: NoInfer<Output>;
33
+ }
34
+ /** Aggregated measured usage across one canonical Task graph. */
35
+ interface TaskWorkUsage {
36
+ costUsd: number;
37
+ inputTokens: number;
38
+ outputTokens: number;
39
+ taskCount: number;
40
+ }
41
+ /** Exact running Task attempt and optional workflow phase used to await messages. */
42
+ interface WaitForTaskMessagesInput {
43
+ task: TaskAttemptRef;
44
+ phase?: string;
45
+ }
46
+ /** Exact running Task attempt to resume after message delivery. */
47
+ interface ResumeTaskWorkInput {
48
+ task: TaskAttemptRef;
49
+ }
50
+ /** Canonical Task graph, receipt, and Task capabilities used by workflow-facing operations. */
51
+ type TaskWorkStores = Pick<FactoryStores, "graphs" | "receipts" | "tasks">;
52
+ /** Engine-owned dependencies used to construct workflow-facing Task operations. */
53
+ interface CreateTaskWorkStoreOptions {
54
+ driver: StoreDriver;
55
+ now: IsoDateTimeClock;
56
+ stores: () => TaskWorkStores;
57
+ workflows: WorkflowRegistry;
58
+ update(task: Task, version: number): Promise<void>;
59
+ restore(task: Task): Promise<Task>;
60
+ }
61
+ /** Creates workflow-facing Task operations backed by canonical graph and Task stores. */
62
+ declare function createTaskWorkStore(options: CreateTaskWorkStoreOptions): TaskWorkStore;
63
+ //#endregion
64
+ export { CompleteTaskWorkInput, CompleteWorkflowTaskWorkInput, CreateTaskWorkStoreOptions, ResumeTaskWorkInput, TaskWorkStore, TaskWorkStores, TaskWorkUsage, WaitForTaskMessagesInput, createTaskWorkStore };
65
+ //# sourceMappingURL=task-work.d.mts.map