chainlesschain 0.165.3 → 0.165.5

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 (214) hide show
  1. package/README.md +151 -29
  2. package/package.json +2 -2
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-BiHNUlbU.js → AIOps-CEeYTeDB.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-D-UFjDRQ.js → ActionButton-BeRUQ3V2.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-DazVsDgW.js → Analytics-DrV718XF.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-DXh9UfNJ.js → AppLayout-Cd2Frt7Q.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-CZ6tsceY.js → Artifacts-CUJMlORU.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-RyxnBr_h.js → Audit-CXJcfT6p.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-BWS51Q6X.js → BackgroundAgents-DOv6Z7H9.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-BRtPcUul.js → Backup-BwdDyBI0.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-CGd4vZYY.js → BaseInput-BmLn4kYH.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-h8ijVwCg.js → Chat-COg8pAW2.js} +4 -4
  14. package/src/assets/web-panel/assets/ChatBubbleRenderer-4gGkdGgA.js +1 -0
  15. package/src/assets/web-panel/assets/{Checkbox-NyF6dPl8.js → Checkbox-BCP4uoU8.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-Ci4OOxr5.js → Codegen-pRt6Y9JI.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-CwTkc9BM.js → Col-DLaprKhS.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-DW_tM82m.js → Community-DyATsz5f.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-DEvHRV4S.js → Compact-BXAaupZK.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-BbjBEEfD.js → Compliance-DpcJBELr.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-10IXBaBa.js → Cowork-DG4EFWyd.js} +2 -2
  22. package/src/assets/web-panel/assets/{Cron-BZkbpd5I.js → Cron-F6Oy5n2P.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-CFQ8L_6v.js → Crosschain-BOdgtalX.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-BDF6AkXe.js → DID-DT1dSkjH.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-CoOdWMi4.js → Dashboard-NBUIqWzC.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-DEsGmu8Y.js → Dropdown-CSpHeMYB.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-BS89SWlK.js → EmailListRenderer-CEG0xISr.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-C1FpCHiI.js → FamilyGuardDashboard-BTZ0BZna.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-BzvpVmLA.js → Federation-BuuCTn2V.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-BeC259PQ.js → FormItemContext-KAVceevk.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-azgG3bmV.js → GenericCardRenderer-DnHpcQvW.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-BmSSowc5.js → Git-C_B_0HwB.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-CTBCSyQZ.js → Governance-DPSZuzuu.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-DA5xyk4a.js → Inference-BV-06V7q.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-D1gPHNig.js → KnowledgeGraph-wpDuupn6.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-BPmLf1AR.js → Logs-Bseca1_I.js} +2 -2
  37. package/src/assets/web-panel/assets/{MarkdownRenderer-SVLOg49H.js → MarkdownRenderer-B4RLp2zs.js} +1 -1
  38. package/src/assets/web-panel/assets/{Marketplace-DtUFcR0E.js → Marketplace-d3kM4DDL.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-DS_kqBv-.js → McpTools-DQ_xZ23i.js} +3 -3
  40. package/src/assets/web-panel/assets/{Memory-Fvh7XL7V.js → Memory-CRIeYO4L.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-C7itAP45.js → MobileBridge-BsllIa9l.js} +1 -1
  42. package/src/assets/web-panel/assets/MobileProjects-BUuQy30X.js +1 -0
  43. package/src/assets/web-panel/assets/{Mtc-B57MiNLK.js → Mtc-BOFDIzrC.js} +6 -6
  44. package/src/assets/web-panel/assets/{MtcAudit-BXfCUcM7.js → MtcAudit-BQg-vyvG.js} +5 -5
  45. package/src/assets/web-panel/assets/{Multisig-yaJ-ZcF6.js → Multisig-Bo1jrPdN.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-CoaUCKrO.js → NLProgramming-Bmod8alw.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-BKLM_65R.js → Notes-CGGFL8w-.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-DoDtK9uZ.js → NotificationSettings-BsZvCJxC.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-BJ28TGr-.js → OrderTableRenderer-C1-Quo_h.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-MuGsdoIb.js → Organization-BjOeDYOi.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-BLUN9J4R.js → Overflow-DwVV3l5A.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-DWuoBUPd.js → P2P-Cu3DQT9W.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-CUi37YPj.js → PdhVaultBrowser-Cg0gR7dH.js} +3 -3
  54. package/src/assets/web-panel/assets/{Permissions-BYQg2pcr.js → Permissions-CsAXxRN5.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-CAxoV2xu.js → PersonalDataHub-C-nNmnYp.js} +6 -6
  56. package/src/assets/web-panel/assets/{Pipeline-B33wGvIO.js → Pipeline-BOnW7nNc.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-A8yXTORP.js → Privacy-ClLSyGKt.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-D49I2I1O.js → ProjectInit-DuLvjjq7.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-Ci73jJDw.js → ProjectSettings-DQYYbDD9.js} +2 -2
  60. package/src/assets/web-panel/assets/{Projects-CF-yD6Cn.js → Projects-Drw8MBGK.js} +1 -1
  61. package/src/assets/web-panel/assets/Providers-ckqHQe6K.js +1 -0
  62. package/src/assets/web-panel/assets/{QrScannerModal-Brza0ykJ.js → QrScannerModal-DW5BXk-G.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-DFydhjxL.js → QuickAsk-DDLnhNTp.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-DLF8_NhA.js → Recommend-PJQ2C91U.js} +1 -1
  65. package/src/assets/web-panel/assets/{RemoteSession-dyuStW3x.js → RemoteSession-s6wmda34.js} +3 -3
  66. package/src/assets/web-panel/assets/{Reputation-5F3tA6yw.js → Reputation-DC2sb-I3.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-Ca2A57S5.js → Row-hPGk1eGj.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-B0bxBkq_.js → RssFeed-RIvfZql0.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-CFNvHalZ.js → Search-DFg1G1eR.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-DSoH3Hav.js → Security-D6H5p8Dp.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-BHpfEmBQ.js → Services-nxYiFV_w.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-Dsh-QNmn.js → Skeleton-BmgFNAdB.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-BhT1NkSU.js → Skills-CsaaD2av.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-DY9snPeJ.js → Sla-yM5y9yvK.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-CWaX0_Cx.js → SpeechSettings-DPy1XMYh.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-B690y_TC.js → SyncSettings-CFVhEyyr.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-2N-w3zWd.js → Tasks-DdO02Inn.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-BjwQOQYC.js → Templates-Eo2d8Llu.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-CUqHErxY.js → Tenant-ChESOXgy.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-C13rXvNy.js → Terminal-BJ7oDxTI.js} +2 -2
  81. package/src/assets/web-panel/assets/TimelineRenderer-hWX0fUvz.js +1 -0
  82. package/src/assets/web-panel/assets/{Tokens-BXHLGXYC.js → Tokens-DVBZQnd-.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-1e5i65o3.js → Trigger-D89cQfVq.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-FLGqNHs5.js → Trust-BIVSb4-V.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-BbaR_LJB.js → UkeySign-B58gWopl.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-NOp4RIov.js → VideoEditing-DhHI7bmG.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-B7DW7bG4.js → Wallet-C4FheWS_.js} +3 -3
  88. package/src/assets/web-panel/assets/{WebAuthn-BptSUWix.js → WebAuthn-DnPRq-Bx.js} +5 -5
  89. package/src/assets/web-panel/assets/{WorkflowEditor-CAJnDOXS.js → WorkflowEditor-BerRPjpJ.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-I8LgG1-Z.js → chat-BzZ52iKr.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-CWe7SOVD.js → colors-BI_E4BAn.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-Cx3u3CA3.js → compact-item-d50mr3yk.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-CgD5ArwY.js → createContext-C6FsQ1IH.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-CagEcIex.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-BfQWiXN8.js → hasIn-DLZEMgLP.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BuEQSorC.js → index-9H_M2jju.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BiI-xPRH.js → index-A5CDWP7y.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DAVy98u7.js → index-AHr7ryWf.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BUAR7RY-.js → index-B81mo1Et.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DlIyt1qF.js → index-BAE3hwev.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-Dcdm_Z2c.js → index-BB9SqVSt.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CWZ3REg6.js → index-BRGx3w6T.js} +3 -3
  103. package/src/assets/web-panel/assets/{index-B6yChzt1.js → index-BTpIOTfR.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DeizoQVZ.js → index-BZjjdQ62.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-e8BM1yY1.js → index-BcSUl9fA.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CNYFQxAW.js → index-BeM4hfht.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DGMYTN5W.js → index-Bmr_vxXD.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BREnPKGo.js → index-BoNZlzhQ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-B1cX4Rxu.js → index-C3k8kevG.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-3iKP9OTJ.js → index-CLoTQr0W.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-C1UjHdgZ.js → index-CO8DAF7U.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Cy_cCJlr.js → index-CRN5TRTQ.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-C0nDKhWv.js → index-CUaEHfQ0.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DslTuqro.js → index-CVzuawCX.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CAUnl4Jv.js → index-CdKt9fOd.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CMu16vPC.js → index-CgkoH3_g.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C-rIKccl.js → index-CjuKZBqJ.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Bx7BNIRH.js → index-Co7s9LsB.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Doc0Ftpd.js → index-D-aBumtY.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Cd79NQAx.js → index-DE0V6cp-.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-V-kIHzAV.js → index-DY4j5zkF.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-Bi24S7Dw.js → index-Dec0Kf_Z.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DCJEY2T0.js → index-DoFtCVZ7.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-C0ztiqtB.js → index-DqkbHHg8.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CcX4FSPf.js → index-DsscwxPE.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CdRkCwm4.js → index-GXE0D8Nx.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DmgtY58H.js → index-IPkwSAW_.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CQDKYbnv.js → index-KNGgO4Wm.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-87gMxqhN.js → index-Pvf30m8Q.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DmrdUwzU.js → index-Q5Tn735s.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DFb-XIKy.js → index-TWG-_D1M.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DsQcURkA.js → index-Y2-q7QLm.js} +1 -1
  133. package/src/assets/web-panel/assets/index-pzT9PpOU.js +1 -0
  134. package/src/assets/web-panel/assets/index-z1kFadaX.js +1 -0
  135. package/src/assets/web-panel/assets/{initDefaultProps-DiBszVdG.js → initDefaultProps-D-4Hzgej.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-BGIFFozv.js → motion-D4Wl4xU7.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-D5W7mp7B.js → move-Cd5eQvL0.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-JFIlxJ7F.js → mtc-parser-B4ilslCW.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-CQ3o6LIU.js → omit-Ckarx-tf.js} +1 -1
  140. package/src/assets/web-panel/assets/parsers-YNLm7sQ0.js +4 -0
  141. package/src/assets/web-panel/assets/{pickAttrs-R8MIlXo3.js → pickAttrs-QJ0bpCmc.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-sW7ylSky.js → placementArrow-CKHm-tq8.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-Cnl39Vbz.js → responsiveObserve-CV6a_w_Y.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-sn8tFd14.js → slide-mHpeQFgk.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-IKKY_QxZ.js → statusUtils-DIaQNQWA.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-BNpV4Nqs.js → styleChecker-PJpzavV8.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-BWyT_eoU.js → useFlexGapSupport-BH7zTw8S.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-D09p6_U9.js → useFs-BDNG3JDd.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-CzW3TkJZ.js → usePersonalDataHub-CY2VWdUg.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-3s3WoAKB.js → vnode-D0kw9jhz.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-Cjy_673s.js → zoom-B5g7TN7r.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/command-help-index.json +3 -3
  154. package/src/commands/agent.js +105 -35
  155. package/src/commands/artifacts.js +598 -33
  156. package/src/commands/cowork.js +200 -5
  157. package/src/commands/session-budget.js +155 -0
  158. package/src/commands/session-location.js +968 -1
  159. package/src/commands/session.js +23 -2
  160. package/src/data/changelog.json +28 -2
  161. package/src/gateways/ws/artifact-protocol.js +77 -13
  162. package/src/gateways/ws/message-dispatcher.js +57 -0
  163. package/src/gateways/ws/session-protocol.js +391 -24
  164. package/src/gateways/ws/ws-agent-handler.js +191 -14
  165. package/src/gateways/ws/ws-server.js +14 -3
  166. package/src/gateways/ws/ws-session-gateway.js +101 -5
  167. package/src/harness/jsonl-session-store.js +1210 -0
  168. package/src/lib/agent-team/team-runner.js +43 -13
  169. package/src/lib/artifact-access-ledger.js +462 -0
  170. package/src/lib/artifact-cleanup-ledger.js +861 -0
  171. package/src/lib/artifact-deletion-ledger.js +678 -0
  172. package/src/lib/artifact-recovery.js +970 -0
  173. package/src/lib/artifact-store.js +256 -51
  174. package/src/lib/artifact-workbench-projection.js +171 -0
  175. package/src/lib/command-lifecycle-report.js +8 -4
  176. package/src/lib/cowork-adapter.js +9 -5
  177. package/src/lib/cowork-task-runner.js +20 -0
  178. package/src/lib/cowork-workflow.js +178 -20
  179. package/src/lib/direct-model-usage.js +62 -22
  180. package/src/lib/dynamic-workflow-runtime.js +3592 -112
  181. package/src/lib/execution-location-result-apply.js +339 -0
  182. package/src/lib/execution-location-result-artifact.js +271 -0
  183. package/src/lib/execution-location-result-review.js +253 -0
  184. package/src/lib/execution-location-result-store.js +331 -0
  185. package/src/lib/execution-location-result.js +617 -0
  186. package/src/lib/execution-location-target.js +240 -3
  187. package/src/lib/managed-tool-checkpoint.js +47 -4
  188. package/src/lib/mcp-stdio-executable-identity.js +16 -0
  189. package/src/lib/mcp-stdio-native-code-policy.js +74 -0
  190. package/src/lib/mcp-stdio-package-materialization.js +12 -3
  191. package/src/lib/process-execution-broker/index.js +112 -0
  192. package/src/lib/process-execution-broker/platform-sandbox.js +57 -3
  193. package/src/lib/process-execution-broker/workspace-transaction.js +29 -0
  194. package/src/lib/session-budget-production-root.js +376 -0
  195. package/src/lib/session-budget-runtime.js +109 -18
  196. package/src/lib/session-budget-usage.js +63 -0
  197. package/src/lib/session-host-snapshot.js +19 -2
  198. package/src/lib/session-projection.js +126 -10
  199. package/src/lib/session-resource-budget.js +766 -105
  200. package/src/lib/sub-agent-context.js +69 -22
  201. package/src/lib/web-ui-server.js +12 -1
  202. package/src/repl/agent-repl.js +237 -16
  203. package/src/runtime/agent-core.js +135 -0
  204. package/src/runtime/headless-runner.js +135 -46
  205. package/src/runtime/headless-stream.js +133 -25
  206. package/src/runtime/policies/agent-policy.js +10 -0
  207. package/src/assets/web-panel/assets/ChatBubbleRenderer-D7tcdDS9.js +0 -1
  208. package/src/assets/web-panel/assets/MobileProjects-DGbP36-3.js +0 -1
  209. package/src/assets/web-panel/assets/Providers-D-etEhg5.js +0 -1
  210. package/src/assets/web-panel/assets/TimelineRenderer-CpbWcya_.js +0 -1
  211. package/src/assets/web-panel/assets/devWarning-DLv_872g.js +0 -1
  212. package/src/assets/web-panel/assets/index-CdiGCibe.js +0 -1
  213. package/src/assets/web-panel/assets/index-D_0z-gyz.js +0 -1
  214. package/src/assets/web-panel/assets/parsers-UEvh_ShA.js +0 -4
@@ -5,23 +5,62 @@ import {
5
5
  buildExecutionLocationCatalog,
6
6
  buildExecutionLocationHandoffPreview,
7
7
  computeExecutionLocationTargetFactsDigest,
8
+ createExecutionLocationTargetAttestation,
8
9
  } from "../lib/execution-location-contract.js";
9
10
  import { captureAmbientExecutionLocation } from "../lib/execution-location-runtime.js";
10
11
  import {
11
12
  EXECUTION_LOCATION_TARGET_ATTESTATION_SCHEMA,
13
+ EXECUTION_LOCATION_TARGET_RESULT_COLLECTION_SCHEMA,
12
14
  EXECUTION_LOCATION_TARGET_RESUME_SCHEMA,
13
15
  attestExecutionLocationTarget,
16
+ collectExecutionLocationTargetResult,
17
+ createExecutionLocationTargetResultCollectionRequest,
14
18
  readExecutionLocationProfile,
15
19
  resumeExecutionLocationTarget,
16
20
  } from "../lib/execution-location-target.js";
21
+ import {
22
+ EXECUTION_LOCATION_RESULT_BUNDLE_SCHEMA,
23
+ EXECUTION_LOCATION_RESULT_VERIFICATION_SCHEMA,
24
+ MAX_EXECUTION_LOCATION_RESULT_BUNDLE_BYTES,
25
+ createExecutionLocationResultBundle,
26
+ readExecutionLocationResultBundle,
27
+ readExecutionLocationResultFile,
28
+ verifyExecutionLocationResultBundle,
29
+ } from "../lib/execution-location-result.js";
17
30
  import {
18
31
  MAX_SESSION_REPLICA_BYTES,
19
32
  SESSION_EXECUTION_LOCATION_HANDOFF_INSTALL_SCHEMA,
33
+ SESSION_EXECUTION_LOCATION_RESULT_APPLY_RECEIPT_SCHEMA,
34
+ SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_RECEIPT_SCHEMA,
35
+ SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_RECEIPT_SCHEMA_V1,
20
36
  getVerifiedSessionExecutionLocationAuthority,
21
37
  installSessionReplica,
22
38
  installSessionReplicaWithLocationHandoff,
39
+ readVerifiedSessionExecutionLocationResultApply,
40
+ readVerifiedSessionExecutionLocationResultSettlement,
23
41
  readVerifiedTranscriptBytes,
42
+ reserveSessionExecutionLocationResultApply,
43
+ settleSessionExecutionLocationResultApply,
44
+ settleSessionExecutionLocationResultCollection,
24
45
  } from "../harness/jsonl-session-store.js";
46
+ import {
47
+ readStoredExecutionLocationResultBundle,
48
+ storeExecutionLocationResultBundle,
49
+ } from "../lib/execution-location-result-store.js";
50
+ import {
51
+ EXECUTION_LOCATION_RESULT_REVIEW_SCHEMA,
52
+ createExecutionLocationResultReview,
53
+ } from "../lib/execution-location-result-review.js";
54
+ import {
55
+ EXECUTION_LOCATION_RESULT_ARTIFACT_IMPORT_SCHEMA,
56
+ importExecutionLocationResultArtifact,
57
+ } from "../lib/execution-location-result-artifact.js";
58
+ import {
59
+ executeControlledExecutionLocationResultApply,
60
+ terminalExecutionLocationResultApplyTransaction,
61
+ verifyExecutionLocationResultApplySourceGit,
62
+ } from "../lib/execution-location-result-apply.js";
63
+ import { executionBroker } from "../lib/process-execution-broker/index.js";
25
64
  import {
26
65
  sameFileStatIdentity,
27
66
  samePathHandleFileIdentity,
@@ -31,6 +70,8 @@ import {
31
70
  const MAX_HANDOFF_FACTS_BYTES = 1024 * 1024;
32
71
  export const SESSION_EXECUTION_LOCATION_AUTHORITY_SCHEMA =
33
72
  "cc-session-execution-location-authority/v1";
73
+ export const EXECUTION_LOCATION_RESULT_PREVIEW_SCHEMA =
74
+ "cc-execution-location-result-preview/v1";
34
75
 
35
76
  function readHandoffFacts(filePath, deps = {}) {
36
77
  const runtimeFs = deps.fs || fs;
@@ -293,6 +334,24 @@ export function prepareSessionReplicaHandoff(sessionId, options, deps = {}) {
293
334
  if (targetFactsDigest !== String(options.expectedTargetFactsDigest || "")) {
294
335
  throw new Error("target facts changed before location handoff append");
295
336
  }
337
+ if (!/^sha256:[a-f0-9]{64}$/u.test(String(options.attestationDigest || ""))) {
338
+ throw new Error("source target attestation digest is invalid");
339
+ }
340
+ // observedAt is intentionally excluded from targetFactsDigest but included
341
+ // in attestationDigest. The source-side probe and this target-side prepare
342
+ // are separate process invocations, so a real target can never reproduce
343
+ // the source probe's timestamp. Bind the handoff event to this fresh target
344
+ // observation; the source rehashes its receipt and immediately verifies the
345
+ // canonical target projection before it is allowed to resume.
346
+ const targetAttestation = createExecutionLocationTargetAttestation({
347
+ profileDigest: options.profileDigest,
348
+ sourceSessionId: sessionId,
349
+ sourceHeadHash: options.expectedHeadHash,
350
+ sourceEventCount: Number(options.expectedEventCount),
351
+ targetEvidenceId: options.targetEvidenceId,
352
+ baseCommit: binding.source.git.commit,
353
+ binding,
354
+ });
296
355
  return (
297
356
  deps.installSessionReplicaWithLocationHandoff ||
298
357
  installSessionReplicaWithLocationHandoff
@@ -308,12 +367,627 @@ export function prepareSessionReplicaHandoff(sessionId, options, deps = {}) {
308
367
  profileDigest: options.profileDigest,
309
368
  targetEvidenceId: options.targetEvidenceId,
310
369
  targetFactsDigest,
311
- attestationDigest: options.attestationDigest,
370
+ attestationDigest: targetAttestation.attestationDigest,
312
371
  binding,
313
372
  },
314
373
  );
315
374
  }
316
375
 
376
+ function parseResultFileSpec(value, label) {
377
+ const text = String(value || "");
378
+ const separator = text.indexOf("=");
379
+ if (separator <= 0 || separator === text.length - 1) {
380
+ throw new Error(`${label} must be <media-type>=<path>`);
381
+ }
382
+ return {
383
+ mediaType: text.slice(0, separator),
384
+ path: text.slice(separator + 1),
385
+ };
386
+ }
387
+
388
+ function collectResultFileSpec(value, previous) {
389
+ return [...previous, value];
390
+ }
391
+
392
+ function resultBoundary(authority) {
393
+ const root = authority?.binding?.policy?.dataBoundary?.root;
394
+ if (typeof root !== "string" || root.length === 0) {
395
+ throw new Error(
396
+ "verified execution location data boundary is required for result files",
397
+ );
398
+ }
399
+ return root;
400
+ }
401
+
402
+ export function createSessionExecutionLocationResultBundle(
403
+ sessionId,
404
+ options,
405
+ deps = {},
406
+ ) {
407
+ const sessionAuthority = projectSessionExecutionLocation(sessionId, deps);
408
+ const boundaryRoot = resultBoundary(sessionAuthority);
409
+ const readFile =
410
+ deps.readExecutionLocationResultFile || readExecutionLocationResultFile;
411
+ const read = (filePath, fileOptions = {}) =>
412
+ readFile(filePath, {
413
+ boundaryRoot,
414
+ ...fileOptions,
415
+ ...(deps.resultFileDependencies || {}),
416
+ });
417
+ const readItems = (values, label) =>
418
+ (values || []).map((value) => {
419
+ const spec = parseResultFileSpec(value, label);
420
+ return {
421
+ mediaType: spec.mediaType,
422
+ bytes: read(spec.path, { allowEmpty: true }),
423
+ };
424
+ });
425
+ return (
426
+ deps.createExecutionLocationResultBundle ||
427
+ createExecutionLocationResultBundle
428
+ )({
429
+ sessionAuthority,
430
+ resultId: options.resultId,
431
+ summaryBytes: read(options.summary),
432
+ diffBytes: read(options.diff, { allowEmpty: true }),
433
+ artifacts: readItems(options.artifact, "--artifact"),
434
+ evidence: readItems(options.evidence, "--evidence"),
435
+ });
436
+ }
437
+
438
+ export function verifySessionExecutionLocationResultBundle(
439
+ sessionId,
440
+ bundlePath,
441
+ expectedHandoffId,
442
+ deps = {},
443
+ ) {
444
+ const sourceAuthority = projectSessionExecutionLocation(sessionId, deps);
445
+ const boundaryRoot = resultBoundary(sourceAuthority);
446
+ const bundle = (
447
+ deps.readExecutionLocationResultBundle || readExecutionLocationResultBundle
448
+ )(bundlePath, {
449
+ boundaryRoot,
450
+ maxBytes: MAX_EXECUTION_LOCATION_RESULT_BUNDLE_BYTES,
451
+ ...(deps.resultFileDependencies || {}),
452
+ });
453
+ return (
454
+ deps.verifyExecutionLocationResultBundle ||
455
+ verifyExecutionLocationResultBundle
456
+ )({
457
+ bundle,
458
+ sourceAuthority,
459
+ expectedHandoffId,
460
+ });
461
+ }
462
+
463
+ export function collectSessionExecutionLocationResult(
464
+ sessionId,
465
+ target,
466
+ options,
467
+ deps = {},
468
+ ) {
469
+ const profile = (
470
+ deps.readExecutionLocationProfile || readExecutionLocationProfile
471
+ )(options.profile, deps);
472
+ const parseItems = (values, label) =>
473
+ (values || []).map((value) => parseResultFileSpec(value, label));
474
+ const artifacts = parseItems(options.artifact, "--artifact");
475
+ const evidence = parseItems(options.evidence, "--evidence");
476
+ const request = (
477
+ deps.createExecutionLocationTargetResultCollectionRequest ||
478
+ createExecutionLocationTargetResultCollectionRequest
479
+ )({
480
+ requestId: options.requestId,
481
+ sessionId,
482
+ target,
483
+ profile,
484
+ expectedTargetFactsDigest: options.expectedTargetFactsDigest,
485
+ expectedHandoffId: options.expectedHandoffId,
486
+ resultId: options.resultId,
487
+ summaryPath: options.summary,
488
+ diffPath: options.diff,
489
+ artifacts,
490
+ evidence,
491
+ });
492
+ const prior = (
493
+ deps.readVerifiedSessionExecutionLocationResultSettlement ||
494
+ readVerifiedSessionExecutionLocationResultSettlement
495
+ )(sessionId, request.requestId, { requestDigest: request.requestDigest });
496
+ if (prior !== null) {
497
+ if (prior.storage) {
498
+ const bundle = (
499
+ deps.readStoredExecutionLocationResultBundle ||
500
+ readStoredExecutionLocationResultBundle
501
+ )(prior.storage, deps.resultStoreOptions || {});
502
+ const verification = (
503
+ deps.verifyExecutionLocationResultBundle ||
504
+ verifyExecutionLocationResultBundle
505
+ )({
506
+ bundle,
507
+ sourceAuthority: {
508
+ sessionId: prior.sessionId,
509
+ headHash: prior.sourceHeadHash,
510
+ eventCount: prior.sourceEventCount,
511
+ },
512
+ expectedHandoffId: prior.handoffId,
513
+ });
514
+ if (
515
+ verification.verificationDigest !== prior.verificationDigest ||
516
+ bundle.bundleDigest !== prior.bundleDigest
517
+ ) {
518
+ throw new Error("stored result bundle does not match settlement");
519
+ }
520
+ return Object.freeze({
521
+ ...prior,
522
+ settlementAppended: false,
523
+ recovered: true,
524
+ bundleAvailable: true,
525
+ bundle,
526
+ verification,
527
+ });
528
+ }
529
+ return Object.freeze({
530
+ ...prior,
531
+ settlementAppended: false,
532
+ recovered: true,
533
+ bundleAvailable: false,
534
+ });
535
+ }
536
+ const handoff = projectExecutionLocationHandoff(
537
+ sessionId,
538
+ target,
539
+ options.facts,
540
+ deps,
541
+ );
542
+ const readSourceAuthority = () => {
543
+ const authority = (
544
+ deps.getVerifiedSessionExecutionLocationAuthority ||
545
+ getVerifiedSessionExecutionLocationAuthority
546
+ )(sessionId);
547
+ return {
548
+ sessionId: authority.sessionId,
549
+ headHash: authority.headHash,
550
+ eventCount: authority.eventCount,
551
+ };
552
+ };
553
+ const collection = (
554
+ deps.collectExecutionLocationTargetResult ||
555
+ collectExecutionLocationTargetResult
556
+ )(
557
+ {
558
+ requestId: request.requestId,
559
+ handoff,
560
+ profile,
561
+ expectedTargetFactsDigest: options.expectedTargetFactsDigest,
562
+ expectedHandoffId: options.expectedHandoffId,
563
+ resultId: options.resultId,
564
+ summaryPath: options.summary,
565
+ diffPath: options.diff,
566
+ artifacts,
567
+ evidence,
568
+ readSourceAuthority,
569
+ },
570
+ deps,
571
+ );
572
+ if (collection.requestDigest !== request.requestDigest) {
573
+ throw new Error(
574
+ "result collection request digest changed during collection",
575
+ );
576
+ }
577
+ const storage = (
578
+ deps.storeExecutionLocationResultBundle ||
579
+ storeExecutionLocationResultBundle
580
+ )(collection.bundle, deps.resultStoreOptions || {});
581
+ const settlement = (
582
+ deps.settleSessionExecutionLocationResultCollection ||
583
+ settleSessionExecutionLocationResultCollection
584
+ )(sessionId, request.requestId, collection, storage.receipt);
585
+ return Object.freeze({
586
+ ...collection,
587
+ storage: Object.freeze({ ...storage.receipt, stored: storage.stored }),
588
+ settlement,
589
+ });
590
+ }
591
+
592
+ function readSessionExecutionLocationResultReviewAuthority(
593
+ sessionId,
594
+ requestId,
595
+ deps,
596
+ ) {
597
+ const settlement = (
598
+ deps.readVerifiedSessionExecutionLocationResultSettlement ||
599
+ readVerifiedSessionExecutionLocationResultSettlement
600
+ )(sessionId, requestId);
601
+ if (settlement === null) {
602
+ throw new Error("result collection settlement was not found");
603
+ }
604
+ if (!settlement.storage) {
605
+ throw new Error(
606
+ "legacy result settlement has no durable bundle available for review",
607
+ );
608
+ }
609
+ const bundle = (
610
+ deps.readStoredExecutionLocationResultBundle ||
611
+ readStoredExecutionLocationResultBundle
612
+ )(settlement.storage, deps.resultStoreOptions || {});
613
+ const review = (
614
+ deps.createExecutionLocationResultReview ||
615
+ createExecutionLocationResultReview
616
+ )({ settlement, bundle });
617
+ return Object.freeze({ settlement, bundle, review });
618
+ }
619
+
620
+ export function reviewSessionExecutionLocationResult(
621
+ sessionId,
622
+ requestId,
623
+ deps = {},
624
+ ) {
625
+ return readSessionExecutionLocationResultReviewAuthority(
626
+ sessionId,
627
+ requestId,
628
+ deps,
629
+ ).review;
630
+ }
631
+
632
+ function selectResultPreviewRecord(bundle, selectorInput) {
633
+ const selector = String(selectorInput || "");
634
+ if (selector === "summary" || selector === "diff") {
635
+ return { kind: selector, record: bundle[selector] };
636
+ }
637
+ const match = /^(artifact|evidence):(sha256:[a-f0-9]{64})$/u.exec(selector);
638
+ if (!match) {
639
+ throw new Error(
640
+ "result preview item must be summary, diff, artifact:<sha256>, or evidence:<sha256>",
641
+ );
642
+ }
643
+ const [, kind, digest] = match;
644
+ const record = bundle[kind === "artifact" ? "artifacts" : "evidence"].find(
645
+ (entry) => entry.digest === digest,
646
+ );
647
+ if (!record) {
648
+ throw new Error(`reviewed ${kind} digest was not found`);
649
+ }
650
+ return { kind, record };
651
+ }
652
+
653
+ export function previewSessionExecutionLocationResult(
654
+ sessionId,
655
+ requestId,
656
+ reviewDigest,
657
+ item,
658
+ deps = {},
659
+ ) {
660
+ const loaded = readSessionExecutionLocationResultReviewAuthority(
661
+ sessionId,
662
+ requestId,
663
+ deps,
664
+ );
665
+ assertReviewDigest(loaded.review, reviewDigest);
666
+ const selected = selectResultPreviewRecord(loaded.bundle, item);
667
+ const bytes = Buffer.from(selected.record.contentBase64, "base64");
668
+ const reviewedRecord =
669
+ selected.kind === "artifact" || selected.kind === "evidence"
670
+ ? loaded.review[
671
+ selected.kind === "artifact" ? "artifacts" : "evidence"
672
+ ].find((entry) => entry.digest === selected.record.digest)
673
+ : loaded.review[selected.kind];
674
+ if (
675
+ bytes.byteLength !== selected.record.byteLength ||
676
+ reviewedRecord?.digest !== selected.record.digest ||
677
+ reviewedRecord?.byteLength !== selected.record.byteLength ||
678
+ reviewedRecord?.mediaType !== selected.record.mediaType
679
+ ) {
680
+ throw new Error(
681
+ "result preview content no longer matches review authority",
682
+ );
683
+ }
684
+ return Object.freeze({
685
+ schema: EXECUTION_LOCATION_RESULT_PREVIEW_SCHEMA,
686
+ sessionId,
687
+ requestId,
688
+ reviewDigest: loaded.review.reviewDigest,
689
+ item: String(item),
690
+ kind: selected.kind,
691
+ mediaType: selected.record.mediaType,
692
+ byteLength: selected.record.byteLength,
693
+ digest: selected.record.digest,
694
+ bytes,
695
+ });
696
+ }
697
+
698
+ export function importSessionExecutionLocationResultArtifact(
699
+ sessionId,
700
+ requestId,
701
+ reviewDigest,
702
+ item,
703
+ deps = {},
704
+ ) {
705
+ const preview = previewSessionExecutionLocationResult(
706
+ sessionId,
707
+ requestId,
708
+ reviewDigest,
709
+ item,
710
+ deps,
711
+ );
712
+ return (
713
+ deps.importExecutionLocationResultArtifact ||
714
+ importExecutionLocationResultArtifact
715
+ )(preview, { artifactStore: deps.artifactStore });
716
+ }
717
+
718
+ function terminalSafeText(bytes) {
719
+ const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
720
+ return text.replace(
721
+ // The explicit control ranges are the terminal-injection boundary.
722
+ // eslint-disable-next-line no-control-regex
723
+ /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f\u200e\u200f\u202a-\u202e\u2066-\u2069]/gu,
724
+ (character) =>
725
+ character.codePointAt(0) <= 0xff
726
+ ? `\\x${character.codePointAt(0).toString(16).padStart(2, "0")}`
727
+ : `\\u${character.codePointAt(0).toString(16).padStart(4, "0")}`,
728
+ );
729
+ }
730
+
731
+ export function writeSessionExecutionLocationResultPreview(preview, deps = {}) {
732
+ const output = deps.stdout || process.stdout;
733
+ const isTerminal = deps.isTTY ?? output.isTTY === true;
734
+ if (!isTerminal) {
735
+ output.write(preview.bytes);
736
+ return;
737
+ }
738
+ if (!["summary", "diff"].includes(preview.kind)) {
739
+ throw new Error(
740
+ "binary artifact/evidence preview requires redirected stdout",
741
+ );
742
+ }
743
+ output.write(terminalSafeText(preview.bytes));
744
+ }
745
+
746
+ function assertReviewDigest(review, expectedReviewDigest) {
747
+ if (review.reviewDigest !== String(expectedReviewDigest || "")) {
748
+ throw new Error(
749
+ "result apply review digest does not match stored authority",
750
+ );
751
+ }
752
+ }
753
+
754
+ function resultApplyProjection(receipt, options = {}) {
755
+ return Object.freeze({
756
+ ...receipt,
757
+ recovered: options.recovered === true,
758
+ allowed: receipt.applied === true,
759
+ stage: options.stage || (receipt.applied ? "complete" : receipt.status),
760
+ process: options.process || null,
761
+ });
762
+ }
763
+
764
+ function settleResultApplyFromTransaction(
765
+ sessionId,
766
+ applyId,
767
+ transactionState,
768
+ deps,
769
+ options = {},
770
+ ) {
771
+ const terminalTransaction = (
772
+ deps.terminalExecutionLocationResultApplyTransaction ||
773
+ terminalExecutionLocationResultApplyTransaction
774
+ )(transactionState);
775
+ const outcome =
776
+ transactionState.state === "committed" ? "applied" : "rolled_back";
777
+ const receipt = (
778
+ deps.settleSessionExecutionLocationResultApply ||
779
+ settleSessionExecutionLocationResultApply
780
+ )(sessionId, applyId, outcome, terminalTransaction);
781
+ return resultApplyProjection(receipt, {
782
+ recovered: options.recovered,
783
+ stage: options.stage || (outcome === "applied" ? "complete" : "recovery"),
784
+ process: options.process,
785
+ });
786
+ }
787
+
788
+ function readPriorResultApply(sessionId, applyId, deps) {
789
+ return (
790
+ deps.readVerifiedSessionExecutionLocationResultApply ||
791
+ readVerifiedSessionExecutionLocationResultApply
792
+ )(sessionId, applyId);
793
+ }
794
+
795
+ function inspectResultApplyTransaction(receipt, deps) {
796
+ const broker = deps.executionBroker || executionBroker;
797
+ if (typeof broker.inspectWorkspaceTransaction !== "function") {
798
+ throw new Error("result apply transaction inspection is unavailable");
799
+ }
800
+ return broker.inspectWorkspaceTransaction(receipt.transaction.id, {
801
+ ...(deps.transactionStateDir ? { stateDir: deps.transactionStateDir } : {}),
802
+ });
803
+ }
804
+
805
+ export function applySessionExecutionLocationResult(
806
+ sessionId,
807
+ options,
808
+ deps = {},
809
+ ) {
810
+ const loaded = readSessionExecutionLocationResultReviewAuthority(
811
+ sessionId,
812
+ options.requestId,
813
+ deps,
814
+ );
815
+ assertReviewDigest(loaded.review, options.reviewDigest);
816
+ const prior = readPriorResultApply(sessionId, options.applyId, deps);
817
+ if (prior !== null && prior.terminal !== null) {
818
+ if (
819
+ prior.requestId !== options.requestId ||
820
+ prior.reviewDigest !== loaded.review.reviewDigest
821
+ ) {
822
+ throw new Error("result apply id is already bound to different inputs");
823
+ }
824
+ return resultApplyProjection(prior, { recovered: true });
825
+ }
826
+ if (prior !== null) {
827
+ if (
828
+ prior.requestId !== options.requestId ||
829
+ prior.reviewDigest !== loaded.review.reviewDigest
830
+ ) {
831
+ throw new Error("result apply id is already bound to different inputs");
832
+ }
833
+ const transactionState = inspectResultApplyTransaction(prior, deps);
834
+ if (["committed", "rolled_back"].includes(transactionState.state)) {
835
+ return settleResultApplyFromTransaction(
836
+ sessionId,
837
+ options.applyId,
838
+ transactionState,
839
+ deps,
840
+ { recovered: true },
841
+ );
842
+ }
843
+ throw new Error(
844
+ `result apply recovery is required for transaction ${prior.transaction.id}`,
845
+ );
846
+ }
847
+
848
+ const authority = (
849
+ deps.getVerifiedSessionExecutionLocationAuthority ||
850
+ getVerifiedSessionExecutionLocationAuthority
851
+ )(sessionId);
852
+ if (
853
+ authority.headHash !== loaded.settlement.settlementEventHash ||
854
+ authority.eventCount !== loaded.settlement.settlementEventCount
855
+ ) {
856
+ throw new Error("source session advanced after result settlement");
857
+ }
858
+ const broker = deps.executionBroker || executionBroker;
859
+ const source = (
860
+ deps.verifyExecutionLocationResultApplySourceGit ||
861
+ verifyExecutionLocationResultApplySourceGit
862
+ )(authority, {
863
+ broker,
864
+ workspaceRoot: options.workspace,
865
+ platform: deps.platform,
866
+ });
867
+ const diffBytes = Buffer.from(loaded.bundle.diff.contentBase64, "base64");
868
+ const execution = (
869
+ deps.executeControlledExecutionLocationResultApply ||
870
+ executeControlledExecutionLocationResultApply
871
+ )({
872
+ broker,
873
+ sessionId,
874
+ applyId: options.applyId,
875
+ workspaceRoot: source.workspaceRoot,
876
+ diffBytes,
877
+ ...(deps.transactionStateDir ? { stateDir: deps.transactionStateDir } : {}),
878
+ onPrepared: (transaction) => {
879
+ const pinnedSource = (
880
+ deps.verifyExecutionLocationResultApplySourceGit ||
881
+ verifyExecutionLocationResultApplySourceGit
882
+ )(authority, {
883
+ broker,
884
+ workspaceRoot: source.workspaceRoot,
885
+ platform: deps.platform,
886
+ });
887
+ if (
888
+ pinnedSource.sourceGit.rootDigest !== source.sourceGit.rootDigest ||
889
+ pinnedSource.sourceGit.commit !== source.sourceGit.commit
890
+ ) {
891
+ throw new Error("source Git identity changed during apply preparation");
892
+ }
893
+ return (
894
+ deps.reserveSessionExecutionLocationResultApply ||
895
+ reserveSessionExecutionLocationResultApply
896
+ )(
897
+ sessionId,
898
+ options.applyId,
899
+ loaded.review,
900
+ pinnedSource.sourceGit,
901
+ transaction,
902
+ );
903
+ },
904
+ });
905
+ if (execution.stage === "reservation") {
906
+ const reserved = readPriorResultApply(sessionId, options.applyId, deps);
907
+ if (reserved === null) throw execution.error;
908
+ if (
909
+ reserved.reviewDigest !== loaded.review.reviewDigest ||
910
+ reserved.transaction.id !== execution.transaction.id
911
+ ) {
912
+ throw new Error("result apply reservation response is ambiguous");
913
+ }
914
+ }
915
+ const receipt = (
916
+ deps.settleSessionExecutionLocationResultApply ||
917
+ settleSessionExecutionLocationResultApply
918
+ )(sessionId, options.applyId, execution.outcome, execution.transaction);
919
+ return resultApplyProjection(receipt, {
920
+ stage: execution.stage,
921
+ process: execution.process,
922
+ });
923
+ }
924
+
925
+ export function recoverSessionExecutionLocationResultApply(
926
+ sessionId,
927
+ options,
928
+ deps = {},
929
+ ) {
930
+ const loaded = readSessionExecutionLocationResultReviewAuthority(
931
+ sessionId,
932
+ options.requestId,
933
+ deps,
934
+ );
935
+ assertReviewDigest(loaded.review, options.reviewDigest);
936
+ const prior = readPriorResultApply(sessionId, options.applyId, deps);
937
+ if (prior === null) {
938
+ throw new Error("result apply reservation was not found");
939
+ }
940
+ if (
941
+ prior.requestId !== options.requestId ||
942
+ prior.reviewDigest !== loaded.review.reviewDigest
943
+ ) {
944
+ throw new Error("result apply recovery authority does not match review");
945
+ }
946
+ if (prior.terminal !== null) {
947
+ return resultApplyProjection(prior, { recovered: true });
948
+ }
949
+ const broker = deps.executionBroker || executionBroker;
950
+ const authority = (
951
+ deps.getVerifiedSessionExecutionLocationAuthority ||
952
+ getVerifiedSessionExecutionLocationAuthority
953
+ )(sessionId);
954
+ const source = (
955
+ deps.verifyExecutionLocationResultApplySourceGit ||
956
+ verifyExecutionLocationResultApplySourceGit
957
+ )(authority, {
958
+ broker,
959
+ workspaceRoot: options.workspace,
960
+ platform: deps.platform,
961
+ });
962
+ let transactionState = inspectResultApplyTransaction(prior, deps);
963
+ if (!["committed", "rolled_back"].includes(transactionState.state)) {
964
+ if (typeof broker.recoverWorkspaceTransactions !== "function") {
965
+ throw new Error("result apply workspace recovery is unavailable");
966
+ }
967
+ broker.recoverWorkspaceTransactions({
968
+ id: prior.transaction.id,
969
+ workspaceRoot: source.workspaceRoot,
970
+ reason: "explicit session result apply recovery",
971
+ ...(deps.transactionStateDir
972
+ ? { stateDir: deps.transactionStateDir }
973
+ : {}),
974
+ });
975
+ transactionState = inspectResultApplyTransaction(prior, deps);
976
+ }
977
+ if (!["committed", "rolled_back"].includes(transactionState.state)) {
978
+ throw new Error(
979
+ `result apply transaction still requires manual recovery: ${transactionState.state}`,
980
+ );
981
+ }
982
+ return settleResultApplyFromTransaction(
983
+ sessionId,
984
+ options.applyId,
985
+ transactionState,
986
+ deps,
987
+ { recovered: true, stage: "recovery" },
988
+ );
989
+ }
990
+
317
991
  function renderBinding(binding) {
318
992
  const git = binding.source.git;
319
993
  return [
@@ -350,6 +1024,57 @@ function writeProjection(projection, options = {}) {
350
1024
  );
351
1025
  return;
352
1026
  }
1027
+ if (projection.schema === EXECUTION_LOCATION_RESULT_BUNDLE_SCHEMA) {
1028
+ process.stdout.write(
1029
+ `RESULT BUNDLE ${projection.resultId}\nBundle: ${projection.bundleDigest}\nBytes: ${projection.totalBytes}\nUse --json to transfer the canonical bundle bytes.\n`,
1030
+ );
1031
+ return;
1032
+ }
1033
+ if (projection.schema === EXECUTION_LOCATION_RESULT_VERIFICATION_SCHEMA) {
1034
+ process.stdout.write(
1035
+ `RESULT VERIFIED ${projection.resultId}\nBundle: ${projection.bundleDigest}\nVerification: ${projection.verificationDigest}\nApplied: no\n`,
1036
+ );
1037
+ return;
1038
+ }
1039
+ if (projection.schema === EXECUTION_LOCATION_RESULT_REVIEW_SCHEMA) {
1040
+ process.stdout.write(
1041
+ `RESULT REVIEWED ${projection.resultId}\nReview: ${projection.reviewDigest}\nBundle: ${projection.bundleDigest}\nSummary: ${projection.summary.byteLength} bytes (${projection.summary.digest})\nDiff: ${projection.diff.byteLength} bytes (${projection.diff.digest})\nApplied: no\n`,
1042
+ );
1043
+ return;
1044
+ }
1045
+ if (projection.schema === EXECUTION_LOCATION_RESULT_ARTIFACT_IMPORT_SCHEMA) {
1046
+ process.stdout.write(
1047
+ `RESULT ARTIFACT ${projection.imported ? "IMPORTED" : "AVAILABLE"} ${projection.artifact.id}\nImport: ${projection.importDigest}\nReview: ${projection.source.reviewDigest}\nItem: ${projection.source.item}\nArtifact bytes: ${projection.artifact.size} (${projection.source.sourceDigest})\nContent emitted: no\n`,
1048
+ );
1049
+ return;
1050
+ }
1051
+ if (
1052
+ projection.schema === SESSION_EXECUTION_LOCATION_RESULT_APPLY_RECEIPT_SCHEMA
1053
+ ) {
1054
+ process.stdout.write(
1055
+ `RESULT APPLY ${projection.applied ? "APPLIED" : "ROLLED BACK"} ${projection.applyId}\nReview: ${projection.reviewDigest}\nTransaction: ${projection.transaction.id}\nEvidence: ${projection.transaction.evidenceDigest || "pending"}\nRecovered: ${projection.recovered ? "yes" : "no"}\n`,
1056
+ );
1057
+ return;
1058
+ }
1059
+ if (
1060
+ projection.schema === EXECUTION_LOCATION_TARGET_RESULT_COLLECTION_SCHEMA
1061
+ ) {
1062
+ process.stdout.write(
1063
+ `RESULT COLLECTED ${projection.resultId}\nBundle: ${projection.bundleDigest}\nCollection: ${projection.collectionDigest}\nApplied: no\nGaps: ${projection.gaps.join(", ")}\n`,
1064
+ );
1065
+ return;
1066
+ }
1067
+ if (
1068
+ [
1069
+ SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_RECEIPT_SCHEMA,
1070
+ SESSION_EXECUTION_LOCATION_RESULT_COLLECTION_RECEIPT_SCHEMA_V1,
1071
+ ].includes(projection.schema)
1072
+ ) {
1073
+ process.stdout.write(
1074
+ `RESULT COLLECTION SETTLED ${projection.resultId}\nRequest: ${projection.requestId}\nSettlement: ${projection.receiptDigest}\nBundle bytes available: ${projection.bundleAvailable ? "yes" : "no"}\nApplied: no\n`,
1075
+ );
1076
+ return;
1077
+ }
353
1078
  if (projection.schema === "chainlesschain.session-replica-install/v1") {
354
1079
  process.stdout.write(
355
1080
  `${projection.installed ? "INSTALLED" : "ALREADY PRESENT"} ${projection.sessionId}\nReceipt: ${projection.receiptDigest}\n`,
@@ -399,6 +1124,16 @@ function runAction(action, options = {}) {
399
1124
  }
400
1125
  }
401
1126
 
1127
+ function runPreviewAction(action, deps = {}) {
1128
+ try {
1129
+ writeSessionExecutionLocationResultPreview(action(), deps);
1130
+ return 0;
1131
+ } catch (error) {
1132
+ process.stderr.write(`Execution location failed: ${error.message}\n`);
1133
+ return 1;
1134
+ }
1135
+ }
1136
+
402
1137
  export function registerSessionLocationSubcommands(session, deps = {}) {
403
1138
  const location = session
404
1139
  .command("location")
@@ -584,4 +1319,236 @@ export function registerSessionLocationSubcommands(session, deps = {}) {
584
1319
  options,
585
1320
  );
586
1321
  });
1322
+
1323
+ location
1324
+ .command("result-pack <id>")
1325
+ .description(
1326
+ "Build a bounded result bundle from a verified target handoff session",
1327
+ )
1328
+ .requiredOption("--result-id <id>", "Stable result bundle id")
1329
+ .requiredOption(
1330
+ "--summary <path>",
1331
+ "UTF-8 summary file inside the data boundary",
1332
+ )
1333
+ .requiredOption("--diff <path>", "Diff file inside the data boundary")
1334
+ .option(
1335
+ "--artifact <media-type=path>",
1336
+ "Artifact bytes to include (repeatable)",
1337
+ collectResultFileSpec,
1338
+ [],
1339
+ )
1340
+ .option(
1341
+ "--evidence <media-type=path>",
1342
+ "Evidence bytes to include (repeatable)",
1343
+ collectResultFileSpec,
1344
+ [],
1345
+ )
1346
+ .option("--json", "Write the canonical bundle including base64 content")
1347
+ .action((id, options) => {
1348
+ process.exitCode = runAction(
1349
+ () => createSessionExecutionLocationResultBundle(id, options, deps),
1350
+ options,
1351
+ );
1352
+ });
1353
+
1354
+ location
1355
+ .command("result-verify <id>")
1356
+ .description(
1357
+ "Rehash a returned bundle and bind it to the unchanged source session",
1358
+ )
1359
+ .requiredOption("--bundle <path>", "Returned canonical bundle JSON")
1360
+ .requiredOption(
1361
+ "--expected-handoff-id <sha256>",
1362
+ "Exact handoff id accepted before target execution",
1363
+ )
1364
+ .option("--json", "Machine-readable content-free verification receipt")
1365
+ .action((id, options) => {
1366
+ process.exitCode = runAction(
1367
+ () =>
1368
+ verifySessionExecutionLocationResultBundle(
1369
+ id,
1370
+ options.bundle,
1371
+ options.expectedHandoffId,
1372
+ deps,
1373
+ ),
1374
+ options,
1375
+ );
1376
+ });
1377
+
1378
+ location
1379
+ .command("result-collect <id> <target>")
1380
+ .description(
1381
+ "Fetch a target result through the fixed transport and verify it on source",
1382
+ )
1383
+ .requiredOption("--facts <path>", "Accepted handoff facts JSON")
1384
+ .requiredOption("--profile <path>", "Secret-free target profile JSON")
1385
+ .requiredOption(
1386
+ "--expected-target-facts-digest <sha256>",
1387
+ "Exact stable target facts digest accepted before execution",
1388
+ )
1389
+ .requiredOption(
1390
+ "--expected-handoff-id <sha256>",
1391
+ "Exact canonical target handoff id",
1392
+ )
1393
+ .requiredOption(
1394
+ "--request-id <id>",
1395
+ "Stable idempotency id for canonical collection settlement",
1396
+ )
1397
+ .requiredOption("--result-id <id>", "Stable result bundle id")
1398
+ .requiredOption("--summary <path>", "Target summary path")
1399
+ .requiredOption("--diff <path>", "Target diff path")
1400
+ .option(
1401
+ "--artifact <media-type=path>",
1402
+ "Target artifact bytes to include (repeatable)",
1403
+ collectResultFileSpec,
1404
+ [],
1405
+ )
1406
+ .option(
1407
+ "--evidence <media-type=path>",
1408
+ "Target evidence bytes to include (repeatable)",
1409
+ collectResultFileSpec,
1410
+ [],
1411
+ )
1412
+ .option(
1413
+ "--json",
1414
+ "Machine-readable collection with bundle bytes and verification receipt",
1415
+ )
1416
+ .action((id, target, options) => {
1417
+ process.exitCode = runAction(
1418
+ () => collectSessionExecutionLocationResult(id, target, options, deps),
1419
+ options,
1420
+ );
1421
+ });
1422
+
1423
+ location
1424
+ .command("result-review <id>")
1425
+ .description(
1426
+ "Review stored result metadata without exposing or applying content",
1427
+ )
1428
+ .requiredOption(
1429
+ "--request-id <id>",
1430
+ "Canonical result collection request id",
1431
+ )
1432
+ .option("--json", "Machine-readable content-free review authority")
1433
+ .action((id, options) => {
1434
+ process.exitCode = runAction(
1435
+ () => reviewSessionExecutionLocationResult(id, options.requestId, deps),
1436
+ options,
1437
+ );
1438
+ });
1439
+
1440
+ location
1441
+ .command("result-preview <id>")
1442
+ .description(
1443
+ "Explicitly stream one reviewed result item without changing the workspace",
1444
+ )
1445
+ .requiredOption(
1446
+ "--request-id <id>",
1447
+ "Canonical result collection request id",
1448
+ )
1449
+ .requiredOption(
1450
+ "--review-digest <sha256>",
1451
+ "Exact content-free review digest accepted by the operator",
1452
+ )
1453
+ .requiredOption(
1454
+ "--item <selector>",
1455
+ "summary, diff, artifact:<sha256>, or evidence:<sha256>",
1456
+ )
1457
+ .action((id, options) => {
1458
+ process.exitCode = runPreviewAction(
1459
+ () =>
1460
+ previewSessionExecutionLocationResult(
1461
+ id,
1462
+ options.requestId,
1463
+ options.reviewDigest,
1464
+ options.item,
1465
+ deps,
1466
+ ),
1467
+ deps.previewOutputDependencies || {},
1468
+ );
1469
+ });
1470
+
1471
+ location
1472
+ .command("result-import <id>")
1473
+ .description(
1474
+ "Import one explicitly reviewed result item into the managed ArtifactStore",
1475
+ )
1476
+ .requiredOption(
1477
+ "--request-id <id>",
1478
+ "Canonical result collection request id",
1479
+ )
1480
+ .requiredOption(
1481
+ "--review-digest <sha256>",
1482
+ "Exact content-free review digest accepted by the operator",
1483
+ )
1484
+ .requiredOption(
1485
+ "--item <selector>",
1486
+ "summary, diff, artifact:<sha256>, or evidence:<sha256>",
1487
+ )
1488
+ .option("--json", "Machine-readable content-free import receipt")
1489
+ .action((id, options) => {
1490
+ process.exitCode = runAction(
1491
+ () =>
1492
+ importSessionExecutionLocationResultArtifact(
1493
+ id,
1494
+ options.requestId,
1495
+ options.reviewDigest,
1496
+ options.item,
1497
+ deps,
1498
+ ),
1499
+ options,
1500
+ );
1501
+ });
1502
+
1503
+ location
1504
+ .command("result-apply <id>")
1505
+ .description(
1506
+ "Apply one explicitly reviewed stored diff inside a durable workspace transaction",
1507
+ )
1508
+ .requiredOption(
1509
+ "--request-id <id>",
1510
+ "Canonical result collection request id",
1511
+ )
1512
+ .requiredOption("--apply-id <id>", "Stable result apply idempotency id")
1513
+ .requiredOption(
1514
+ "--review-digest <sha256>",
1515
+ "Exact content-free review digest accepted by the operator",
1516
+ )
1517
+ .option(
1518
+ "--workspace <path>",
1519
+ "Exact source Git workspace (defaults to session authority)",
1520
+ )
1521
+ .option("--json", "Machine-readable content-free apply receipt")
1522
+ .action((id, options) => {
1523
+ process.exitCode = runAction(
1524
+ () => applySessionExecutionLocationResult(id, options, deps),
1525
+ options,
1526
+ );
1527
+ });
1528
+
1529
+ location
1530
+ .command("result-apply-recover <id>")
1531
+ .description(
1532
+ "Explicitly recover a reserved result apply without replaying its diff",
1533
+ )
1534
+ .requiredOption(
1535
+ "--request-id <id>",
1536
+ "Canonical result collection request id",
1537
+ )
1538
+ .requiredOption("--apply-id <id>", "Reserved result apply id")
1539
+ .requiredOption(
1540
+ "--review-digest <sha256>",
1541
+ "Exact content-free review digest bound to the reservation",
1542
+ )
1543
+ .option(
1544
+ "--workspace <path>",
1545
+ "Exact source Git workspace (defaults to session authority)",
1546
+ )
1547
+ .option("--json", "Machine-readable content-free recovery receipt")
1548
+ .action((id, options) => {
1549
+ process.exitCode = runAction(
1550
+ () => recoverSessionExecutionLocationResultApply(id, options, deps),
1551
+ options,
1552
+ );
1553
+ });
587
1554
  }