chainlesschain 0.165.2 → 0.165.4

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 (210) hide show
  1. package/README.md +151 -29
  2. package/package.json +2 -2
  3. package/src/assets/web-panel/assets/{AIOps-lS1R0Cza.js → AIOps-C__nnraW.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-BmlgBPsj.js → ActionButton-CsKWHEZ-.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-CNKczv1S.js → Analytics-BhIjfjWO.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-BuZGJARQ.js → AppLayout-BjuXFzWZ.js} +4 -4
  7. package/src/assets/web-panel/assets/{Artifacts-Dm73Sl-O.js → Artifacts-k6whDkZJ.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-BGMW7A5e.js → Audit-C4FBMYRh.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-BQ6M54JR.js → BackgroundAgents-C_vRrSXk.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-DBzGP0bR.js → Backup-CngFZeVp.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-D1mLCoOV.js → BaseInput-B_H9EBRm.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-BUfcN7p8.js → Chat-DLEC5kt7.js} +4 -4
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-xijcWkJe.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-Du0Yg5Pi.js → Checkbox-m3ClR4xh.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-B2RXziHW.js → Codegen-CmLSFrgp.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-DWhekOrR.js → Col-DFGQteHN.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-HQhrkon4.js → Community-EUUVORHE.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-izHNb4uz.js → Compact-2PSg0Yr7.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BDwLy41-.js → Compliance-CcKur7gB.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-DFJhLa7K.js → Cowork-DK_Fezfa.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-DYY9RG7-.js → Cron-Dbw89xl7.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-rr7tJTtv.js → Crosschain-CH66h_Ec.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-D2sfHRLi.js → DID-D1igRb17.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-q_eGdhha.js → Dashboard-DVAsrobk.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-Cufrh2Bz.js → Dropdown-Dl7W8AQs.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-B-kdv10f.js → EmailListRenderer-D5tpaEQC.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-D21XjgfG.js → FamilyGuardDashboard-O_VQf8gq.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-CAwRTLZH.js → Federation-BTVcgS9n.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-vx3daNDF.js → FormItemContext-BRnkJAIz.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-CRWY2wU4.js → GenericCardRenderer-8OWSCkDj.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Q6SwauyD.js → Git-WXLYTQj2.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-BJ1q4IQZ.js → Governance-BezaUhtc.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CSWjROgD.js → Inference-CuRay3Gu.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-fzuQsWuY.js → KnowledgeGraph-DfWLDW1m.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-DVF8Mnns.js → Logs-C55y2pPY.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-hDpWdiBc.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-BQP7LOA4.js → Marketplace-Dk08Uycg.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-BNlJCmNc.js → McpTools-C11fSB5V.js} +4 -4
  39. package/src/assets/web-panel/assets/{Memory-DLLg5WQ4.js → Memory-mr0eZc97.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-CR2skNAF.js → MobileBridge-C0iCSRbb.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-BxVavObl.js → MobileProjects-CY-xMG8Z.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-B17pgqMI.js → Mtc-Bplqc_Wc.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-4UmV5cIL.js → MtcAudit-BlzwsoSM.js} +2 -2
  44. package/src/assets/web-panel/assets/{Multisig-DoMEXEcU.js → Multisig-BBLmTty6.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-h9DMXFX4.js → NLProgramming-DtT1uf1W.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-Cihn-xX8.js → Notes-DcqQAxTK.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-BE6ZGa3R.js → NotificationSettings-cb0kWoZe.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-CnwojoSI.js → OrderTableRenderer-kw9HZQNN.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-B2vpwmjb.js → Organization-DlTlbkUN.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-C4z28R0-.js → Overflow-pp1qs-oY.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-BVlFkwhW.js → P2P-BESLnyYz.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-BXbEdL5B.js → PdhVaultBrowser-B-J1mGuf.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-C28xs4lp.js → Permissions-B36PeT1_.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-Dgl_rBjM.js → PersonalDataHub-CTK2ad-3.js} +3 -3
  55. package/src/assets/web-panel/assets/{Pipeline-3QUIhrKI.js → Pipeline-zJNGXsac.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-8Gh33OZ5.js → Privacy-b9fz0Qf0.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-BNmg4tZi.js → ProjectInit-DjZbZgiB.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-vgMfeCf9.js → ProjectSettings-C-hHJXlD.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-BC9KSDM6.js +1 -0
  60. package/src/assets/web-panel/assets/{Providers-CXoOa8eX.js → Providers-Dz-CAYYU.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-BhfTF0oS.js → QrScannerModal-A0yoQ3-3.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-C746HEAj.js → QuickAsk-DrFgFJNC.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-BSej8Eo0.js → Recommend-KC8hF1g4.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-f3gmnlG3.js → RemoteSession-DGTPIk6u.js} +3 -3
  65. package/src/assets/web-panel/assets/{Reputation-CyvybpkN.js → Reputation-QmbwM7Yk.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-DwV2PeYn.js → Row-BxjJylia.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-11GrzjZy.js → RssFeed-B7Wda1J6.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-BjKXkrAY.js → Search-_plQ_YSA.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-eWiFb9Yk.js → Security-CD2YJZfx.js} +2 -2
  70. package/src/assets/web-panel/assets/{Services-CdCsMAtt.js → Services-qQE7NmwE.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-4Q2UTKQ5.js → Skeleton-DgQqkFf7.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-v4rtYrRj.js → Skills-C4C0oFFt.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-CRhsFvd_.js → Sla-Px2N2B5c.js} +1 -1
  74. package/src/assets/web-panel/assets/SpeechSettings-DN6C3lQd.js +1 -0
  75. package/src/assets/web-panel/assets/{SyncSettings-D16zonl7.js → SyncSettings-jm5aH_m7.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-Xxozz0i_.js → Tasks-DlkJcv67.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-CXJpPtCT.js → Templates-DyrTHUBs.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-XRV0L1ZF.js → Tenant-mC434PtL.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-CYuO1i_w.js → Terminal-o0_s3NgK.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-BXqitWsu.js → TimelineRenderer-DAGlAXOw.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-BvPrDHIy.js → Tokens-BnulS_bs.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-DhCrSTf5.js → Trigger-suQbVXYM.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-DmsuZD6K.js → Trust-DbIJAPo5.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-D_yrts5C.js → UkeySign-CQNpbIHi.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-B01ihPrm.js → VideoEditing-D8aWCERk.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-DpUjKa-N.js → Wallet-CuLpYfZc.js} +2 -2
  87. package/src/assets/web-panel/assets/{WebAuthn-CL07yON6.js → WebAuthn-CsfG8ZMc.js} +2 -2
  88. package/src/assets/web-panel/assets/{WorkflowEditor-CLMflnRr.js → WorkflowEditor-BYsEAZbd.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-DtUqe8h_.js → chat-FT4Um3-I.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-DPKrgVfy.js → colors-CKbS_Wlt.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-BTt2GtOm.js → compact-item-CFJtzuJM.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-D_VeUc1J.js → createContext-B9kSRW6K.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-DJZ0gAMu.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-1kndiylj.js → hasIn-DR-x0Xpi.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-dVc-CXY4.js → index-7jHr_A_k.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DFIZ_1Sf.js → index-B3ZX81mK.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-fk2Rjacw.js → index-B7osrXqy.js} +3 -3
  98. package/src/assets/web-panel/assets/{index-CHG-KcS4.js → index-BGbPnC5x.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-Dbbymxpj.js → index-BI5hP_qy.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-BaZAbw9A.js → index-BK3TiKVq.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CzjkKUmR.js → index-BVPU43b1.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BAXfRKfG.js → index-BW-t9n-q.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-8nz_fmlj.js → index-BfFCQHL3.js} +1 -1
  104. package/src/assets/web-panel/assets/index-Bizb4hkw.js +1 -0
  105. package/src/assets/web-panel/assets/{index-DdkplL9R.js → index-Bt4fS2eL.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DG2MZQ3f.js → index-BwR7yc2h.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DfKBRdSS.js → index-Bzz0C1BZ.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-GsoUQ2M7.js → index-C2JvmYRc.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-l1BETrDb.js → index-CGaXUsIs.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-4bna2_SR.js → index-CJmIQ9XR.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DfGl8CqG.js → index-C_enk9I_.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-D95OFht7.js → index-Cr2FLUsD.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DsJCDUJG.js → index-CvrCCqJt.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-sDoMHTNA.js → index-D4LfPvWA.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-By5n8up9.js → index-DMGmg497.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-ocf06EVQ.js → index-DShSkww-.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Bhudc_Ez.js → index-DTxNy0ZU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CX81qSM4.js → index-DW4BWjTk.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BlDNVgBt.js → index-DWdqx7zI.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CcO04eDn.js → index-Dap9c3eD.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-Dwqmtk65.js → index-DcfxhKXR.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-2eyAXE3d.js → index-DdkIhfi-.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-brCInrzq.js → index-DeSgw-WV.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DJ8vXGOa.js → index-DiNUEpSQ.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BHpBMWCh.js → index-DjEP7WkH.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-m31Ka8hZ.js → index-DtkFqPVA.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CtF7EN49.js → index-KqDaCApw.js} +1 -1
  128. package/src/assets/web-panel/assets/index-OHSl-xCh.js +1 -0
  129. package/src/assets/web-panel/assets/{index-B9KvcS7R.js → index-OSzjTzGM.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CauoBQkH.js → index-QBSeNVO3.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-FzdwcSy2.js → index-WE08gMJP.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DxdTdBix.js → index-r2VI1Ikk.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-BepLZwgB.js → index-tqSEHPRT.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-CvyYJd7z.js → initDefaultProps-Dd7n7VgI.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-DYZkhUdz.js → motion-BwxouRw1.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-slnJRVT1.js → move-DObN0PG9.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-DVc0CKmy.js → mtc-parser-B3nOUQc7.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-BCXAtHCq.js → omit-o9WU2Nbl.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-DBsemz_K.js → pickAttrs-CL_vvfQ_.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-BRtkJ-nv.js → placementArrow-CYrM2tyK.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-Cebq7EZn.js → responsiveObserve-k_06cQ96.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-DT7qvId2.js → slide-CPKG0pxS.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-pQiITLkG.js → statusUtils-BDDEeLTw.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-c-19BVKQ.js → styleChecker-Cmb7RTh7.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-DsS5-0bE.js → useFlexGapSupport-e2IedC4N.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-CxGiMe5n.js → useFs-CE_gxVnm.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-D9btVID5.js → usePersonalDataHub-BkMIIKMz.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-CUYFsFEN.js → vnode-DW886XV1.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-CXmn_35j.js → zoom-Dwo_adaf.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/command-help-index.json +3 -3
  152. package/src/commands/agent.js +105 -35
  153. package/src/commands/artifacts.js +363 -33
  154. package/src/commands/cowork.js +202 -36
  155. package/src/commands/session-budget.js +155 -0
  156. package/src/commands/session-location.js +948 -0
  157. package/src/commands/session.js +72 -46
  158. package/src/data/changelog.json +26 -0
  159. package/src/gateways/ws/artifact-protocol.js +77 -13
  160. package/src/gateways/ws/session-protocol.js +391 -24
  161. package/src/gateways/ws/ws-agent-handler.js +191 -14
  162. package/src/gateways/ws/ws-server.js +14 -3
  163. package/src/gateways/ws/ws-session-gateway.js +101 -5
  164. package/src/harness/jsonl-session-store.js +1210 -0
  165. package/src/lib/agent-team/team-runner.js +43 -13
  166. package/src/lib/artifact-access-ledger.js +461 -0
  167. package/src/lib/artifact-cleanup-ledger.js +861 -0
  168. package/src/lib/artifact-deletion-ledger.js +677 -0
  169. package/src/lib/artifact-store.js +256 -51
  170. package/src/lib/background-agent-keeper-protocol.js +75 -4
  171. package/src/lib/background-agent-launch-barrier.js +74 -0
  172. package/src/lib/background-agent-supervisor.js +149 -5
  173. package/src/lib/background-turn-bootstrap-protocol.js +4 -0
  174. package/src/lib/command-lifecycle-report.js +8 -4
  175. package/src/lib/cowork-adapter.js +9 -5
  176. package/src/lib/cowork-task-runner.js +20 -0
  177. package/src/lib/cowork-workflow.js +178 -20
  178. package/src/lib/direct-model-usage.js +62 -22
  179. package/src/lib/dynamic-workflow-runtime.js +3184 -111
  180. package/src/lib/execution-location-result-apply.js +339 -0
  181. package/src/lib/execution-location-result-artifact.js +271 -0
  182. package/src/lib/execution-location-result-review.js +253 -0
  183. package/src/lib/execution-location-result-store.js +331 -0
  184. package/src/lib/execution-location-result.js +617 -0
  185. package/src/lib/execution-location-target.js +236 -1
  186. package/src/lib/managed-tool-checkpoint.js +47 -4
  187. package/src/lib/process-execution-broker/workspace-transaction.js +3 -0
  188. package/src/lib/session-budget-production-root.js +376 -0
  189. package/src/lib/session-budget-runtime.js +109 -18
  190. package/src/lib/session-budget-usage.js +63 -0
  191. package/src/lib/session-host-snapshot.js +19 -2
  192. package/src/lib/session-resource-budget.js +766 -105
  193. package/src/lib/sub-agent-context.js +69 -22
  194. package/src/lib/web-ui-server.js +12 -1
  195. package/src/lib/with-file-lock.js +175 -26
  196. package/src/repl/agent-repl.js +237 -16
  197. package/src/runtime/agent-core.js +123 -0
  198. package/src/runtime/headless-runner.js +135 -46
  199. package/src/runtime/headless-stream.js +133 -25
  200. package/src/runtime/policies/agent-policy.js +10 -0
  201. package/src/workers/background-agent-keeper.js +112 -19
  202. package/src/workers/background-agent-worker.js +383 -134
  203. package/src/workers/background-turn-bootstrap.js +13 -8
  204. package/src/assets/web-panel/assets/ChatBubbleRenderer-CY5m8ZHg.js +0 -1
  205. package/src/assets/web-panel/assets/MarkdownRenderer-BLif4QSg.js +0 -1
  206. package/src/assets/web-panel/assets/Projects-BhtAVilc.js +0 -1
  207. package/src/assets/web-panel/assets/SpeechSettings-DLjKsDVu.js +0 -1
  208. package/src/assets/web-panel/assets/devWarning-Bj5nUW2v.js +0 -1
  209. package/src/assets/web-panel/assets/index-CPcM-eqo.js +0 -1
  210. package/src/assets/web-panel/assets/index-xeSyVoRe.js +0 -1
@@ -0,0 +1,253 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ normalizeExecutionLocationResultBundle,
4
+ verifyExecutionLocationResultBundle,
5
+ } from "./execution-location-result.js";
6
+ import { normalizeExecutionLocationResultStoreReceipt } from "./execution-location-result-store.js";
7
+ import { canonicalJson } from "./scheduler-kernel/contract.js";
8
+
9
+ export const EXECUTION_LOCATION_RESULT_REVIEW_SCHEMA =
10
+ "cc-execution-location-result-review/v1";
11
+
12
+ const RESULT_SETTLEMENT_RECEIPT_SCHEMA =
13
+ "chainlesschain.session-execution-location-result-collection-receipt/v2";
14
+ const SHA256_RE = /^sha256:[a-f0-9]{64}$/u;
15
+ const HEAD_RE = /^[a-f0-9]{64}$/u;
16
+ const AUTHORITY_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:@+-]{0,255}$/u;
17
+ const RESULT_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u;
18
+
19
+ function digest(domain, value) {
20
+ return `sha256:${createHash("sha256")
21
+ .update(domain, "utf8")
22
+ .update(canonicalJson(value, "executionLocationResultReview"), "utf8")
23
+ .digest("hex")}`;
24
+ }
25
+
26
+ function exactObject(value, fields, label) {
27
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
28
+ throw new TypeError(`${label} must be an object`);
29
+ }
30
+ const actual = Object.keys(value).sort();
31
+ const expected = [...fields].sort();
32
+ if (
33
+ actual.length !== expected.length ||
34
+ actual.some((field, index) => field !== expected[index])
35
+ ) {
36
+ throw new TypeError(`${label} has an invalid schema`);
37
+ }
38
+ return value;
39
+ }
40
+
41
+ function positiveCount(value, label) {
42
+ const count = Number(value);
43
+ if (!Number.isSafeInteger(count) || count < 1) {
44
+ throw new TypeError(`${label} is invalid`);
45
+ }
46
+ return count;
47
+ }
48
+
49
+ function requireDigest(value, label) {
50
+ const result = String(value || "");
51
+ if (!SHA256_RE.test(result)) {
52
+ throw new TypeError(`${label} is invalid`);
53
+ }
54
+ return result;
55
+ }
56
+
57
+ function requireHead(value, label) {
58
+ const result = String(value || "");
59
+ if (!HEAD_RE.test(result)) {
60
+ throw new TypeError(`${label} is invalid`);
61
+ }
62
+ return result;
63
+ }
64
+
65
+ function normalizeSettlement(input) {
66
+ const value = exactObject(
67
+ input,
68
+ [
69
+ "schema",
70
+ "sessionId",
71
+ "settlementId",
72
+ "requestId",
73
+ "requestDigest",
74
+ "resultId",
75
+ "handoffId",
76
+ "sourceHeadHash",
77
+ "sourceEventCount",
78
+ "settlementEventHash",
79
+ "settlementEventCount",
80
+ "targetHeadHash",
81
+ "targetEventCount",
82
+ "bundleDigest",
83
+ "verificationDigest",
84
+ "collectionDigest",
85
+ "storage",
86
+ "totalBytes",
87
+ "applied",
88
+ "receiptDigest",
89
+ ],
90
+ "execution-location result settlement receipt",
91
+ );
92
+ const sessionId = String(value.sessionId || "");
93
+ const requestId = String(value.requestId || "");
94
+ const resultId = String(value.resultId || "");
95
+ const sourceEventCount = positiveCount(
96
+ value.sourceEventCount,
97
+ "source event count",
98
+ );
99
+ const settlementEventCount = positiveCount(
100
+ value.settlementEventCount,
101
+ "settlement event count",
102
+ );
103
+ const targetEventCount = positiveCount(
104
+ value.targetEventCount,
105
+ "target event count",
106
+ );
107
+ const totalBytes = Number(value.totalBytes);
108
+ if (
109
+ value.schema !== RESULT_SETTLEMENT_RECEIPT_SCHEMA ||
110
+ !AUTHORITY_ID_RE.test(sessionId) ||
111
+ !AUTHORITY_ID_RE.test(requestId) ||
112
+ !RESULT_ID_RE.test(resultId) ||
113
+ settlementEventCount !== sourceEventCount + 1 ||
114
+ !Number.isSafeInteger(totalBytes) ||
115
+ totalBytes < 1 ||
116
+ value.applied !== false
117
+ ) {
118
+ throw new TypeError(
119
+ "execution-location result settlement receipt is invalid",
120
+ );
121
+ }
122
+ return Object.freeze({
123
+ schema: value.schema,
124
+ sessionId,
125
+ settlementId: requireDigest(value.settlementId, "settlement id"),
126
+ requestId,
127
+ requestDigest: requireDigest(value.requestDigest, "request digest"),
128
+ resultId,
129
+ handoffId: requireDigest(value.handoffId, "handoff id"),
130
+ sourceHeadHash: requireHead(value.sourceHeadHash, "source head"),
131
+ sourceEventCount,
132
+ settlementEventHash: requireHead(
133
+ value.settlementEventHash,
134
+ "settlement event hash",
135
+ ),
136
+ settlementEventCount,
137
+ targetHeadHash: requireHead(value.targetHeadHash, "target head"),
138
+ targetEventCount,
139
+ bundleDigest: requireDigest(value.bundleDigest, "bundle digest"),
140
+ verificationDigest: requireDigest(
141
+ value.verificationDigest,
142
+ "verification digest",
143
+ ),
144
+ collectionDigest: requireDigest(
145
+ value.collectionDigest,
146
+ "collection digest",
147
+ ),
148
+ storage: normalizeExecutionLocationResultStoreReceipt(value.storage),
149
+ totalBytes,
150
+ applied: false,
151
+ receiptDigest: requireDigest(
152
+ value.receiptDigest,
153
+ "settlement receipt digest",
154
+ ),
155
+ });
156
+ }
157
+
158
+ function metadata(record) {
159
+ return Object.freeze({
160
+ mediaType: record.mediaType,
161
+ byteLength: record.byteLength,
162
+ digest: record.digest,
163
+ });
164
+ }
165
+
166
+ export function createExecutionLocationResultReview(input = {}) {
167
+ const settlement = normalizeSettlement(input.settlement);
168
+ const bundle = normalizeExecutionLocationResultBundle(input.bundle);
169
+ const verification = verifyExecutionLocationResultBundle({
170
+ bundle,
171
+ sourceAuthority: {
172
+ sessionId: settlement.sessionId,
173
+ headHash: settlement.sourceHeadHash,
174
+ eventCount: settlement.sourceEventCount,
175
+ },
176
+ expectedHandoffId: settlement.handoffId,
177
+ });
178
+ const storage = settlement.storage;
179
+ if (
180
+ settlement.resultId !== bundle.resultId ||
181
+ settlement.bundleDigest !== bundle.bundleDigest ||
182
+ settlement.verificationDigest !== verification.verificationDigest ||
183
+ settlement.totalBytes !== bundle.totalBytes ||
184
+ settlement.targetHeadHash !== bundle.session.target.headHash ||
185
+ settlement.targetEventCount !== bundle.session.target.eventCount ||
186
+ storage.sessionId !== settlement.sessionId ||
187
+ storage.resultId !== settlement.resultId ||
188
+ storage.handoffId !== settlement.handoffId ||
189
+ storage.bundleDigest !== settlement.bundleDigest
190
+ ) {
191
+ throw new Error("stored result bundle does not match settlement authority");
192
+ }
193
+ const material = {
194
+ schema: EXECUTION_LOCATION_RESULT_REVIEW_SCHEMA,
195
+ sessionId: settlement.sessionId,
196
+ requestId: settlement.requestId,
197
+ requestDigest: settlement.requestDigest,
198
+ resultId: settlement.resultId,
199
+ handoffId: settlement.handoffId,
200
+ settlement: {
201
+ settlementId: settlement.settlementId,
202
+ eventHash: settlement.settlementEventHash,
203
+ eventCount: settlement.settlementEventCount,
204
+ receiptDigest: settlement.receiptDigest,
205
+ },
206
+ source: {
207
+ headHash: settlement.sourceHeadHash,
208
+ eventCount: settlement.sourceEventCount,
209
+ },
210
+ target: {
211
+ headHash: settlement.targetHeadHash,
212
+ eventCount: settlement.targetEventCount,
213
+ },
214
+ bundleDigest: bundle.bundleDigest,
215
+ verificationDigest: verification.verificationDigest,
216
+ collectionDigest: settlement.collectionDigest,
217
+ storage: {
218
+ storeId: storage.storeId,
219
+ receiptDigest: storage.receiptDigest,
220
+ canonicalBytesDigest: storage.canonicalBytesDigest,
221
+ byteLength: storage.byteLength,
222
+ format: storage.format,
223
+ retention: storage.retention,
224
+ },
225
+ summary: metadata(bundle.summary),
226
+ diff: metadata(bundle.diff),
227
+ artifacts: bundle.artifacts.map(metadata),
228
+ evidence: bundle.evidence.map(metadata),
229
+ totalBytes: bundle.totalBytes,
230
+ applied: false,
231
+ applyPolicy: {
232
+ automaticApply: false,
233
+ requirements: [
234
+ "explicit-review-digest",
235
+ "exact-source-git-identity",
236
+ "managed-workspace-transaction",
237
+ "session-apply-reservation",
238
+ ],
239
+ },
240
+ gaps: [
241
+ "stored-result-not-applied",
242
+ "local-store-not-worm-or-off-box",
243
+ "ide-review-ui-not-integrated",
244
+ ],
245
+ };
246
+ return Object.freeze({
247
+ ...material,
248
+ reviewDigest: digest(
249
+ "chainlesschain.execution-location.result-review.v1\0",
250
+ material,
251
+ ),
252
+ });
253
+ }
@@ -0,0 +1,331 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createHash, randomUUID } from "node:crypto";
4
+ import { TextDecoder } from "node:util";
5
+ import { getHomeDir } from "./paths.js";
6
+ import { ensurePrivateDirectory, ensurePrivateFile } from "./secure-fs.js";
7
+ import {
8
+ sameFileStatIdentity,
9
+ samePathHandleFileIdentity,
10
+ withTrustedFileParentSync,
11
+ } from "./secure-file-identity.js";
12
+ import { withFileLock } from "./with-file-lock.js";
13
+ import { canonicalJson } from "./scheduler-kernel/contract.js";
14
+ import {
15
+ MAX_EXECUTION_LOCATION_RESULT_BUNDLE_BYTES,
16
+ normalizeExecutionLocationResultBundle,
17
+ } from "./execution-location-result.js";
18
+
19
+ export const EXECUTION_LOCATION_RESULT_STORE_RECEIPT_SCHEMA =
20
+ "chainlesschain.execution-location-result-store-receipt/v1";
21
+
22
+ const SHA256_RE = /^sha256:[a-f0-9]{64}$/u;
23
+ const STORE_ID_RE = /^result-sha256-[a-f0-9]{64}$/u;
24
+
25
+ export const _executionLocationResultStoreFaultHooks = Object.seal({
26
+ afterFilePublish: null,
27
+ });
28
+
29
+ function digest(domain, value) {
30
+ return `sha256:${createHash("sha256")
31
+ .update(domain, "utf8")
32
+ .update(canonicalJson(value, "executionLocationResultStore"), "utf8")
33
+ .digest("hex")}`;
34
+ }
35
+
36
+ function bytesDigest(bytes) {
37
+ return `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
38
+ }
39
+
40
+ function exactObject(value, fields, label) {
41
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
42
+ throw new TypeError(`${label} must be an object`);
43
+ }
44
+ const actual = Object.keys(value).sort();
45
+ const expected = [...fields].sort();
46
+ if (
47
+ actual.length !== expected.length ||
48
+ actual.some((field, index) => field !== expected[index])
49
+ ) {
50
+ throw new TypeError(`${label} has an invalid schema`);
51
+ }
52
+ return value;
53
+ }
54
+
55
+ function canonicalBundleBytes(bundleInput) {
56
+ const bundle = normalizeExecutionLocationResultBundle(bundleInput);
57
+ const bytes = Buffer.from(
58
+ canonicalJson(bundle, "executionLocationResultStoreBundle"),
59
+ "utf8",
60
+ );
61
+ if (
62
+ bytes.length <= 0 ||
63
+ bytes.length > MAX_EXECUTION_LOCATION_RESULT_BUNDLE_BYTES
64
+ ) {
65
+ throw new Error("canonical execution-location result bundle is oversized");
66
+ }
67
+ return Object.freeze({ bundle, bytes });
68
+ }
69
+
70
+ function createReceipt(bundle, bytes) {
71
+ const material = {
72
+ schema: EXECUTION_LOCATION_RESULT_STORE_RECEIPT_SCHEMA,
73
+ storeId: `result-${bundle.bundleDigest.replace(":", "-")}`,
74
+ sessionId: bundle.session.sessionId,
75
+ resultId: bundle.resultId,
76
+ handoffId: bundle.session.handoffId,
77
+ bundleDigest: bundle.bundleDigest,
78
+ canonicalBytesDigest: bytesDigest(bytes),
79
+ byteLength: bytes.length,
80
+ format: "canonical-json",
81
+ retention: "explicit-delete-local-not-worm",
82
+ };
83
+ return Object.freeze({
84
+ ...material,
85
+ receiptDigest: digest(
86
+ "chainlesschain.execution-location.result-store-receipt.v1\0",
87
+ material,
88
+ ),
89
+ });
90
+ }
91
+
92
+ export function normalizeExecutionLocationResultStoreReceipt(input) {
93
+ const value = exactObject(
94
+ input,
95
+ [
96
+ "schema",
97
+ "storeId",
98
+ "sessionId",
99
+ "resultId",
100
+ "handoffId",
101
+ "bundleDigest",
102
+ "canonicalBytesDigest",
103
+ "byteLength",
104
+ "format",
105
+ "retention",
106
+ "receiptDigest",
107
+ ],
108
+ "execution-location result store receipt",
109
+ );
110
+ if (
111
+ value.schema !== EXECUTION_LOCATION_RESULT_STORE_RECEIPT_SCHEMA ||
112
+ !STORE_ID_RE.test(String(value.storeId || "")) ||
113
+ !SHA256_RE.test(String(value.handoffId || "")) ||
114
+ !SHA256_RE.test(String(value.bundleDigest || "")) ||
115
+ !SHA256_RE.test(String(value.canonicalBytesDigest || "")) ||
116
+ !SHA256_RE.test(String(value.receiptDigest || "")) ||
117
+ value.storeId !== `result-${value.bundleDigest.replace(":", "-")}` ||
118
+ !Number.isSafeInteger(Number(value.byteLength)) ||
119
+ Number(value.byteLength) <= 0 ||
120
+ Number(value.byteLength) > MAX_EXECUTION_LOCATION_RESULT_BUNDLE_BYTES ||
121
+ value.format !== "canonical-json" ||
122
+ value.retention !== "explicit-delete-local-not-worm"
123
+ ) {
124
+ throw new TypeError("execution-location result store receipt is invalid");
125
+ }
126
+ const material = {
127
+ schema: value.schema,
128
+ storeId: value.storeId,
129
+ sessionId: String(value.sessionId || ""),
130
+ resultId: String(value.resultId || ""),
131
+ handoffId: value.handoffId,
132
+ bundleDigest: value.bundleDigest,
133
+ canonicalBytesDigest: value.canonicalBytesDigest,
134
+ byteLength: Number(value.byteLength),
135
+ format: value.format,
136
+ retention: value.retention,
137
+ };
138
+ if (
139
+ material.sessionId.length === 0 ||
140
+ material.sessionId.length > 256 ||
141
+ material.resultId.length === 0 ||
142
+ material.resultId.length > 128 ||
143
+ value.receiptDigest !==
144
+ digest(
145
+ "chainlesschain.execution-location.result-store-receipt.v1\0",
146
+ material,
147
+ )
148
+ ) {
149
+ throw new TypeError("execution-location result store receipt is invalid");
150
+ }
151
+ return Object.freeze({ ...material, receiptDigest: value.receiptDigest });
152
+ }
153
+
154
+ export function executionLocationResultStoreDir() {
155
+ return path.join(getHomeDir(), "execution-location-results");
156
+ }
157
+
158
+ function resultPath(receipt, dir) {
159
+ return path.join(dir, `${receipt.storeId}.json`);
160
+ }
161
+
162
+ function syncDirectory(directory, runtimeFs, platform) {
163
+ if (platform === "win32") return;
164
+ const descriptor = runtimeFs.openSync(directory, "r");
165
+ try {
166
+ runtimeFs.fsyncSync(descriptor);
167
+ } finally {
168
+ runtimeFs.closeSync(descriptor);
169
+ }
170
+ }
171
+
172
+ function readStoredBytes(receipt, dir, options = {}) {
173
+ const runtimeFs = options.fs || fs;
174
+ const filePath = resultPath(receipt, dir);
175
+ return (options.withTrustedFileParentSync || withTrustedFileParentSync)(
176
+ runtimeFs,
177
+ filePath,
178
+ ({ canonicalPath, parentDevice }) => {
179
+ const before = runtimeFs.lstatSync(canonicalPath, { bigint: true });
180
+ if (
181
+ before.isSymbolicLink() ||
182
+ !before.isFile() ||
183
+ Number(before.nlink) !== 1 ||
184
+ Number(before.size) !== receipt.byteLength
185
+ ) {
186
+ throw new Error("stored execution-location result identity is invalid");
187
+ }
188
+ let descriptor = null;
189
+ try {
190
+ descriptor = runtimeFs.openSync(
191
+ canonicalPath,
192
+ runtimeFs.constants.O_RDONLY |
193
+ Number(runtimeFs.constants.O_NOFOLLOW || 0),
194
+ );
195
+ const opened = runtimeFs.fstatSync(descriptor, { bigint: true });
196
+ if (
197
+ !opened.isFile() ||
198
+ Number(opened.nlink) !== 1 ||
199
+ !(options.samePathHandleFileIdentity || samePathHandleFileIdentity)(
200
+ before,
201
+ opened,
202
+ parentDevice,
203
+ options.runtime,
204
+ )
205
+ ) {
206
+ throw new Error(
207
+ "stored execution-location result changed while opening",
208
+ );
209
+ }
210
+ const bytes = runtimeFs.readFileSync(descriptor);
211
+ const after = runtimeFs.fstatSync(descriptor, { bigint: true });
212
+ if (
213
+ bytes.length !== receipt.byteLength ||
214
+ !(options.sameFileStatIdentity || sameFileStatIdentity)(opened, after)
215
+ ) {
216
+ throw new Error(
217
+ "stored execution-location result changed while reading",
218
+ );
219
+ }
220
+ return bytes;
221
+ } finally {
222
+ if (descriptor !== null) runtimeFs.closeSync(descriptor);
223
+ }
224
+ },
225
+ );
226
+ }
227
+
228
+ export function readStoredExecutionLocationResultBundle(
229
+ receiptInput,
230
+ options = {},
231
+ ) {
232
+ const receipt = normalizeExecutionLocationResultStoreReceipt(receiptInput);
233
+ const dir = path.resolve(options.dir || executionLocationResultStoreDir());
234
+ (options.ensurePrivateDirectory || ensurePrivateDirectory)(dir);
235
+ (options.ensurePrivateFile || ensurePrivateFile)(resultPath(receipt, dir));
236
+ const bytes = readStoredBytes(receipt, dir, options);
237
+ if (bytesDigest(bytes) !== receipt.canonicalBytesDigest) {
238
+ throw new Error("stored execution-location result byte digest mismatch");
239
+ }
240
+ let parsed;
241
+ try {
242
+ parsed = JSON.parse(
243
+ new TextDecoder("utf-8", { fatal: true }).decode(bytes),
244
+ );
245
+ } catch {
246
+ throw new Error("stored execution-location result JSON is invalid");
247
+ }
248
+ const canonical = canonicalBundleBytes(parsed);
249
+ if (
250
+ canonical.bundle.bundleDigest !== receipt.bundleDigest ||
251
+ canonical.bundle.resultId !== receipt.resultId ||
252
+ canonical.bundle.session.sessionId !== receipt.sessionId ||
253
+ canonical.bundle.session.handoffId !== receipt.handoffId ||
254
+ !canonical.bytes.equals(bytes)
255
+ ) {
256
+ throw new Error("stored execution-location result receipt mismatch");
257
+ }
258
+ return canonical.bundle;
259
+ }
260
+
261
+ export function storeExecutionLocationResultBundle(bundleInput, options = {}) {
262
+ const canonical = canonicalBundleBytes(bundleInput);
263
+ const receipt = createReceipt(canonical.bundle, canonical.bytes);
264
+ const dir = path.resolve(options.dir || executionLocationResultStoreDir());
265
+ const runtimeFs = options.fs || fs;
266
+ (options.ensurePrivateDirectory || ensurePrivateDirectory)(dir);
267
+ const filePath = resultPath(receipt, dir);
268
+ return (options.withFileLock || withFileLock)(
269
+ filePath,
270
+ () => {
271
+ if (runtimeFs.existsSync(filePath)) {
272
+ readStoredExecutionLocationResultBundle(receipt, { ...options, dir });
273
+ return Object.freeze({ receipt, stored: false });
274
+ }
275
+ const temporaryPath = path.join(
276
+ dir,
277
+ `.${receipt.storeId}.${process.pid}.${randomUUID()}.tmp`,
278
+ );
279
+ let descriptor = null;
280
+ let published = false;
281
+ try {
282
+ descriptor = runtimeFs.openSync(temporaryPath, "wx", 0o600);
283
+ runtimeFs.writeFileSync(descriptor, canonical.bytes);
284
+ runtimeFs.fsyncSync(descriptor);
285
+ runtimeFs.closeSync(descriptor);
286
+ descriptor = null;
287
+ runtimeFs.linkSync(temporaryPath, filePath);
288
+ published = true;
289
+ runtimeFs.unlinkSync(temporaryPath);
290
+ (options.ensurePrivateFile || ensurePrivateFile)(filePath);
291
+ syncDirectory(dir, runtimeFs, options.platform || process.platform);
292
+ if (
293
+ typeof _executionLocationResultStoreFaultHooks.afterFilePublish ===
294
+ "function"
295
+ ) {
296
+ _executionLocationResultStoreFaultHooks.afterFilePublish({
297
+ filePath,
298
+ receipt,
299
+ });
300
+ }
301
+ } catch (error) {
302
+ if (descriptor !== null) {
303
+ try {
304
+ runtimeFs.closeSync(descriptor);
305
+ } catch {
306
+ // Preserve the original publication error.
307
+ }
308
+ }
309
+ try {
310
+ runtimeFs.unlinkSync(temporaryPath);
311
+ } catch {
312
+ // Best-effort staging cleanup.
313
+ }
314
+ if (!published && error?.code === "EEXIST") {
315
+ readStoredExecutionLocationResultBundle(receipt, { ...options, dir });
316
+ return Object.freeze({ receipt, stored: false });
317
+ }
318
+ throw error;
319
+ }
320
+ readStoredExecutionLocationResultBundle(receipt, { ...options, dir });
321
+ return Object.freeze({ receipt, stored: true });
322
+ },
323
+ {
324
+ failIfUnavailable: true,
325
+ timeoutMs: 30_000,
326
+ retryMs: 1,
327
+ maxRetryMs: 8,
328
+ retryJitterMs: 4,
329
+ },
330
+ );
331
+ }