chainlesschain 0.165.3 → 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 (203) hide show
  1. package/README.md +151 -29
  2. package/package.json +2 -2
  3. package/src/assets/web-panel/assets/{AIOps-BiHNUlbU.js → AIOps-C__nnraW.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-D-UFjDRQ.js → ActionButton-CsKWHEZ-.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-DazVsDgW.js → Analytics-BhIjfjWO.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-DXh9UfNJ.js → AppLayout-BjuXFzWZ.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-CZ6tsceY.js → Artifacts-k6whDkZJ.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-RyxnBr_h.js → Audit-C4FBMYRh.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-BWS51Q6X.js → BackgroundAgents-C_vRrSXk.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-BRtPcUul.js → Backup-CngFZeVp.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-CGd4vZYY.js → BaseInput-B_H9EBRm.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-h8ijVwCg.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-NyF6dPl8.js → Checkbox-m3ClR4xh.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-Ci4OOxr5.js → Codegen-CmLSFrgp.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-CwTkc9BM.js → Col-DFGQteHN.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-DW_tM82m.js → Community-EUUVORHE.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-DEvHRV4S.js → Compact-2PSg0Yr7.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BbjBEEfD.js → Compliance-CcKur7gB.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-10IXBaBa.js → Cowork-DK_Fezfa.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-BZkbpd5I.js → Cron-Dbw89xl7.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-CFQ8L_6v.js → Crosschain-CH66h_Ec.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-BDF6AkXe.js → DID-D1igRb17.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-CoOdWMi4.js → Dashboard-DVAsrobk.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-DEsGmu8Y.js → Dropdown-Dl7W8AQs.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-BS89SWlK.js → EmailListRenderer-D5tpaEQC.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-C1FpCHiI.js → FamilyGuardDashboard-O_VQf8gq.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-BzvpVmLA.js → Federation-BTVcgS9n.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-BeC259PQ.js → FormItemContext-BRnkJAIz.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-azgG3bmV.js → GenericCardRenderer-8OWSCkDj.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-BmSSowc5.js → Git-WXLYTQj2.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-CTBCSyQZ.js → Governance-BezaUhtc.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-DA5xyk4a.js → Inference-CuRay3Gu.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-D1gPHNig.js → KnowledgeGraph-DfWLDW1m.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-BPmLf1AR.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-DtUFcR0E.js → Marketplace-Dk08Uycg.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-DS_kqBv-.js → McpTools-C11fSB5V.js} +3 -3
  39. package/src/assets/web-panel/assets/{Memory-Fvh7XL7V.js → Memory-mr0eZc97.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-C7itAP45.js → MobileBridge-C0iCSRbb.js} +1 -1
  41. package/src/assets/web-panel/assets/MobileProjects-CY-xMG8Z.js +1 -0
  42. package/src/assets/web-panel/assets/{Mtc-B57MiNLK.js → Mtc-Bplqc_Wc.js} +6 -6
  43. package/src/assets/web-panel/assets/{MtcAudit-BXfCUcM7.js → MtcAudit-BlzwsoSM.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-yaJ-ZcF6.js → Multisig-BBLmTty6.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-CoaUCKrO.js → NLProgramming-DtT1uf1W.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-BKLM_65R.js → Notes-DcqQAxTK.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-DoDtK9uZ.js → NotificationSettings-cb0kWoZe.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-BJ28TGr-.js → OrderTableRenderer-kw9HZQNN.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-MuGsdoIb.js → Organization-DlTlbkUN.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-BLUN9J4R.js → Overflow-pp1qs-oY.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-DWuoBUPd.js → P2P-BESLnyYz.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-CUi37YPj.js → PdhVaultBrowser-B-J1mGuf.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-BYQg2pcr.js → Permissions-B36PeT1_.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-CAxoV2xu.js → PersonalDataHub-CTK2ad-3.js} +6 -6
  55. package/src/assets/web-panel/assets/{Pipeline-B33wGvIO.js → Pipeline-zJNGXsac.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-A8yXTORP.js → Privacy-b9fz0Qf0.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-D49I2I1O.js → ProjectInit-DjZbZgiB.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-Ci73jJDw.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-Dz-CAYYU.js +1 -0
  61. package/src/assets/web-panel/assets/{QrScannerModal-Brza0ykJ.js → QrScannerModal-A0yoQ3-3.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-DFydhjxL.js → QuickAsk-DrFgFJNC.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-DLF8_NhA.js → Recommend-KC8hF1g4.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-dyuStW3x.js → RemoteSession-DGTPIk6u.js} +3 -3
  65. package/src/assets/web-panel/assets/{Reputation-5F3tA6yw.js → Reputation-QmbwM7Yk.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-Ca2A57S5.js → Row-BxjJylia.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-B0bxBkq_.js → RssFeed-B7Wda1J6.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-CFNvHalZ.js → Search-_plQ_YSA.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-DSoH3Hav.js → Security-CD2YJZfx.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-BHpfEmBQ.js → Services-qQE7NmwE.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-Dsh-QNmn.js → Skeleton-DgQqkFf7.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-BhT1NkSU.js → Skills-C4C0oFFt.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-DY9snPeJ.js → Sla-Px2N2B5c.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-CWaX0_Cx.js → SpeechSettings-DN6C3lQd.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-B690y_TC.js → SyncSettings-jm5aH_m7.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-2N-w3zWd.js → Tasks-DlkJcv67.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-BjwQOQYC.js → Templates-DyrTHUBs.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-CUqHErxY.js → Tenant-mC434PtL.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-C13rXvNy.js → Terminal-o0_s3NgK.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-CpbWcya_.js → TimelineRenderer-DAGlAXOw.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-BXHLGXYC.js → Tokens-BnulS_bs.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-1e5i65o3.js → Trigger-suQbVXYM.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-FLGqNHs5.js → Trust-DbIJAPo5.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-BbaR_LJB.js → UkeySign-CQNpbIHi.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-NOp4RIov.js → VideoEditing-D8aWCERk.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-B7DW7bG4.js → Wallet-CuLpYfZc.js} +3 -3
  87. package/src/assets/web-panel/assets/{WebAuthn-BptSUWix.js → WebAuthn-CsfG8ZMc.js} +5 -5
  88. package/src/assets/web-panel/assets/{WorkflowEditor-CAJnDOXS.js → WorkflowEditor-BYsEAZbd.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-I8LgG1-Z.js → chat-FT4Um3-I.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-CWe7SOVD.js → colors-CKbS_Wlt.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-Cx3u3CA3.js → compact-item-CFJtzuJM.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-CgD5ArwY.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-BfQWiXN8.js → hasIn-DR-x0Xpi.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-DAVy98u7.js → index-7jHr_A_k.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DlIyt1qF.js → index-B3ZX81mK.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-CWZ3REg6.js → index-B7osrXqy.js} +3 -3
  98. package/src/assets/web-panel/assets/{index-DGMYTN5W.js → index-BGbPnC5x.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DFb-XIKy.js → index-BI5hP_qy.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CAUnl4Jv.js → index-BK3TiKVq.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BUAR7RY-.js → index-BVPU43b1.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cd79NQAx.js → index-BW-t9n-q.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BiI-xPRH.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-B6yChzt1.js → index-Bt4fS2eL.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-e8BM1yY1.js → index-BwR7yc2h.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-V-kIHzAV.js → index-Bzz0C1BZ.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Bx7BNIRH.js → index-C2JvmYRc.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-87gMxqhN.js → index-CGaXUsIs.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Cy_cCJlr.js → index-CJmIQ9XR.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-C1UjHdgZ.js → index-C_enk9I_.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Bi24S7Dw.js → index-Cr2FLUsD.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CcX4FSPf.js → index-CvrCCqJt.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DmrdUwzU.js → index-D4LfPvWA.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Dcdm_Z2c.js → index-DMGmg497.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DCJEY2T0.js → index-DShSkww-.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C0ztiqtB.js → index-DTxNy0ZU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-C-rIKccl.js → index-DW4BWjTk.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CdRkCwm4.js → index-DWdqx7zI.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-C0nDKhWv.js → index-Dap9c3eD.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CQDKYbnv.js → index-DcfxhKXR.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BuEQSorC.js → index-DdkIhfi-.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-3iKP9OTJ.js → index-DeSgw-WV.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-Doc0Ftpd.js → index-DiNUEpSQ.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BREnPKGo.js → index-DjEP7WkH.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CNYFQxAW.js → index-DtkFqPVA.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DslTuqro.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-CMu16vPC.js → index-OSzjTzGM.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DsQcURkA.js → index-QBSeNVO3.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DeizoQVZ.js → index-WE08gMJP.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-B1cX4Rxu.js → index-r2VI1Ikk.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DmgtY58H.js → index-tqSEHPRT.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-DiBszVdG.js → initDefaultProps-Dd7n7VgI.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BGIFFozv.js → motion-BwxouRw1.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-D5W7mp7B.js → move-DObN0PG9.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-JFIlxJ7F.js → mtc-parser-B3nOUQc7.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-CQ3o6LIU.js → omit-o9WU2Nbl.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-R8MIlXo3.js → pickAttrs-CL_vvfQ_.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-sW7ylSky.js → placementArrow-CYrM2tyK.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-Cnl39Vbz.js → responsiveObserve-k_06cQ96.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-sn8tFd14.js → slide-CPKG0pxS.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-IKKY_QxZ.js → statusUtils-BDDEeLTw.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-BNpV4Nqs.js → styleChecker-Cmb7RTh7.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-BWyT_eoU.js → useFlexGapSupport-e2IedC4N.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-D09p6_U9.js → useFs-CE_gxVnm.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-CzW3TkJZ.js → usePersonalDataHub-BkMIIKMz.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-3s3WoAKB.js → vnode-DW886XV1.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-Cjy_673s.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 +13 -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/command-lifecycle-report.js +8 -4
  171. package/src/lib/cowork-adapter.js +9 -5
  172. package/src/lib/cowork-task-runner.js +20 -0
  173. package/src/lib/cowork-workflow.js +178 -20
  174. package/src/lib/direct-model-usage.js +62 -22
  175. package/src/lib/dynamic-workflow-runtime.js +3184 -111
  176. package/src/lib/execution-location-result-apply.js +339 -0
  177. package/src/lib/execution-location-result-artifact.js +271 -0
  178. package/src/lib/execution-location-result-review.js +253 -0
  179. package/src/lib/execution-location-result-store.js +331 -0
  180. package/src/lib/execution-location-result.js +617 -0
  181. package/src/lib/execution-location-target.js +236 -1
  182. package/src/lib/managed-tool-checkpoint.js +47 -4
  183. package/src/lib/process-execution-broker/workspace-transaction.js +3 -0
  184. package/src/lib/session-budget-production-root.js +376 -0
  185. package/src/lib/session-budget-runtime.js +109 -18
  186. package/src/lib/session-budget-usage.js +63 -0
  187. package/src/lib/session-host-snapshot.js +19 -2
  188. package/src/lib/session-resource-budget.js +766 -105
  189. package/src/lib/sub-agent-context.js +69 -22
  190. package/src/lib/web-ui-server.js +12 -1
  191. package/src/repl/agent-repl.js +237 -16
  192. package/src/runtime/agent-core.js +123 -0
  193. package/src/runtime/headless-runner.js +135 -46
  194. package/src/runtime/headless-stream.js +133 -25
  195. package/src/runtime/policies/agent-policy.js +10 -0
  196. package/src/assets/web-panel/assets/ChatBubbleRenderer-D7tcdDS9.js +0 -1
  197. package/src/assets/web-panel/assets/MarkdownRenderer-SVLOg49H.js +0 -1
  198. package/src/assets/web-panel/assets/MobileProjects-DGbP36-3.js +0 -1
  199. package/src/assets/web-panel/assets/Projects-CF-yD6Cn.js +0 -1
  200. package/src/assets/web-panel/assets/Providers-D-etEhg5.js +0 -1
  201. package/src/assets/web-panel/assets/devWarning-DLv_872g.js +0 -1
  202. package/src/assets/web-panel/assets/index-CdiGCibe.js +0 -1
  203. package/src/assets/web-panel/assets/index-D_0z-gyz.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
+ }