chainlesschain 0.162.188 → 0.162.193

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 (337) hide show
  1. package/README.md +61 -11
  2. package/bin/chainlesschain.js +7 -52
  3. package/completions/_cc +209 -0
  4. package/completions/cc.bash +18 -0
  5. package/completions/cc.fish +13 -0
  6. package/completions/cc.ps1 +226 -0
  7. package/package.json +10 -2
  8. package/src/assets/web-panel/assets/{AIOps-Brr1LVcE.js → AIOps-DBLkaTje.js} +1 -1
  9. package/src/assets/web-panel/assets/{ActionButton-DQU74DKG.js → ActionButton-BAy-Qebo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Analytics-CYp9178y.js → Analytics-Dfb1Mlau.js} +3 -3
  11. package/src/assets/web-panel/assets/{AppLayout-DW4SCYsW.js → AppLayout-BbFkN8m0.js} +5 -5
  12. package/src/assets/web-panel/assets/{Artifacts-CYlD_ed1.js → Artifacts-kM4-cEEH.js} +1 -1
  13. package/src/assets/web-panel/assets/{Audit-CWl1rZOi.js → Audit-BSQfYWf3.js} +1 -1
  14. package/src/assets/web-panel/assets/{BackgroundAgents-BOR-LPsa.js → BackgroundAgents-CWDbI_fG.js} +1 -1
  15. package/src/assets/web-panel/assets/{Backup-DLpG7j1X.js → Backup-BxLPbq_Q.js} +1 -1
  16. package/src/assets/web-panel/assets/{BaseInput-B35K9wdr.js → BaseInput-DuIbdrp6.js} +1 -1
  17. package/src/assets/web-panel/assets/{Chat-CwUJb9gB.js → Chat-NEmjGahU.js} +5 -5
  18. package/src/assets/web-panel/assets/{ChatBubbleRenderer-1v6aMS1m.js → ChatBubbleRenderer-DfJEo-5_.js} +1 -1
  19. package/src/assets/web-panel/assets/{Checkbox-pi3-tPNW.js → Checkbox-CaoeG3Ns.js} +1 -1
  20. package/src/assets/web-panel/assets/{Codegen-FyNF35eL.js → Codegen-BFf_g3xY.js} +1 -1
  21. package/src/assets/web-panel/assets/{Col-tGt_JDEr.js → Col-CNOd8mdQ.js} +1 -1
  22. package/src/assets/web-panel/assets/{Community-CC7LonQX.js → Community-BhpDqz-i.js} +1 -1
  23. package/src/assets/web-panel/assets/{Compact-BGXrHHjE.js → Compact-CQ42T7Z6.js} +1 -1
  24. package/src/assets/web-panel/assets/{Compliance-DSW0TBZ8.js → Compliance-DI5PcLMN.js} +1 -1
  25. package/src/assets/web-panel/assets/{Cowork-Bhk7rbvE.js → Cowork-wYYZe0wR.js} +3 -3
  26. package/src/assets/web-panel/assets/{Cron-DxyiQ2NZ.js → Cron-Dlq03DD_.js} +2 -2
  27. package/src/assets/web-panel/assets/{Crosschain-B2ZkxHok.js → Crosschain-BzqS8PP3.js} +1 -1
  28. package/src/assets/web-panel/assets/{DID-yOJV99eJ.js → DID-It55Yem7.js} +2 -2
  29. package/src/assets/web-panel/assets/{Dashboard-CKsttz7D.js → Dashboard-9HkH6oxn.js} +2 -2
  30. package/src/assets/web-panel/assets/{Dropdown-CVFldXSL.js → Dropdown-00e2YWRB.js} +1 -1
  31. package/src/assets/web-panel/assets/{EmailListRenderer-Bufv638J.js → EmailListRenderer-By-ugRDL.js} +1 -1
  32. package/src/assets/web-panel/assets/{FamilyGuardDashboard-4ncjoIjL.js → FamilyGuardDashboard-C396yu5m.js} +1 -1
  33. package/src/assets/web-panel/assets/{Federation-DsknEDoX.js → Federation-BME5sbZY.js} +1 -1
  34. package/src/assets/web-panel/assets/{FormItemContext-Cqe5jWXA.js → FormItemContext-B4TEZCr-.js} +1 -1
  35. package/src/assets/web-panel/assets/{GenericCardRenderer-NAJaFKxc.js → GenericCardRenderer-_9CX9ieY.js} +1 -1
  36. package/src/assets/web-panel/assets/{Git-CszKQpnl.js → Git-BrS6WVSr.js} +2 -2
  37. package/src/assets/web-panel/assets/{Governance-BXGodXi6.js → Governance-BMdCWnKF.js} +1 -1
  38. package/src/assets/web-panel/assets/{Inference-CkoYuG2c.js → Inference-Bcp3vzcA.js} +1 -1
  39. package/src/assets/web-panel/assets/{KnowledgeGraph-DFlEr_T0.js → KnowledgeGraph-DlLuqGY5.js} +1 -1
  40. package/src/assets/web-panel/assets/{Logs-CVaENddA.js → Logs-D-W_6x09.js} +2 -2
  41. package/src/assets/web-panel/assets/MarkdownRenderer-DElGPxCZ.js +1 -0
  42. package/src/assets/web-panel/assets/{Marketplace-CDlLT0fw.js → Marketplace-Dzn2guvI.js} +1 -1
  43. package/src/assets/web-panel/assets/{McpTools-DdwOyszN.js → McpTools-uPict-KL.js} +6 -6
  44. package/src/assets/web-panel/assets/{Memory-DKQnkKuG.js → Memory-BCw43kOb.js} +2 -2
  45. package/src/assets/web-panel/assets/{MobileBridge-DGseqlzJ.js → MobileBridge-DmV8Wv7F.js} +1 -1
  46. package/src/assets/web-panel/assets/{MobileProjects-COBbEOlj.js → MobileProjects-C-HaCmSM.js} +1 -1
  47. package/src/assets/web-panel/assets/{Mtc-O61Vwyli.js → Mtc-C6jxJ34Y.js} +5 -5
  48. package/src/assets/web-panel/assets/{MtcAudit-Dw2SyasS.js → MtcAudit-Za8ExwhQ.js} +5 -5
  49. package/src/assets/web-panel/assets/{Multisig-hSu_l8kf.js → Multisig-KKDbuEgb.js} +3 -3
  50. package/src/assets/web-panel/assets/{NLProgramming-CX1Epurr.js → NLProgramming-Dj97zbCk.js} +1 -1
  51. package/src/assets/web-panel/assets/{Notes-R9xX8o8_.js → Notes-DBXvMraU.js} +4 -4
  52. package/src/assets/web-panel/assets/{NotificationSettings-jtSNLCuK.js → NotificationSettings-DOxITLYl.js} +1 -1
  53. package/src/assets/web-panel/assets/OrderTableRenderer-7DVjZwMM.js +1 -0
  54. package/src/assets/web-panel/assets/{Organization-Pu2WO-U3.js → Organization-D1i73mjb.js} +4 -4
  55. package/src/assets/web-panel/assets/{Overflow-BjnqUyFp.js → Overflow-kW6Q3rvg.js} +1 -1
  56. package/src/assets/web-panel/assets/{P2P-jjkvz44c.js → P2P-C-v_8p2v.js} +2 -2
  57. package/src/assets/web-panel/assets/PdhVaultBrowser-tUbbY64W.js +7 -0
  58. package/src/assets/web-panel/assets/{Permissions-D4yDpivd.js → Permissions-DkHxEZ58.js} +4 -4
  59. package/src/assets/web-panel/assets/{PersonalDataHub-0qsL6iH1.js → PersonalDataHub-DWuMPGrK.js} +5 -5
  60. package/src/assets/web-panel/assets/{Pipeline-Cx7Ybrk2.js → Pipeline-30IYXWWm.js} +1 -1
  61. package/src/assets/web-panel/assets/{Privacy-PbfR_M_V.js → Privacy-DZNQ4RrH.js} +1 -1
  62. package/src/assets/web-panel/assets/{ProjectInit-CyV6Gsub.js → ProjectInit-De2MCElf.js} +2 -2
  63. package/src/assets/web-panel/assets/{ProjectSettings-C7KZ2Wdk.js → ProjectSettings-5uHk9wsC.js} +2 -2
  64. package/src/assets/web-panel/assets/{Projects-DQDjO-yK.js → Projects-XjDfrFLb.js} +1 -1
  65. package/src/assets/web-panel/assets/{Providers-DyFVBBMX.js → Providers-Bgwj6gcE.js} +1 -1
  66. package/src/assets/web-panel/assets/{QrScannerModal-CzB1BC9_.js → QrScannerModal-gKql9umv.js} +1 -1
  67. package/src/assets/web-panel/assets/{QuickAsk-Bk636mC1.js → QuickAsk-BWvmwkh7.js} +1 -1
  68. package/src/assets/web-panel/assets/{Recommend-DoWxHIT3.js → Recommend-Uok4hZPd.js} +1 -1
  69. package/src/assets/web-panel/assets/{RemoteSession-oOVIv9wq.js → RemoteSession-DLJzTk9a.js} +3 -3
  70. package/src/assets/web-panel/assets/{Reputation-BucoReGG.js → Reputation-ZVwIPMSO.js} +1 -1
  71. package/src/assets/web-panel/assets/{Row-DzmOdJU7.js → Row-CN04HxWR.js} +1 -1
  72. package/src/assets/web-panel/assets/{RssFeed-C1tK7KGU.js → RssFeed-BdSrEG4g.js} +3 -3
  73. package/src/assets/web-panel/assets/{Search-CSnInOqk.js → Search-5PwVd0IR.js} +1 -1
  74. package/src/assets/web-panel/assets/{Security-dlejr15l.js → Security-DdBo4zjN.js} +3 -3
  75. package/src/assets/web-panel/assets/{Services-BioPZuNh.js → Services-D3letU7M.js} +2 -2
  76. package/src/assets/web-panel/assets/{Skeleton-DWMibwpC.js → Skeleton--Jb83f1v.js} +1 -1
  77. package/src/assets/web-panel/assets/{Skills-BAAnx1B2.js → Skills-Bg-CulHX.js} +1 -1
  78. package/src/assets/web-panel/assets/{Sla-jWNp4hNO.js → Sla-7QOa7S-X.js} +1 -1
  79. package/src/assets/web-panel/assets/{SpeechSettings-y5kqKha-.js → SpeechSettings-DQwppjRw.js} +1 -1
  80. package/src/assets/web-panel/assets/{SyncSettings-B9GNsc3e.js → SyncSettings-dNPQGL-s.js} +2 -2
  81. package/src/assets/web-panel/assets/{Tasks-BDBYKRen.js → Tasks-Ggs-Z48q.js} +1 -1
  82. package/src/assets/web-panel/assets/{Templates-DRiE5eaN.js → Templates-78TYHgRO.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tenant-BGlAvExF.js → Tenant-xHwwv9vO.js} +1 -1
  84. package/src/assets/web-panel/assets/{Terminal-B8uzrbNY.js → Terminal-BJXSJfm4.js} +2 -2
  85. package/src/assets/web-panel/assets/{TimelineRenderer-Df48iveY.js → TimelineRenderer-fLbjRhJw.js} +1 -1
  86. package/src/assets/web-panel/assets/{Tokens-CcmHndN6.js → Tokens-oMSBSBmB.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trigger-DPkWxmQ2.js → Trigger-CfnY_wX_.js} +1 -1
  88. package/src/assets/web-panel/assets/{Trust-DTb5a5AV.js → Trust-AdyTgYKO.js} +1 -1
  89. package/src/assets/web-panel/assets/{UkeySign-CBmg5vch.js → UkeySign-C5K_81dS.js} +1 -1
  90. package/src/assets/web-panel/assets/{VideoEditing-B0mZrz4O.js → VideoEditing-vcGVDqki.js} +1 -1
  91. package/src/assets/web-panel/assets/{Wallet-Bxs7_mpd.js → Wallet-hhOc3hlY.js} +4 -4
  92. package/src/assets/web-panel/assets/{WebAuthn-C8x3cMxU.js → WebAuthn-CVloC11s.js} +3 -3
  93. package/src/assets/web-panel/assets/{WorkflowEditor-DPrNznrP.js → WorkflowEditor-CYeE32R5.js} +1 -1
  94. package/src/assets/web-panel/assets/{chat-D3bYWu7S.js → chat-CNROR5bN.js} +1 -1
  95. package/src/assets/web-panel/assets/{colors-DY-PwMu4.js → colors-Cjx-cnwU.js} +1 -1
  96. package/src/assets/web-panel/assets/{compact-item-LDk10Kw6.js → compact-item-DOIfelvD.js} +1 -1
  97. package/src/assets/web-panel/assets/{createContext-C-2MZnFq.js → createContext-DfA7UZ8u.js} +1 -1
  98. package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +1 -0
  99. package/src/assets/web-panel/assets/{hasIn-BQIBjcnB.js → hasIn-BMSCzcfM.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CQVb2dWp.js → index-5-HXgOX5.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BdXnYMCZ.js → index-AWg-0M1S.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cx6D_dx2.js → index-B4iYzpkL.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-_HRO_cIu.js → index-B5Udeb_6.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DlRYqt3S.js → index-B7gf77CJ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BrnRO9yE.js → index-BEMwBBHk.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-VCh5zNJo.js → index-BM1y_9hM.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BRI3ngNg.js → index-BUonmKSE.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C3GNvExG.js → index-BbQ2eQ8H.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DSvo_bp0.js → index-BemJ2u_E.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-L6qixyLc.js → index-BolaOQxx.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BI4KgcYC.js → index-BxOk9vkG.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CY4KnaO9.js → index-By61ojUx.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-L3smcoQX.js → index-C2K9SNVX.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BX2b9Orc.js → index-C3L5gdiD.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Cz4b6Z_7.js → index-C7xn0Nub.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-COG61sRv.js → index-CAnvhwg6.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C7FC8cP2.js → index-CEKMcOyU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BN-xdSWZ.js → index-CNC5onm4.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DY2FIrmz.js → index-CVL27kXC.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CiTvBAr-.js → index-CVm1_i3t.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DhRt9cYJ.js → index-CdYBye8B.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B5pgtZnY.js → index-ClNMrqEY.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-7xKu7Fns.js → index-Cs6l7uRu.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D4K1weKc.js → index-CshQbilz.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-k7C_oDCO.js → index-Cyweh0Hy.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D3Oq-DLL.js → index-DBpWXFed.js} +3 -3
  127. package/src/assets/web-panel/assets/{index-DYyLJPlF.js → index-DHtpHZAQ.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Dh-tkpKQ.js → index-DLmn0BoK.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-8JC9BJa1.js → index-DPAWBrMf.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Dd2Km97U.js → index-DjEsxO5h.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-KFZO_lcx.js → index-FBc_CJBd.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DTIZpPtG.js → index-Icdoqmzt.js} +1 -1
  133. package/src/assets/web-panel/assets/index-Q2IajL54.js +1 -0
  134. package/src/assets/web-panel/assets/index-bRkHgOMc.js +1 -0
  135. package/src/assets/web-panel/assets/{index-lmm9p-jm.js → index-dCd8cSUq.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-HasPt4-h.js → index-m2vG9gG_.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-CaslYch6.js → index-mTpHoEzr.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-CbR6ROOa.js → index-ti_lnTWl.js} +1 -1
  139. package/src/assets/web-panel/assets/{initDefaultProps-zQPSHf2C.js → initDefaultProps-Bu8k7H1Y.js} +1 -1
  140. package/src/assets/web-panel/assets/{motion-CKCStGVk.js → motion-s3iVK41k.js} +1 -1
  141. package/src/assets/web-panel/assets/{move-BufVDGYF.js → move-B6B-E5Jz.js} +1 -1
  142. package/src/assets/web-panel/assets/{mtc-parser-DcaFxy5D.js → mtc-parser-BiYgTidA.js} +1 -1
  143. package/src/assets/web-panel/assets/{omit-EScpkGdo.js → omit-pU1RdUDA.js} +1 -1
  144. package/src/assets/web-panel/assets/{pickAttrs-72hG_qfT.js → pickAttrs-Cdoq_SeM.js} +1 -1
  145. package/src/assets/web-panel/assets/{placementArrow-CMFWiH20.js → placementArrow-DIuvAn2K.js} +1 -1
  146. package/src/assets/web-panel/assets/{responsiveObserve-DKQHS41p.js → responsiveObserve-8w16YR2D.js} +1 -1
  147. package/src/assets/web-panel/assets/{slide-QVAFHTIQ.js → slide-VZ01cZe3.js} +1 -1
  148. package/src/assets/web-panel/assets/{statusUtils-DIz38e2G.js → statusUtils-lh8YMN8Z.js} +1 -1
  149. package/src/assets/web-panel/assets/{styleChecker-zK5cyLby.js → styleChecker-CmDyreec.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFlexGapSupport-DhZngk62.js → useFlexGapSupport-hiJWMU5y.js} +1 -1
  151. package/src/assets/web-panel/assets/{useFs-BvV2cvkg.js → useFs-Thnu-Iaj.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-CRmxb9l3.js → usePersonalDataHub-LBdOxjwY.js} +1 -1
  153. package/src/assets/web-panel/assets/{vnode-CgQIbobP.js → vnode-Cg6lFY_X.js} +1 -1
  154. package/src/assets/web-panel/assets/{zoom-D4XrrO0R.js → zoom-DVfsR1YO.js} +1 -1
  155. package/src/assets/web-panel/index.html +1 -1
  156. package/src/cli-help.js +181 -0
  157. package/src/command-help-index.json +181 -0
  158. package/src/command-manifest.json +1107 -175
  159. package/src/command-surface-policy.js +197 -0
  160. package/src/commands/agent.js +98 -33
  161. package/src/commands/artifacts.js +400 -2
  162. package/src/commands/background-session.js +41 -3
  163. package/src/commands/checkpoint-managed.js +1059 -0
  164. package/src/commands/checkpoint-restore-recovery.js +1476 -0
  165. package/src/commands/checkpoint.js +950 -22
  166. package/src/commands/compact.js +101 -25
  167. package/src/commands/config.js +506 -20
  168. package/src/commands/doctor.js +4 -1
  169. package/src/commands/hub.js +1 -1
  170. package/src/commands/mcp.js +688 -24
  171. package/src/commands/pack.js +16 -2
  172. package/src/commands/plugin.js +20 -12
  173. package/src/commands/session-mcp-recovery.js +218 -0
  174. package/src/commands/session.js +470 -110
  175. package/src/commands/setup.js +36 -10
  176. package/src/commands/skill.js +181 -110
  177. package/src/commands/status.js +21 -5
  178. package/src/commands/team-distributed.js +3324 -0
  179. package/src/commands/team.js +1130 -74
  180. package/src/commands/update.js +68 -6
  181. package/src/constants.js +11 -0
  182. package/src/data/changelog.json +26 -0
  183. package/src/gateways/ws/action-protocol.js +10 -0
  184. package/src/gateways/ws/session-protocol.js +555 -27
  185. package/src/gateways/ws/ws-agent-handler.js +541 -14
  186. package/src/gateways/ws/ws-session-gateway.js +129 -22
  187. package/src/gateways/ws/ws-session-state.js +431 -0
  188. package/src/harness/background-task-manager.js +233 -36
  189. package/src/harness/jsonl-session-store.js +2551 -167
  190. package/src/harness/mcp-client.js +802 -61
  191. package/src/harness/prompt-compressor.js +227 -27
  192. package/src/harness/session-index.js +89 -38
  193. package/src/harness/session-list-index.js +254 -0
  194. package/src/harness/structured-handoff.js +410 -0
  195. package/src/lazy-dispatch.js +747 -84
  196. package/src/lib/__tests__/logger.test.js +50 -2
  197. package/src/lib/advisor-runtime.js +1047 -0
  198. package/src/lib/agent-core.js +2 -0
  199. package/src/lib/agent-sandbox.js +120 -26
  200. package/src/lib/agent-session-export.js +20 -0
  201. package/src/lib/agent-team/task-lease.js +271 -3
  202. package/src/lib/agent-team/team-adjudication.js +1501 -0
  203. package/src/lib/agent-team/team-budget.js +4 -1
  204. package/src/lib/agent-team/team-control-store.js +582 -0
  205. package/src/lib/agent-team/team-distributed-queue.js +5246 -0
  206. package/src/lib/agent-team/team-process-checkpoint.js +211 -0
  207. package/src/lib/agent-team/team-runner.js +543 -24
  208. package/src/lib/agent-team/team-worktree.js +1403 -95
  209. package/src/lib/artifact-store.js +131 -8
  210. package/src/lib/background-agent-supervisor.js +185 -13
  211. package/src/lib/background-interaction-journal.js +37 -9
  212. package/src/lib/background-launch-profile.js +1058 -0
  213. package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
  214. package/src/lib/checkpoint-restore-orchestrator.js +987 -0
  215. package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
  216. package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
  217. package/src/lib/checkpoint-restore-recovery.js +884 -0
  218. package/src/lib/checkpoint-restore-retention.js +126 -0
  219. package/src/lib/checkpoint-restore-saga.js +5079 -0
  220. package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
  221. package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
  222. package/src/lib/checkpoint-store.js +1688 -97
  223. package/src/lib/checkpoint-timeline-authority.js +522 -0
  224. package/src/lib/checkpoint-timeline.js +642 -0
  225. package/src/lib/config-keys.js +18 -119
  226. package/src/lib/config-manager.js +446 -27
  227. package/src/lib/config-redaction.js +57 -0
  228. package/src/lib/config-schema.js +853 -0
  229. package/src/lib/cowork-mcp-tools.js +5 -0
  230. package/src/lib/cowork-task-runner.js +458 -63
  231. package/src/lib/delivery-coordinator.js +1234 -0
  232. package/src/lib/delivery-evidence.js +450 -0
  233. package/src/lib/doctor-checkup.js +199 -14
  234. package/src/lib/executable-path.js +34 -0
  235. package/src/lib/fatal-handler.js +16 -0
  236. package/src/lib/file-checkpoint.js +4909 -186
  237. package/src/lib/file-lines.js +125 -0
  238. package/src/lib/headless-config-command.js +16 -5
  239. package/src/lib/hook-runner.cjs +139 -38
  240. package/src/lib/hooks-v2-workspace-context.js +10 -0
  241. package/src/lib/impacted-gate-selector.js +424 -0
  242. package/src/lib/interaction-adapter.js +62 -0
  243. package/src/lib/jsonl-session-store.js +1 -35
  244. package/src/lib/logger.js +66 -14
  245. package/src/lib/managed-checkpoint-render.js +60 -0
  246. package/src/lib/managed-tool-checkpoint.js +194 -0
  247. package/src/lib/mcp-call-ledger-store.js +1069 -0
  248. package/src/lib/mcp-call-ledger.js +747 -0
  249. package/src/lib/mcp-client.js +5 -0
  250. package/src/lib/mcp-conflict-scheduler.js +468 -0
  251. package/src/lib/mcp-effect-contract.js +102 -0
  252. package/src/lib/mcp-headers-helper-trust.js +145 -0
  253. package/src/lib/mcp-headers-helper.js +616 -0
  254. package/src/lib/mcp-host-recovery-runtime.js +131 -0
  255. package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
  256. package/src/lib/mcp-recovery-adjudication.js +443 -0
  257. package/src/lib/output-context.js +86 -0
  258. package/src/lib/packer/file-identity.js +170 -0
  259. package/src/lib/packer/index.js +3 -0
  260. package/src/lib/packer/native-update-state.js +277 -0
  261. package/src/lib/packer/pack-update-applier.js +1983 -136
  262. package/src/lib/packer/pack-update-checker.js +34 -0
  263. package/src/lib/packer/pack-update-downloader.js +875 -86
  264. package/src/lib/packer/pack-update-signature.js +86 -0
  265. package/src/lib/packer/pkg-config-generator.js +6 -0
  266. package/src/lib/paths.js +65 -10
  267. package/src/lib/plan-mode.js +831 -14
  268. package/src/lib/plan-persistence.js +540 -0
  269. package/src/lib/plugin-runtime/hooks.js +227 -69
  270. package/src/lib/plugin-runtime/plugin-options.js +189 -44
  271. package/src/lib/pr-automation-policy.js +146 -8
  272. package/src/lib/process-execution-broker/credential-agent.js +7 -0
  273. package/src/lib/process-execution-broker/index.js +491 -13
  274. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +28 -1
  275. package/src/lib/process-execution-broker/linux-generic-bwrap.js +28 -4
  276. package/src/lib/process-execution-broker/platform-sandbox.js +92 -70
  277. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  278. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  279. package/src/lib/process-execution-broker/windows-sandbox.cs +284 -19
  280. package/src/lib/process-execution-broker/workspace-transaction.js +4459 -0
  281. package/src/lib/project-instructions.js +165 -29
  282. package/src/lib/project-mcp-trust.js +67 -0
  283. package/src/lib/public-ide-capability-manifest.js +272 -0
  284. package/src/lib/public-ide-capability-validation.js +351 -0
  285. package/src/lib/secret-store.js +267 -43
  286. package/src/lib/secure-file-identity.js +433 -0
  287. package/src/lib/secure-fs.js +1089 -0
  288. package/src/lib/security-audit.js +58 -0
  289. package/src/lib/service-manager.js +34 -13
  290. package/src/lib/session-budget-runtime.js +1452 -0
  291. package/src/lib/session-host-snapshot.js +388 -0
  292. package/src/lib/session-message-provenance.js +429 -0
  293. package/src/lib/session-projection.js +804 -0
  294. package/src/lib/session-resource-budget.js +1495 -0
  295. package/src/lib/settings-hooks.cjs +138 -22
  296. package/src/lib/settings-loader.cjs +25 -2
  297. package/src/lib/side-effect-ledger-store.js +45 -23
  298. package/src/lib/skill-execution-identity.js +217 -0
  299. package/src/lib/skill-loader.js +299 -18
  300. package/src/lib/sub-agent-context.js +236 -28
  301. package/src/lib/sub-agent-registry.js +5 -0
  302. package/src/lib/subagent-contract.js +94 -0
  303. package/src/lib/todo-manager.js +185 -18
  304. package/src/lib/todo-persistence.js +417 -0
  305. package/src/lib/turn-binding-store.js +41 -23
  306. package/src/lib/turn-binding.js +160 -2
  307. package/src/lib/with-file-lock.js +165 -24
  308. package/src/lib/ws-chat-handler.js +21 -0
  309. package/src/program-base.js +18 -0
  310. package/src/repl/advisor-command.js +103 -0
  311. package/src/repl/agent-repl.js +2175 -146
  312. package/src/repl/btw-command.js +93 -10
  313. package/src/repl/clipboard-image.js +119 -0
  314. package/src/repl/config-summary.js +64 -108
  315. package/src/repl/prompt-editor.js +233 -0
  316. package/src/repl/prompt-interactions.js +344 -0
  317. package/src/repl/prompt-stash.js +354 -0
  318. package/src/repl/prompt-suggestions.js +312 -0
  319. package/src/repl/repl-keybindings.js +227 -0
  320. package/src/repl/session-recap.js +217 -0
  321. package/src/repl/slash-command-registry.js +22 -0
  322. package/src/repl/terminal-layout.js +88 -0
  323. package/src/runtime/agent-core.js +1630 -447
  324. package/src/runtime/coding-agent-contract-shared.cjs +13 -1
  325. package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
  326. package/src/runtime/diagnostics.js +32 -13
  327. package/src/runtime/headless-runner.js +310 -118
  328. package/src/runtime/headless-stream.js +356 -95
  329. package/src/runtime/mcp-config.js +148 -14
  330. package/src/runtime/policies/agent-policy.js +14 -0
  331. package/src/runtime/status-diagnostics-lite.js +137 -0
  332. package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +0 -1
  333. package/src/assets/web-panel/assets/OrderTableRenderer-BU2Yqq5H.js +0 -1
  334. package/src/assets/web-panel/assets/PdhVaultBrowser-69ca_WeR.js +0 -7
  335. package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +0 -1
  336. package/src/assets/web-panel/assets/index-C-C7DaG6.js +0 -1
  337. package/src/assets/web-panel/assets/index-DkfWzWtd.js +0 -1
@@ -0,0 +1,689 @@
1
+ /**
2
+ * Conservative production recovery for durable checkpoint restores.
3
+ *
4
+ * This first control-plane slice intentionally supports only two operations:
5
+ *
6
+ * - abort before a session intent or workspace mutation can have been issued;
7
+ * - release an exact terminal operation's retained workspace lock and archive
8
+ * its saga.
9
+ *
10
+ * Anything that may have crossed the session-intent or mutation boundary must
11
+ * be reconciled by a richer session/workspace recovery planner. Refusing those
12
+ * phases is important: a saga phase is a durable lower bound, not permission to
13
+ * guess that an external side effect did not happen.
14
+ */
15
+
16
+ import {
17
+ CheckpointRestoreSagaStore,
18
+ CHECKPOINT_RESTORE_SAGA_ERROR_CODES,
19
+ computeCheckpointRestoreWorkspaceLockOwnerDigest,
20
+ } from "./checkpoint-restore-saga.js";
21
+ import {
22
+ inspectWorkspaceLockOwnerSync,
23
+ withWorkspaceRecoveryLockSync,
24
+ } from "./process-execution-broker/workspace-transaction.js";
25
+
26
+ const HASH_PATTERN = /^sha256:[a-f0-9]{64}$/;
27
+ const RECOVERY_PHASES = new Set(["recovery_required", "recovery_started"]);
28
+ const SAFE_ABORT_BASE_PHASES = new Set(["created", "locked"]);
29
+ const TERMINAL_PHASES = new Set(["completed", "aborted", "rolled_back"]);
30
+ const CHECKPOINT_RESTORE_PURPOSE = "checkpoint-restore";
31
+
32
+ export const CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES = Object.freeze({
33
+ INVALID_ARGUMENT: "CHECKPOINT_RESTORE_RECOVERY_INVALID_ARGUMENT",
34
+ SAGA_CONFLICT: "CHECKPOINT_RESTORE_RECOVERY_SAGA_CONFLICT",
35
+ ACTION_NOT_ALLOWED: "CHECKPOINT_RESTORE_RECOVERY_ACTION_NOT_ALLOWED",
36
+ OWNER_CONFLICT: "CHECKPOINT_RESTORE_RECOVERY_OWNER_CONFLICT",
37
+ });
38
+
39
+ export class CheckpointRestoreRecoveryError extends Error {
40
+ constructor(code, message, details = {}, cause = null) {
41
+ super(message, cause ? { cause } : undefined);
42
+ this.name = "CheckpointRestoreRecoveryError";
43
+ this.code = code;
44
+ Object.assign(this, details);
45
+ }
46
+ }
47
+
48
+ function recoveryError(code, message, details = {}, cause = null) {
49
+ return new CheckpointRestoreRecoveryError(code, message, details, cause);
50
+ }
51
+
52
+ function canonicalJson(value) {
53
+ if (value === null) return "null";
54
+ if (typeof value === "string" || typeof value === "boolean") {
55
+ return JSON.stringify(value);
56
+ }
57
+ if (typeof value === "number" && Number.isFinite(value)) {
58
+ return JSON.stringify(value);
59
+ }
60
+ if (Array.isArray(value)) {
61
+ return `[${value.map((entry) => canonicalJson(entry)).join(",")}]`;
62
+ }
63
+ if (value && typeof value === "object") {
64
+ return `{${Object.keys(value)
65
+ .sort()
66
+ .map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`)
67
+ .join(",")}}`;
68
+ }
69
+ throw recoveryError(
70
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.INVALID_ARGUMENT,
71
+ "Checkpoint restore recovery evidence is not canonical JSON",
72
+ );
73
+ }
74
+
75
+ function boundedText(value, fallback, maximum) {
76
+ let result = "";
77
+ for (const character of String(value || fallback)) {
78
+ const code = character.charCodeAt(0);
79
+ result += code < 32 || code === 127 ? " " : character;
80
+ }
81
+ return (result.trim() || fallback).slice(0, maximum);
82
+ }
83
+
84
+ function validateExpectedAuthority({
85
+ expectedSeq,
86
+ expectedHash,
87
+ expectedOwnerDigest,
88
+ }) {
89
+ if (
90
+ !Number.isSafeInteger(expectedSeq) ||
91
+ expectedSeq < 1 ||
92
+ typeof expectedHash !== "string" ||
93
+ !HASH_PATTERN.test(expectedHash) ||
94
+ !(
95
+ expectedOwnerDigest === null ||
96
+ (typeof expectedOwnerDigest === "string" &&
97
+ HASH_PATTERN.test(expectedOwnerDigest))
98
+ )
99
+ ) {
100
+ throw recoveryError(
101
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.INVALID_ARGUMENT,
102
+ "Checkpoint restore recovery requires exact saga and observed-owner authority",
103
+ );
104
+ }
105
+ }
106
+
107
+ function exactSaga(saga, operationId, expectedSeq, expectedHash) {
108
+ if (
109
+ !saga ||
110
+ saga.operationId !== operationId ||
111
+ saga.seq !== expectedSeq ||
112
+ saga.headHash !== expectedHash
113
+ ) {
114
+ throw recoveryError(
115
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.SAGA_CONFLICT,
116
+ "Checkpoint restore saga changed after recovery preview",
117
+ {
118
+ operationId,
119
+ expectedSeq,
120
+ expectedHash,
121
+ actualSeq: saga?.seq ?? null,
122
+ actualHash: saga?.headHash ?? null,
123
+ },
124
+ );
125
+ }
126
+ return saga;
127
+ }
128
+
129
+ function basePhase(saga) {
130
+ for (let index = saga.events.length - 1; index >= 0; index -= 1) {
131
+ const phase = saga.events[index]?.phase;
132
+ if (!RECOVERY_PHASES.has(phase)) return phase || null;
133
+ }
134
+ return null;
135
+ }
136
+
137
+ function terminalSummary(value) {
138
+ return Object.freeze({
139
+ operationId: value.operationId,
140
+ phase: value.phase,
141
+ seq: value.seq,
142
+ headHash: value.headHash,
143
+ });
144
+ }
145
+
146
+ function archiveWarning(error) {
147
+ return Object.freeze({
148
+ code: boundedText(
149
+ error?.code,
150
+ "CHECKPOINT_RESTORE_SAGA_ARCHIVE_PENDING",
151
+ 128,
152
+ ),
153
+ message: boundedText(
154
+ error?.message,
155
+ "Checkpoint restore saga archive is pending",
156
+ 512,
157
+ ),
158
+ commitState:
159
+ typeof error?.commitState === "string"
160
+ ? boundedText(error.commitState, "unknown", 128)
161
+ : null,
162
+ });
163
+ }
164
+
165
+ function processAlive(pid) {
166
+ try {
167
+ process.kill(pid, 0);
168
+ return true;
169
+ } catch (error) {
170
+ // A permission failure proves that the PID exists but is not observable.
171
+ // PID reuse is intentionally fail-closed and is therefore also "alive".
172
+ return error?.code === "EPERM";
173
+ }
174
+ }
175
+
176
+ function propagateRecoveryDiagnostics(error) {
177
+ if (!error || typeof error !== "object") return error;
178
+ const nested = error.cause;
179
+ if (!nested || typeof nested !== "object") return error;
180
+ for (const field of [
181
+ "checkpointRestoreRecoveryCause",
182
+ "checkpointRestoreOperationId",
183
+ "checkpointRestoreSagaPhase",
184
+ "checkpointRestoreSagaSeq",
185
+ "checkpointRestoreSagaHeadHash",
186
+ "checkpointRestoreRecoveryRequired",
187
+ ]) {
188
+ if (error[field] === undefined && nested[field] !== undefined) {
189
+ error[field] = nested[field];
190
+ }
191
+ }
192
+ return error;
193
+ }
194
+
195
+ /**
196
+ * The controller never keeps a saga store lock while acquiring a workspace or
197
+ * session authority. Store methods take short internal locks, and all calls
198
+ * made from a workspace callback therefore follow workspace -> saga order.
199
+ */
200
+ export class CheckpointRestoreRecoveryController {
201
+ constructor(options = {}) {
202
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
203
+ throw recoveryError(
204
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.INVALID_ARGUMENT,
205
+ "Checkpoint restore recovery controller options must be an object",
206
+ );
207
+ }
208
+ if (
209
+ typeof options.workspaceRoot !== "string" ||
210
+ options.workspaceRoot.length === 0
211
+ ) {
212
+ throw recoveryError(
213
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.INVALID_ARGUMENT,
214
+ "Checkpoint restore recovery requires a workspaceRoot",
215
+ );
216
+ }
217
+ this.workspaceRoot = options.workspaceRoot;
218
+ this.store =
219
+ options.store ||
220
+ new CheckpointRestoreSagaStore({
221
+ workspaceRoot: this.workspaceRoot,
222
+ });
223
+ this._inspectWorkspaceLockOwnerSync =
224
+ options.inspectWorkspaceLockOwnerSync || inspectWorkspaceLockOwnerSync;
225
+ this._withWorkspaceRecoveryLockSync =
226
+ options.withWorkspaceRecoveryLockSync || withWorkspaceRecoveryLockSync;
227
+ this._workspaceLockOwnerDigest =
228
+ options.computeWorkspaceLockOwnerDigest ||
229
+ computeCheckpointRestoreWorkspaceLockOwnerDigest;
230
+ this._isProcessAlive = options.isProcessAlive || processAlive;
231
+ this._workspaceLockOptions = Object.freeze({
232
+ ...(options.workspaceLockOptions || {}),
233
+ });
234
+ }
235
+
236
+ _lockOptions(operationId) {
237
+ return {
238
+ ...this._workspaceLockOptions,
239
+ workspaceRoot: this.workspaceRoot,
240
+ operationId,
241
+ purpose: CHECKPOINT_RESTORE_PURPOSE,
242
+ };
243
+ }
244
+
245
+ _loadExact(operationId, expectedSeq, expectedHash) {
246
+ return exactSaga(
247
+ this.store.load(operationId),
248
+ operationId,
249
+ expectedSeq,
250
+ expectedHash,
251
+ );
252
+ }
253
+
254
+ _assertAbortable(saga) {
255
+ const sourcePhase = basePhase(saga);
256
+ if (!SAFE_ABORT_BASE_PHASES.has(sourcePhase) || saga.terminal) {
257
+ throw recoveryError(
258
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.ACTION_NOT_ALLOWED,
259
+ "Checkpoint restore can only be aborted before prepared session intent authority",
260
+ {
261
+ operationId: saga.operationId,
262
+ phase: saga.phase,
263
+ basePhase: sourcePhase,
264
+ },
265
+ );
266
+ }
267
+ return sourcePhase;
268
+ }
269
+
270
+ _assertTerminal(saga) {
271
+ if (!saga.terminal || !TERMINAL_PHASES.has(saga.phase)) {
272
+ throw recoveryError(
273
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.ACTION_NOT_ALLOWED,
274
+ "Only a terminal checkpoint restore can release recovery authority",
275
+ {
276
+ operationId: saga.operationId,
277
+ phase: saga.phase,
278
+ basePhase: basePhase(saga),
279
+ },
280
+ );
281
+ }
282
+ return saga;
283
+ }
284
+
285
+ _advanceExact(saga, phase, evidence) {
286
+ try {
287
+ return this.store.advance(saga.operationId, {
288
+ expectedSeq: saga.seq,
289
+ expectedHash: saga.headHash,
290
+ phase,
291
+ evidence,
292
+ });
293
+ } catch (error) {
294
+ // Event publication and HEAD replacement are separate durable renames.
295
+ // Reconcile only the exact intended successor; never blind-retry a CAS.
296
+ try {
297
+ const observed = this.store.load(saga.operationId);
298
+ const latest = observed.events.at(-1);
299
+ if (
300
+ observed.seq === saga.seq + 1 &&
301
+ observed.phase === phase &&
302
+ latest?.prevHash === saga.headHash &&
303
+ canonicalJson(latest.evidence) === canonicalJson(evidence)
304
+ ) {
305
+ return observed;
306
+ }
307
+ } catch (loadError) {
308
+ if (error && typeof error === "object") {
309
+ error.checkpointRestoreRecoveryLoadError = loadError;
310
+ }
311
+ }
312
+ throw error;
313
+ }
314
+ }
315
+
316
+ _inspectBoundOwner(operationId, expectedOwnerDigest) {
317
+ const owner = this._inspectWorkspaceLockOwnerSync(
318
+ this._lockOptions(operationId),
319
+ );
320
+ if (owner === null) {
321
+ if (expectedOwnerDigest !== null) {
322
+ throw recoveryError(
323
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.OWNER_CONFLICT,
324
+ "Checkpoint restore workspace owner disappeared after recovery preview",
325
+ { operationId, expectedOwnerDigest, actualOwnerDigest: null },
326
+ );
327
+ }
328
+ return null;
329
+ }
330
+ const actualOwnerDigest = this._workspaceLockOwnerDigest(owner);
331
+ if (actualOwnerDigest !== expectedOwnerDigest) {
332
+ throw recoveryError(
333
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.OWNER_CONFLICT,
334
+ "Checkpoint restore workspace owner changed after recovery preview",
335
+ { operationId, expectedOwnerDigest, actualOwnerDigest },
336
+ );
337
+ }
338
+ return owner;
339
+ }
340
+
341
+ _withBoundWorkspaceAuthority(operationId, expectedOwnerDigest, callback) {
342
+ const observedOwner = this._inspectBoundOwner(
343
+ operationId,
344
+ expectedOwnerDigest,
345
+ );
346
+ if (!observedOwner) {
347
+ throw recoveryError(
348
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.OWNER_CONFLICT,
349
+ "Checkpoint restore has no retained workspace owner to take over",
350
+ { operationId, expectedOwnerDigest: null, actualOwnerDigest: null },
351
+ );
352
+ }
353
+ return this._withWorkspaceRecoveryLockSync(
354
+ {
355
+ ...this._lockOptions(operationId),
356
+ expectedOwner: observedOwner,
357
+ },
358
+ callback,
359
+ );
360
+ }
361
+
362
+ _abortCreatedWithoutPublishedOwner(
363
+ saga,
364
+ expectedOwnerDigest,
365
+ normalizedReason,
366
+ ) {
367
+ if (expectedOwnerDigest !== null || saga.phase !== "created") return null;
368
+ const created = saga.events[0];
369
+ const actorPid = created?.evidence?.actorPid;
370
+ if (!Number.isSafeInteger(actorPid) || actorPid <= 0) {
371
+ throw recoveryError(
372
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.ACTION_NOT_ALLOWED,
373
+ "Lock-free created recovery requires the durable initiator PID",
374
+ { operationId: saga.operationId, phase: saga.phase },
375
+ );
376
+ }
377
+ if (this._isProcessAlive(actorPid)) {
378
+ throw recoveryError(
379
+ CHECKPOINT_RESTORE_RECOVERY_ERROR_CODES.OWNER_CONFLICT,
380
+ "Checkpoint restore initiator is still live",
381
+ { operationId: saga.operationId, actorPid },
382
+ );
383
+ }
384
+ // Re-read absence immediately before the saga CAS. Once the initiator is
385
+ // dead, no original process can publish a later workspace lock. Competing
386
+ // recovery callers are serialized by the exact saga head CAS.
387
+ this._inspectBoundOwner(saga.operationId, null);
388
+ const aborted = this._advanceExact(saga, "aborted", {
389
+ recoveryAction: "abort-before-lock",
390
+ reason: normalizedReason,
391
+ });
392
+ const archive = this._archiveTerminal(aborted);
393
+ return Object.freeze({
394
+ ok: true,
395
+ action: "abort",
396
+ ...terminalSummary(aborted),
397
+ reconciledFromError: false,
398
+ ...archive,
399
+ });
400
+ }
401
+
402
+ _archiveTerminal(saga) {
403
+ try {
404
+ const archived = this.store.archiveTerminal(saga.operationId, {
405
+ expectedSeq: saga.seq,
406
+ expectedHash: saga.headHash,
407
+ });
408
+ return Object.freeze({
409
+ archived: true,
410
+ alreadyArchived: archived.alreadyArchived === true,
411
+ warning: null,
412
+ });
413
+ } catch (error) {
414
+ return Object.freeze({
415
+ archived: false,
416
+ alreadyArchived: false,
417
+ warning: archiveWarning(error),
418
+ });
419
+ }
420
+ }
421
+
422
+ _retainAbortFailure(operationError, lease) {
423
+ let observed = null;
424
+ try {
425
+ observed = this.store.load(lease.recoveryOfOperationId);
426
+ } catch (loadError) {
427
+ if (operationError && typeof operationError === "object") {
428
+ operationError.checkpointRestoreRecoveryLoadError = loadError;
429
+ }
430
+ }
431
+
432
+ if (observed?.terminal) return observed;
433
+
434
+ if (observed && observed.phase !== "recovery_required") {
435
+ try {
436
+ observed = this._advanceExact(observed, "recovery_required", {
437
+ reason: boundedText(
438
+ operationError?.message,
439
+ "Checkpoint restore abort requires another recovery attempt",
440
+ 2_048,
441
+ ),
442
+ errorCode: boundedText(
443
+ operationError?.code,
444
+ "CHECKPOINT_RESTORE_RECOVERY_ABORT_FAILED",
445
+ 128,
446
+ ),
447
+ });
448
+ } catch (journalError) {
449
+ if (operationError && typeof operationError === "object") {
450
+ operationError.checkpointRestoreRecoveryJournalError = journalError;
451
+ }
452
+ }
453
+ }
454
+
455
+ try {
456
+ lease.retainForRecovery(
457
+ boundedText(
458
+ `${operationError?.code || "CHECKPOINT_RESTORE_RECOVERY_ABORT_FAILED"}: ${operationError?.message || "abort outcome is unknown"}`,
459
+ "Checkpoint restore abort outcome is unknown",
460
+ 512,
461
+ ),
462
+ );
463
+ } catch (retentionError) {
464
+ if (retentionError && typeof retentionError === "object") {
465
+ retentionError.checkpointRestoreRecoveryCause = operationError;
466
+ retentionError.checkpointRestoreOperationId =
467
+ lease.recoveryOfOperationId;
468
+ retentionError.checkpointRestoreSagaPhase = observed?.phase || null;
469
+ retentionError.checkpointRestoreSagaSeq = observed?.seq || null;
470
+ retentionError.checkpointRestoreSagaHeadHash =
471
+ observed?.headHash || null;
472
+ retentionError.checkpointRestoreRecoveryRequired = true;
473
+ }
474
+ throw retentionError;
475
+ }
476
+ throw operationError;
477
+ }
478
+
479
+ abort(
480
+ operationId,
481
+ {
482
+ expectedSeq,
483
+ expectedHash,
484
+ expectedOwnerDigest,
485
+ reason = "Operator aborted checkpoint restore before durable intent",
486
+ } = {},
487
+ ) {
488
+ validateExpectedAuthority({
489
+ expectedSeq,
490
+ expectedHash,
491
+ expectedOwnerDigest,
492
+ });
493
+ const previewSaga = this._loadExact(operationId, expectedSeq, expectedHash);
494
+ this._assertAbortable(previewSaga);
495
+ const normalizedReason = boundedText(
496
+ reason,
497
+ "Operator aborted checkpoint restore before durable intent",
498
+ 2_048,
499
+ );
500
+ const lockFreeAbort = this._abortCreatedWithoutPublishedOwner(
501
+ previewSaga,
502
+ expectedOwnerDigest,
503
+ normalizedReason,
504
+ );
505
+ if (lockFreeAbort) return lockFreeAbort;
506
+
507
+ let settled;
508
+ try {
509
+ settled = this._withBoundWorkspaceAuthority(
510
+ operationId,
511
+ expectedOwnerDigest,
512
+ (lease) => {
513
+ try {
514
+ lease.assertOwned();
515
+ let saga = this._loadExact(operationId, expectedSeq, expectedHash);
516
+ this._assertAbortable(saga);
517
+
518
+ if (saga.phase !== "recovery_required") {
519
+ saga = this._advanceExact(saga, "recovery_required", {
520
+ reason:
521
+ "Checkpoint restore was interrupted before durable intent",
522
+ errorCode: "CHECKPOINT_RESTORE_RECOVERY_ABORT_REQUESTED",
523
+ });
524
+ }
525
+ lease.assertOwned();
526
+ const recoveryStartedEvidence = {
527
+ workspaceLockOwner: lease.owner,
528
+ lockOwnerDigest: this._workspaceLockOwnerDigest(lease.owner),
529
+ recoveryAction: "abort-pre-intent",
530
+ };
531
+ saga = this._advanceExact(
532
+ saga,
533
+ "recovery_started",
534
+ recoveryStartedEvidence,
535
+ );
536
+ lease.assertOwned();
537
+ saga = this._advanceExact(saga, "aborted", {
538
+ recoveryAction: "abort-pre-intent",
539
+ reason: normalizedReason,
540
+ });
541
+ lease.assertOwned();
542
+ return Object.freeze({ saga, reconciledFromError: false });
543
+ } catch (error) {
544
+ const saga = this._retainAbortFailure(error, lease);
545
+ return Object.freeze({ saga, reconciledFromError: true });
546
+ }
547
+ },
548
+ );
549
+ } catch (error) {
550
+ throw propagateRecoveryDiagnostics(error);
551
+ }
552
+
553
+ const archive = this._archiveTerminal(settled.saga);
554
+ return Object.freeze({
555
+ ok: true,
556
+ action: "abort",
557
+ ...terminalSummary(settled.saga),
558
+ reconciledFromError: settled.reconciledFromError,
559
+ ...archive,
560
+ });
561
+ }
562
+
563
+ _readTerminalRetention(operationId, expectedSeq, expectedHash) {
564
+ try {
565
+ return Object.freeze({
566
+ saga: this._assertTerminal(
567
+ this._loadExact(operationId, expectedSeq, expectedHash),
568
+ ),
569
+ alreadyArchived: false,
570
+ });
571
+ } catch (error) {
572
+ if (error?.code !== CHECKPOINT_RESTORE_SAGA_ERROR_CODES.NOT_FOUND) {
573
+ throw error;
574
+ }
575
+ // `archiveTerminal` is an exact, idempotent retained-state read when the
576
+ // active operation is absent and the requested archive already exists.
577
+ const archived = this.store.archiveTerminal(operationId, {
578
+ expectedSeq,
579
+ expectedHash,
580
+ });
581
+ return Object.freeze({
582
+ saga: Object.freeze({
583
+ operationId,
584
+ phase: archived.phase,
585
+ seq: archived.seq,
586
+ headHash: archived.headHash,
587
+ terminal: true,
588
+ }),
589
+ alreadyArchived: archived.alreadyArchived === true,
590
+ });
591
+ }
592
+ }
593
+
594
+ _retainTerminalVerificationFailure(operationError, lease) {
595
+ try {
596
+ lease.retainForRecovery(
597
+ boundedText(
598
+ `${operationError?.code || "CHECKPOINT_RESTORE_TERMINAL_VERIFY_FAILED"}: ${operationError?.message || "terminal authority is unknown"}`,
599
+ "Checkpoint restore terminal authority is unknown",
600
+ 512,
601
+ ),
602
+ );
603
+ } catch (retentionError) {
604
+ if (retentionError && typeof retentionError === "object") {
605
+ retentionError.checkpointRestoreRecoveryCause = operationError;
606
+ retentionError.checkpointRestoreOperationId =
607
+ lease.recoveryOfOperationId;
608
+ retentionError.checkpointRestoreRecoveryRequired = true;
609
+ }
610
+ throw retentionError;
611
+ }
612
+ throw operationError;
613
+ }
614
+
615
+ release(
616
+ operationId,
617
+ { expectedSeq, expectedHash, expectedOwnerDigest } = {},
618
+ ) {
619
+ validateExpectedAuthority({
620
+ expectedSeq,
621
+ expectedHash,
622
+ expectedOwnerDigest,
623
+ });
624
+ const preview = this._readTerminalRetention(
625
+ operationId,
626
+ expectedSeq,
627
+ expectedHash,
628
+ );
629
+ this._assertTerminal(preview.saga);
630
+
631
+ const observedOwner = this._inspectBoundOwner(
632
+ operationId,
633
+ expectedOwnerDigest,
634
+ );
635
+ if (!observedOwner) {
636
+ const archive = preview.alreadyArchived
637
+ ? Object.freeze({
638
+ archived: true,
639
+ alreadyArchived: true,
640
+ warning: null,
641
+ })
642
+ : this._archiveTerminal(preview.saga);
643
+ return Object.freeze({
644
+ ok: true,
645
+ action: "release",
646
+ ...terminalSummary(preview.saga),
647
+ ...archive,
648
+ });
649
+ }
650
+
651
+ const settled = this._withBoundWorkspaceAuthority(
652
+ operationId,
653
+ expectedOwnerDigest,
654
+ (lease) => {
655
+ try {
656
+ lease.assertOwned();
657
+ const retained = this._readTerminalRetention(
658
+ operationId,
659
+ expectedSeq,
660
+ expectedHash,
661
+ );
662
+ this._assertTerminal(retained.saga);
663
+ lease.assertOwned();
664
+ return retained;
665
+ } catch (error) {
666
+ return this._retainTerminalVerificationFailure(error, lease);
667
+ }
668
+ },
669
+ );
670
+
671
+ const archive = settled.alreadyArchived
672
+ ? Object.freeze({
673
+ archived: true,
674
+ alreadyArchived: true,
675
+ warning: null,
676
+ })
677
+ : this._archiveTerminal(settled.saga);
678
+ return Object.freeze({
679
+ ok: true,
680
+ action: "release",
681
+ ...terminalSummary(settled.saga),
682
+ ...archive,
683
+ });
684
+ }
685
+ }
686
+
687
+ export function createCheckpointRestoreRecoveryController(options = {}) {
688
+ return new CheckpointRestoreRecoveryController(options);
689
+ }