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,339 @@
1
+ import { createHash } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { WORKSPACE_TRANSACTION_COVERAGE } from "./process-execution-broker/workspace-transaction.js";
5
+ import { canonicalJson } from "./scheduler-kernel/contract.js";
6
+
7
+ const MAX_GIT_OUTPUT_BYTES = 16 * 1024;
8
+ const MAX_APPLY_OUTPUT_BYTES = 1024 * 1024;
9
+ const PROCESS_TREE_BOUNDARY = "process-tree";
10
+
11
+ function digest(domain, value) {
12
+ return `sha256:${createHash("sha256")
13
+ .update(domain, "utf8")
14
+ .update(canonicalJson(value, "executionLocationResultApply"), "utf8")
15
+ .digest("hex")}`;
16
+ }
17
+
18
+ function bytesLength(value) {
19
+ if (value == null) return 0;
20
+ return Buffer.isBuffer(value)
21
+ ? value.byteLength
22
+ : Buffer.byteLength(String(value), "utf8");
23
+ }
24
+
25
+ function runGit(broker, args, options = {}) {
26
+ if (!broker || typeof broker.spawnSync !== "function") {
27
+ throw new TypeError("result apply requires ProcessExecutionBroker");
28
+ }
29
+ const result = broker.spawnSync("git", args, {
30
+ cwd: options.cwd,
31
+ shell: false,
32
+ detached: false,
33
+ policy: "allow",
34
+ origin: options.origin || "session:result-apply",
35
+ scope: "session",
36
+ encoding: "buffer",
37
+ maxBuffer: options.maxBuffer || MAX_APPLY_OUTPUT_BYTES,
38
+ ...(options.input ? { input: options.input } : {}),
39
+ ...(options.requiredBoundaries
40
+ ? { requiredBoundaries: options.requiredBoundaries }
41
+ : {}),
42
+ });
43
+ return Object.freeze({
44
+ exitCode: Number.isInteger(result?.status) ? result.status : null,
45
+ signal: typeof result?.signal === "string" ? result.signal : null,
46
+ stdoutBytes: bytesLength(result?.stdout),
47
+ stderrBytes: bytesLength(result?.stderr),
48
+ errorCode: result?.error?.code ? String(result.error.code) : null,
49
+ stdout: result?.stdout,
50
+ });
51
+ }
52
+
53
+ function strictGitText(result, label, maxBytes) {
54
+ if (result.exitCode !== 0 || result.errorCode !== null) {
55
+ throw new Error(`${label} failed`);
56
+ }
57
+ const bytes = Buffer.isBuffer(result.stdout)
58
+ ? result.stdout
59
+ : Buffer.from(result.stdout || "");
60
+ if (bytes.byteLength <= 0 || bytes.byteLength > maxBytes) {
61
+ throw new Error(`${label} output is invalid`);
62
+ }
63
+ return bytes.toString("utf8").trim();
64
+ }
65
+
66
+ function canonicalDirectory(value) {
67
+ const requested = path.resolve(value);
68
+ const resolved = (fs.realpathSync.native || fs.realpathSync)(requested);
69
+ const entry = fs.lstatSync(resolved);
70
+ if (entry.isSymbolicLink() || !entry.isDirectory()) {
71
+ throw new Error("result apply workspace root is invalid");
72
+ }
73
+ return path.resolve(resolved);
74
+ }
75
+
76
+ function samePath(left, right, platform = process.platform) {
77
+ const normalizedLeft = path.resolve(left);
78
+ const normalizedRight = path.resolve(right);
79
+ return platform === "win32"
80
+ ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase()
81
+ : normalizedLeft === normalizedRight;
82
+ }
83
+
84
+ export function verifyExecutionLocationResultApplySourceGit(
85
+ sessionAuthority,
86
+ options = {},
87
+ ) {
88
+ const broker = options.broker;
89
+ const expectedRoot = sessionAuthority?.binding?.source?.git?.root;
90
+ const expectedCommit = String(
91
+ sessionAuthority?.binding?.source?.git?.commit || "",
92
+ ).toLowerCase();
93
+ if (
94
+ typeof expectedRoot !== "string" ||
95
+ expectedRoot.length === 0 ||
96
+ !/^[a-f0-9]{40,64}$/u.test(expectedCommit)
97
+ ) {
98
+ throw new Error(
99
+ "session has no exact source Git identity for result apply",
100
+ );
101
+ }
102
+ const requestedRoot = canonicalDirectory(
103
+ options.workspaceRoot || expectedRoot,
104
+ );
105
+ const liveRootText = strictGitText(
106
+ runGit(broker, ["rev-parse", "--show-toplevel"], {
107
+ cwd: requestedRoot,
108
+ origin: "session:result-apply-git-root",
109
+ maxBuffer: MAX_GIT_OUTPUT_BYTES,
110
+ }),
111
+ "result apply Git root readback",
112
+ MAX_GIT_OUTPUT_BYTES,
113
+ );
114
+ const liveRoot = canonicalDirectory(liveRootText);
115
+ const canonicalExpectedRoot = canonicalDirectory(expectedRoot);
116
+ const liveCommit = strictGitText(
117
+ runGit(broker, ["rev-parse", "--verify", "HEAD"], {
118
+ cwd: liveRoot,
119
+ origin: "session:result-apply-git-head",
120
+ maxBuffer: MAX_GIT_OUTPUT_BYTES,
121
+ }),
122
+ "result apply Git HEAD readback",
123
+ 128,
124
+ ).toLowerCase();
125
+ if (
126
+ !samePath(requestedRoot, liveRoot, options.platform) ||
127
+ !samePath(canonicalExpectedRoot, liveRoot, options.platform) ||
128
+ liveCommit !== expectedCommit
129
+ ) {
130
+ throw new Error("live source Git identity changed before result apply");
131
+ }
132
+ return Object.freeze({
133
+ workspaceRoot: liveRoot,
134
+ sourceGit: Object.freeze({
135
+ rootDigest: digest(
136
+ "chainlesschain.execution-location.result-apply-git-root.v1\0",
137
+ { canonicalRoot: liveRoot },
138
+ ),
139
+ commit: liveCommit,
140
+ }),
141
+ });
142
+ }
143
+
144
+ function transactionId(sessionId, applyId) {
145
+ return `result-apply-${createHash("sha256")
146
+ .update(String(sessionId), "utf8")
147
+ .update("\0", "utf8")
148
+ .update(String(applyId), "utf8")
149
+ .digest("hex")
150
+ .slice(0, 32)}`;
151
+ }
152
+
153
+ function preparedTransaction(transaction) {
154
+ const state = transaction.snapshot();
155
+ return Object.freeze({
156
+ id: transaction.id,
157
+ checkpointId: transaction.checkpointId,
158
+ checkpointDigest: state.checkpoint?.digest,
159
+ coverage: state.requestedCoverage || WORKSPACE_TRANSACTION_COVERAGE.PARTIAL,
160
+ externalSideEffects: false,
161
+ });
162
+ }
163
+
164
+ export function terminalExecutionLocationResultApplyTransaction(stateInput) {
165
+ const state = stateInput?.snapshot ? stateInput.snapshot() : stateInput;
166
+ const evidence = state?.evidence;
167
+ if (
168
+ !state ||
169
+ !evidence ||
170
+ !["committed", "rolled_back"].includes(state.state) ||
171
+ !["committed", "rolled_back"].includes(evidence.outcome)
172
+ ) {
173
+ throw new Error("result apply workspace transaction is not terminal");
174
+ }
175
+ return Object.freeze({
176
+ id: state.id,
177
+ checkpointId: state.checkpointId,
178
+ checkpointDigest: evidence.checkpointDigest,
179
+ evidenceDigest: evidence.evidenceDigest,
180
+ writeManifestDigest: evidence.writeManifestDigest,
181
+ coverage: evidence.coverage,
182
+ fileCoverage: evidence.fileCoverage,
183
+ externalSideEffects: evidence.externalSideEffects,
184
+ uncoveredPaths: Object.freeze(
185
+ [...(evidence.uncoveredPaths || [])].sort((left, right) =>
186
+ left.localeCompare(right),
187
+ ),
188
+ ),
189
+ });
190
+ }
191
+
192
+ function rollbackResult(
193
+ transaction,
194
+ stage,
195
+ processResult,
196
+ reason,
197
+ error = null,
198
+ ) {
199
+ const evidence = transaction.rollback({ reason });
200
+ return Object.freeze({
201
+ ok: false,
202
+ outcome: "rolled_back",
203
+ stage,
204
+ transaction: terminalExecutionLocationResultApplyTransaction({
205
+ ...transaction.snapshot(),
206
+ evidence,
207
+ }),
208
+ process: processResult
209
+ ? Object.freeze({
210
+ exitCode: processResult.exitCode,
211
+ signal: processResult.signal,
212
+ stdoutBytes: processResult.stdoutBytes,
213
+ stderrBytes: processResult.stderrBytes,
214
+ errorCode: processResult.errorCode,
215
+ })
216
+ : null,
217
+ error,
218
+ });
219
+ }
220
+
221
+ export function executeControlledExecutionLocationResultApply(input = {}) {
222
+ const broker = input.broker;
223
+ if (
224
+ !broker ||
225
+ typeof broker.beginWorkspaceTransaction !== "function" ||
226
+ typeof broker.spawnSync !== "function"
227
+ ) {
228
+ throw new TypeError("result apply requires ProcessExecutionBroker");
229
+ }
230
+ const diffBytes = Buffer.isBuffer(input.diffBytes)
231
+ ? Buffer.from(input.diffBytes)
232
+ : Buffer.from(input.diffBytes || "");
233
+ const transaction = broker.beginWorkspaceTransaction({
234
+ id: transactionId(input.sessionId, input.applyId),
235
+ workspaceRoot: input.workspaceRoot,
236
+ runId: `session-result-apply-${input.applyId}`,
237
+ taskKey: `result-apply:${input.applyId}`,
238
+ coverageTarget: WORKSPACE_TRANSACTION_COVERAGE.PARTIAL,
239
+ externalSideEffects: false,
240
+ writerIsolation: "exclusive-workspace",
241
+ exclusions: [".git"],
242
+ ...(input.stateDir ? { stateDir: path.resolve(input.stateDir) } : {}),
243
+ });
244
+ const prepared = preparedTransaction(transaction);
245
+ try {
246
+ input.onPrepared?.(prepared);
247
+ } catch (error) {
248
+ return rollbackResult(
249
+ transaction,
250
+ "reservation",
251
+ null,
252
+ "result apply reservation failed before process execution",
253
+ error,
254
+ );
255
+ }
256
+
257
+ let checked;
258
+ try {
259
+ checked = runGit(
260
+ broker,
261
+ ["apply", "--check", "--whitespace=error-all", "-"],
262
+ {
263
+ cwd: input.workspaceRoot,
264
+ input: diffBytes,
265
+ requiredBoundaries: [PROCESS_TREE_BOUNDARY],
266
+ },
267
+ );
268
+ } catch (error) {
269
+ return rollbackResult(
270
+ transaction,
271
+ "check",
272
+ null,
273
+ "git apply check could not complete",
274
+ error,
275
+ );
276
+ }
277
+ if (checked.exitCode !== 0 || checked.errorCode !== null) {
278
+ return rollbackResult(
279
+ transaction,
280
+ "check",
281
+ checked,
282
+ "git apply check rejected the reviewed diff",
283
+ );
284
+ }
285
+
286
+ let applied;
287
+ try {
288
+ applied = runGit(broker, ["apply", "--whitespace=error-all", "-"], {
289
+ cwd: input.workspaceRoot,
290
+ input: diffBytes,
291
+ requiredBoundaries: [PROCESS_TREE_BOUNDARY],
292
+ });
293
+ } catch (error) {
294
+ return rollbackResult(
295
+ transaction,
296
+ "apply",
297
+ null,
298
+ "git apply could not complete",
299
+ error,
300
+ );
301
+ }
302
+ if (applied.exitCode !== 0 || applied.errorCode !== null) {
303
+ return rollbackResult(
304
+ transaction,
305
+ "apply",
306
+ applied,
307
+ "git apply rejected the reviewed diff",
308
+ );
309
+ }
310
+
311
+ try {
312
+ const evidence = transaction.accept();
313
+ return Object.freeze({
314
+ ok: true,
315
+ outcome: "applied",
316
+ stage: "complete",
317
+ transaction: terminalExecutionLocationResultApplyTransaction({
318
+ ...transaction.snapshot(),
319
+ evidence,
320
+ }),
321
+ process: Object.freeze({
322
+ exitCode: applied.exitCode,
323
+ signal: applied.signal,
324
+ stdoutBytes: checked.stdoutBytes + applied.stdoutBytes,
325
+ stderrBytes: checked.stderrBytes + applied.stderrBytes,
326
+ errorCode: null,
327
+ }),
328
+ error: null,
329
+ });
330
+ } catch (error) {
331
+ return rollbackResult(
332
+ transaction,
333
+ "commit",
334
+ applied,
335
+ "result apply transaction commit failed",
336
+ error,
337
+ );
338
+ }
339
+ }
@@ -0,0 +1,271 @@
1
+ import { createHash } from "node:crypto";
2
+ import { ArtifactStore, publicArtifactMetadata } from "./artifact-store.js";
3
+ import { canonicalJson } from "./scheduler-kernel/contract.js";
4
+
5
+ export const EXECUTION_LOCATION_RESULT_ARTIFACT_IMPORT_SCHEMA =
6
+ "cc-execution-location-result-artifact-import/v1";
7
+ export const EXECUTION_LOCATION_RESULT_ARTIFACT_LINEAGE_SCHEMA =
8
+ "cc-execution-location-result-artifact-lineage/v1";
9
+
10
+ const SHA256_RE = /^sha256:[a-f0-9]{64}$/u;
11
+ const AUTHORITY_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:@+-]{0,255}$/u;
12
+
13
+ function digest(domain, value) {
14
+ return `sha256:${createHash("sha256")
15
+ .update(domain, "utf8")
16
+ .update(canonicalJson(value, "executionLocationResultArtifact"), "utf8")
17
+ .digest("hex")}`;
18
+ }
19
+
20
+ function bytesDigest(bytes) {
21
+ return `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
22
+ }
23
+
24
+ function exactObject(value, fields, label) {
25
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
26
+ throw new TypeError(`${label} must be an object`);
27
+ }
28
+ const actual = Object.keys(value).sort();
29
+ const expected = [...fields].sort();
30
+ if (
31
+ actual.length !== expected.length ||
32
+ actual.some((field, index) => field !== expected[index])
33
+ ) {
34
+ throw new TypeError(`${label} has an invalid schema`);
35
+ }
36
+ return value;
37
+ }
38
+
39
+ function normalizeLineage(input) {
40
+ const value = exactObject(
41
+ input,
42
+ [
43
+ "schema",
44
+ "sessionId",
45
+ "requestId",
46
+ "reviewDigest",
47
+ "item",
48
+ "kind",
49
+ "mediaType",
50
+ "byteLength",
51
+ "sourceDigest",
52
+ ],
53
+ "execution-location result artifact lineage",
54
+ );
55
+ const sessionId = String(value.sessionId || "");
56
+ const requestId = String(value.requestId || "");
57
+ const reviewDigest = String(value.reviewDigest || "");
58
+ const item = String(value.item || "");
59
+ const kind = String(value.kind || "");
60
+ const mediaType = String(value.mediaType || "");
61
+ const sourceDigest = String(value.sourceDigest || "");
62
+ const byteLength = Number(value.byteLength);
63
+ const selectorMatches =
64
+ (kind === "summary" && item === "summary") ||
65
+ (kind === "diff" && item === "diff") ||
66
+ ((kind === "artifact" || kind === "evidence") &&
67
+ item === `${kind}:${sourceDigest}`);
68
+ if (
69
+ value.schema !== EXECUTION_LOCATION_RESULT_ARTIFACT_LINEAGE_SCHEMA ||
70
+ !AUTHORITY_ID_RE.test(sessionId) ||
71
+ !AUTHORITY_ID_RE.test(requestId) ||
72
+ !SHA256_RE.test(reviewDigest) ||
73
+ !SHA256_RE.test(sourceDigest) ||
74
+ !selectorMatches ||
75
+ mediaType.length < 1 ||
76
+ mediaType.length > 256 ||
77
+ Array.from(mediaType).some((character) => {
78
+ const codePoint = character.codePointAt(0);
79
+ return codePoint <= 0x1f || codePoint === 0x7f;
80
+ }) ||
81
+ !Number.isSafeInteger(byteLength) ||
82
+ byteLength < 0
83
+ ) {
84
+ throw new TypeError(
85
+ "execution-location result artifact lineage is invalid",
86
+ );
87
+ }
88
+ return Object.freeze({
89
+ schema: value.schema,
90
+ sessionId,
91
+ requestId,
92
+ reviewDigest,
93
+ item,
94
+ kind,
95
+ mediaType,
96
+ byteLength,
97
+ sourceDigest,
98
+ });
99
+ }
100
+
101
+ function artifactKind(kind) {
102
+ if (kind === "summary") return "report";
103
+ if (kind === "diff") return "patch";
104
+ if (kind === "evidence") return "data";
105
+ return "other";
106
+ }
107
+
108
+ function extensionFor(lineage) {
109
+ if (lineage.kind === "diff") return ".patch";
110
+ const exact = {
111
+ "application/json": ".json",
112
+ "image/gif": ".gif",
113
+ "image/jpeg": ".jpg",
114
+ "image/png": ".png",
115
+ "image/webp": ".webp",
116
+ "text/csv": ".csv",
117
+ "text/html": ".html",
118
+ "text/markdown": ".md",
119
+ "text/plain": ".txt",
120
+ };
121
+ return exact[lineage.mediaType.toLowerCase()] || ".bin";
122
+ }
123
+
124
+ function expectedArtifactMetadata(lineage, importDigest) {
125
+ const suffix = importDigest.slice("sha256:".length, "sha256:".length + 16);
126
+ return Object.freeze({
127
+ title: `Returned ${lineage.kind} ${suffix}`,
128
+ kind: artifactKind(lineage.kind),
129
+ mime: lineage.mediaType,
130
+ size: lineage.byteLength,
131
+ sha256: lineage.sourceDigest.slice("sha256:".length),
132
+ sessionId: lineage.sessionId,
133
+ immutable: true,
134
+ recordDigest: importDigest,
135
+ fileName: `execution-result-${lineage.kind}-${suffix}${extensionFor(lineage)}`,
136
+ });
137
+ }
138
+
139
+ function createReceipt(entry, lineage, importDigest) {
140
+ const metadata = publicArtifactMetadata(entry);
141
+ const artifact = { ...metadata };
142
+ delete artifact.lineage;
143
+ const material = {
144
+ schema: EXECUTION_LOCATION_RESULT_ARTIFACT_IMPORT_SCHEMA,
145
+ importDigest,
146
+ source: lineage,
147
+ artifact,
148
+ retention: "artifact-store-ttl-explicit-delete-not-worm",
149
+ };
150
+ return Object.freeze({
151
+ ...material,
152
+ receiptDigest: digest(
153
+ "chainlesschain.execution-location.result-artifact-import-receipt.v1\0",
154
+ material,
155
+ ),
156
+ });
157
+ }
158
+
159
+ export function readExecutionLocationResultArtifactImport(
160
+ importDigestInput,
161
+ options = {},
162
+ ) {
163
+ const importDigest = String(importDigestInput || "");
164
+ if (!SHA256_RE.test(importDigest)) {
165
+ throw new TypeError(
166
+ "execution-location result artifact import digest is invalid",
167
+ );
168
+ }
169
+ const store = options.artifactStore || new ArtifactStore();
170
+ const matches = store
171
+ .list()
172
+ .filter((entry) => entry.recordDigest === importDigest);
173
+ if (matches.length !== 1) {
174
+ throw new Error(
175
+ matches.length === 0
176
+ ? "execution-location result artifact import was not found"
177
+ : "execution-location result artifact import is ambiguous",
178
+ );
179
+ }
180
+ const entry = matches[0];
181
+ const lineage = normalizeLineage(entry.lineage);
182
+ const expectedImportDigest = digest(
183
+ "chainlesschain.execution-location.result-artifact-import.v1\0",
184
+ lineage,
185
+ );
186
+ const expected = expectedArtifactMetadata(lineage, expectedImportDigest);
187
+ const integrity = store.verifyIntegrity(entry);
188
+ if (
189
+ expectedImportDigest !== importDigest ||
190
+ entry.title !== expected.title ||
191
+ entry.kind !== expected.kind ||
192
+ entry.mime !== expected.mime ||
193
+ entry.size !== expected.size ||
194
+ entry.sha256 !== expected.sha256 ||
195
+ entry.sessionId !== expected.sessionId ||
196
+ entry.immutable !== true ||
197
+ entry.recordDigest !== expected.recordDigest ||
198
+ integrity.ok !== true ||
199
+ integrity.actualSha256 !== expected.sha256
200
+ ) {
201
+ throw new Error(
202
+ "execution-location result ArtifactStore readback does not match import authority",
203
+ );
204
+ }
205
+ return Object.freeze({
206
+ receipt: createReceipt(entry, lineage, importDigest),
207
+ entry,
208
+ integrity: Object.freeze({ ...integrity }),
209
+ });
210
+ }
211
+
212
+ export function importExecutionLocationResultArtifact(preview, options = {}) {
213
+ const bytes = Buffer.isBuffer(preview?.bytes)
214
+ ? Buffer.from(preview.bytes)
215
+ : null;
216
+ const lineage = normalizeLineage({
217
+ schema: EXECUTION_LOCATION_RESULT_ARTIFACT_LINEAGE_SCHEMA,
218
+ sessionId: preview?.sessionId,
219
+ requestId: preview?.requestId,
220
+ reviewDigest: preview?.reviewDigest,
221
+ item: preview?.item,
222
+ kind: preview?.kind,
223
+ mediaType: preview?.mediaType,
224
+ byteLength: preview?.byteLength,
225
+ sourceDigest: preview?.digest,
226
+ });
227
+ if (
228
+ bytes === null ||
229
+ bytes.byteLength !== lineage.byteLength ||
230
+ bytesDigest(bytes) !== lineage.sourceDigest
231
+ ) {
232
+ throw new Error(
233
+ "execution-location result content does not match import authority",
234
+ );
235
+ }
236
+ const importDigest = digest(
237
+ "chainlesschain.execution-location.result-artifact-import.v1\0",
238
+ lineage,
239
+ );
240
+ const expected = expectedArtifactMetadata(lineage, importDigest);
241
+ const store = options.artifactStore || new ArtifactStore();
242
+ if (typeof store.publishDataOnce !== "function") {
243
+ throw new Error("ArtifactStore idempotent import is unavailable");
244
+ }
245
+ const publication = store.publishDataOnce({
246
+ data: bytes,
247
+ fileName: expected.fileName,
248
+ title: expected.title,
249
+ kind: expected.kind,
250
+ mime: expected.mime,
251
+ sessionId: expected.sessionId,
252
+ immutable: true,
253
+ recordDigest: importDigest,
254
+ lineage,
255
+ });
256
+ const readback = readExecutionLocationResultArtifactImport(importDigest, {
257
+ artifactStore: store,
258
+ });
259
+ if (
260
+ canonicalJson(readback.entry.lineage, "resultArtifactStoredLineage") !==
261
+ canonicalJson(lineage, "resultArtifactExpectedLineage")
262
+ ) {
263
+ throw new Error(
264
+ "execution-location result ArtifactStore lineage does not match reviewed item",
265
+ );
266
+ }
267
+ return Object.freeze({
268
+ ...readback.receipt,
269
+ imported: publication.published === true,
270
+ });
271
+ }