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
@@ -20,8 +20,106 @@
20
20
  */
21
21
 
22
22
  import chalk from "chalk";
23
+ import { createHash } from "node:crypto";
23
24
  import { resolve } from "path";
25
+ import {
26
+ buildCheckpointTimeline,
27
+ projectCheckpointTimeline,
28
+ } from "../lib/checkpoint-timeline.js";
29
+ import {
30
+ CHECKPOINT_TIMELINE_AUDIT_EVENT,
31
+ CHECKPOINT_TIMELINE_INTENT_EVENT,
32
+ CHECKPOINT_TIMELINE_RESULT_SCHEMA,
33
+ CHECKPOINT_TIMELINE_RESULT_VERSION,
34
+ checkpointTimelineConfirmationsMatch,
35
+ planCheckpointTimelineAction,
36
+ timelineActionError,
37
+ validateCheckpointTimelineConfirmationSubmission,
38
+ validateCheckpointTimelineSubmission,
39
+ } from "../lib/checkpoint-timeline-authority.js";
24
40
  import { logger } from "../lib/logger.js";
41
+ import {
42
+ loadTurnBindingLog,
43
+ TURN_BINDING_TIMELINE_EVENT,
44
+ } from "../lib/turn-binding-store.js";
45
+ import {
46
+ createBranchSession,
47
+ findLatestEvent,
48
+ readVerifiedMessages,
49
+ withSessionAuthorityTransaction,
50
+ } from "../harness/jsonl-session-store.js";
51
+ import { withWorkspaceLockSync as withCanonicalWorkspaceLockSync } from "../lib/process-execution-broker/workspace-transaction.js";
52
+ import {
53
+ CheckpointRestoreSagaStore,
54
+ computeCheckpointRestoreWorkspaceLockOwnerDigest,
55
+ } from "../lib/checkpoint-restore-saga.js";
56
+ import {
57
+ computeCheckpointRestoreDigest,
58
+ runCheckpointRestoreOperation,
59
+ } from "../lib/checkpoint-restore-orchestrator.js";
60
+ import { registerManagedCheckpointCommands } from "./checkpoint-managed.js";
61
+ import { registerCheckpointRestoreRecoveryCommands } from "./checkpoint-restore-recovery.js";
62
+
63
+ function stableCheckpointRestoreValue(value) {
64
+ if (value === undefined) return "null";
65
+ if (
66
+ value === null ||
67
+ typeof value === "string" ||
68
+ typeof value === "boolean"
69
+ ) {
70
+ return JSON.stringify(value);
71
+ }
72
+ if (typeof value === "number" && Number.isFinite(value)) {
73
+ return JSON.stringify(value);
74
+ }
75
+ if (Array.isArray(value)) {
76
+ return `[${value.map((entry) => stableCheckpointRestoreValue(entry)).join(",")}]`;
77
+ }
78
+ if (value && typeof value === "object") {
79
+ return `{${Object.keys(value)
80
+ .sort()
81
+ .map(
82
+ (key) =>
83
+ `${JSON.stringify(key)}:${stableCheckpointRestoreValue(value[key])}`,
84
+ )
85
+ .join(",")}}`;
86
+ }
87
+ throw new TypeError("checkpoint restore evidence is not canonical JSON");
88
+ }
89
+
90
+ function checkpointRestoreDigest(domain, value) {
91
+ return `sha256:${createHash("sha256")
92
+ .update(`${domain}\0${stableCheckpointRestoreValue(value)}`)
93
+ .digest("hex")}`;
94
+ }
95
+
96
+ function boundedCheckpointRestoreText(value, fallback, maximum = 2_048) {
97
+ let sanitized = "";
98
+ for (const character of String(value || fallback)) {
99
+ const code = character.charCodeAt(0);
100
+ sanitized += code < 32 || code === 127 ? " " : character;
101
+ }
102
+ const normalized = sanitized.trim();
103
+ return (normalized || fallback).slice(0, maximum);
104
+ }
105
+
106
+ function checkpointRestoreErrorCode(error) {
107
+ return boundedCheckpointRestoreText(
108
+ error?.code,
109
+ "CHECKPOINT_RESTORE_FAILED",
110
+ 128,
111
+ );
112
+ }
113
+
114
+ function checkpointRestoreTargetCount(planned) {
115
+ const total = planned?.preview?.code?.summary?.total;
116
+ if (!Number.isSafeInteger(total) || total < 0) {
117
+ const error = new Error("checkpoint restore target count is unavailable");
118
+ error.code = "TIMELINE_WORKSPACE_BINDING_INVALID";
119
+ throw error;
120
+ }
121
+ return total;
122
+ }
25
123
 
26
124
  /** git-plumbing engine adapter (normalized interface). */
27
125
  function gitEngine(gs, dir, session) {
@@ -42,12 +140,37 @@ function gitEngine(gs, dir, session) {
42
140
  label: r.label,
43
141
  createdAt: r.createdAt,
44
142
  fileCount: null,
143
+ identity: r.commit ? `git:${r.commit}` : null,
45
144
  })),
46
145
  show: (id) => gs.showCheckpoint(dir, id, { session }),
47
- status: (id) => gs.statusAgainst(dir, id, { session }),
146
+ status: (id, o) => {
147
+ const status = gs.statusAgainst(dir, id, {
148
+ session,
149
+ expectedIdentity: o?.expectedIdentity,
150
+ });
151
+ return {
152
+ checkpointIdentity: status.checkpointIdentity,
153
+ modified: status.modified,
154
+ added: status.added,
155
+ deleted: status.deleted,
156
+ ...(o?.includeWorkspaceBinding
157
+ ? { workspaceBinding: status.workspaceBinding }
158
+ : {}),
159
+ };
160
+ },
48
161
  diffText: (id, o) => gs.diffCheckpoint(dir, id, { session, stat: o?.stat }),
49
162
  restore: (id, o) => {
50
- const r = gs.rewindTo(dir, id, { session, dryRun: o?.dryRun });
163
+ const r = gs.rewindTo(dir, id, {
164
+ session,
165
+ dryRun: o?.dryRun,
166
+ skipSafety: o?.skipSafety,
167
+ expectedIdentity: o?.expectedIdentity,
168
+ expectedWorkspaceBinding: o?.expectedWorkspaceBinding,
169
+ expectedSafetyPlanIdentity: o?.expectedSafetyPlanIdentity,
170
+ onSafetyReady: o?.onSafetyReady,
171
+ onMutationStarted: o?.onMutationStarted,
172
+ onWorkspaceApplied: o?.onWorkspaceApplied,
173
+ });
51
174
  return {
52
175
  dryRun: !!r.dryRun,
53
176
  restoredCount: r.modified + r.recreated,
@@ -55,6 +178,9 @@ function gitEngine(gs, dir, session) {
55
178
  recreated: r.recreated,
56
179
  deleted: r.deleted,
57
180
  safetyId: r.safetyId,
181
+ safetyIdentity: r.safetyIdentity,
182
+ safetyPlanIdentity: r.safetyPlanIdentity,
183
+ safetyCoverage: r.safetyCoverage,
58
184
  };
59
185
  },
60
186
  remove: (id) => gs.deleteCheckpoint(dir, id, { session }),
@@ -76,14 +202,15 @@ function copyEngine(cs, dir) {
76
202
  };
77
203
  },
78
204
  list: () =>
79
- cs.listCheckpoints().map((c) => ({
205
+ cs.listCheckpoints({ cwd: dir }).map((c) => ({
80
206
  id: c.id,
81
207
  label: c.label,
82
208
  createdAt: c.createdAt,
83
209
  fileCount: c.fileCount,
210
+ identity: c.identity || null,
84
211
  })),
85
212
  show: (id) => {
86
- const m = cs.getCheckpoint(id);
213
+ const m = cs.getCheckpoint(id, { cwd: dir });
87
214
  if (!m) throw new Error(`no such checkpoint: ${id}`);
88
215
  return {
89
216
  id: m.id,
@@ -93,27 +220,50 @@ function copyEngine(cs, dir) {
93
220
  files: m.files.map((f) => ({ rel: f.rel, bytes: f.bytes })),
94
221
  };
95
222
  },
96
- status: (id) => {
97
- const d = cs.diffCheckpoint(id);
98
- return { modified: d.modified, added: [], deleted: d.deleted };
223
+ status: (id, o) => {
224
+ const d = cs.diffCheckpoint(id, {
225
+ cwd: dir,
226
+ expectedIdentity: o?.expectedIdentity,
227
+ expectedSafetyPlanIdentity: o?.expectedSafetyPlanIdentity,
228
+ });
229
+ return {
230
+ checkpointIdentity: d.checkpointIdentity,
231
+ modified: d.modified,
232
+ added: [],
233
+ deleted: d.deleted,
234
+ ...(o?.includeWorkspaceBinding
235
+ ? { workspaceBinding: d.workspaceBinding }
236
+ : {}),
237
+ };
99
238
  },
100
239
  diffText: () => null, // copy engine has no raw patch — caller uses status()
101
240
  restore: (id, o) => {
102
- const r = cs.restoreCheckpoint(id, { cwd: dir, dryRun: o?.dryRun });
241
+ const r = cs.restoreCheckpoint(id, {
242
+ cwd: dir,
243
+ dryRun: o?.dryRun,
244
+ skipSafety: o?.skipSafety,
245
+ expectedIdentity: o?.expectedIdentity,
246
+ expectedWorkspaceBinding: o?.expectedWorkspaceBinding,
247
+ expectedSafetyPlanIdentity: o?.expectedSafetyPlanIdentity,
248
+ onSafetyReady: o?.onSafetyReady,
249
+ onMutationStarted: o?.onMutationStarted,
250
+ onWorkspaceApplied: o?.onWorkspaceApplied,
251
+ });
103
252
  return {
104
253
  dryRun: !!r.dryRun,
105
254
  restoredCount: r.restored.length,
106
255
  restored: r.restored,
107
256
  missingBlob: r.missingBlob,
108
257
  safetyId: r.safetyId,
258
+ safetyIdentity: r.safetyIdentity,
259
+ safetyPlanIdentity: r.safetyPlanIdentity,
260
+ safetyCoverage: r.safetyCoverage,
261
+ createdPaths: r.createdPaths,
262
+ deletedPaths: r.deletedPaths,
109
263
  };
110
264
  },
111
- remove: (id) => cs.deleteCheckpoint(id),
112
- clear: () => {
113
- const all = cs.listCheckpoints();
114
- for (const c of all) cs.deleteCheckpoint(c.id);
115
- return all.length;
116
- },
265
+ remove: (id) => cs.deleteCheckpoint(id, { cwd: dir }),
266
+ clear: () => cs.clearCheckpoints({ cwd: dir }),
117
267
  };
118
268
  }
119
269
 
@@ -125,13 +275,149 @@ async function pickEngine(dir, session) {
125
275
  return copyEngine(cs, dir);
126
276
  }
127
277
 
278
+ function loadTimelineContext(engine, sessionId) {
279
+ const binding = loadTurnBindingLog(sessionId);
280
+ const checkpoints = engine.list();
281
+ const headHash = findLatestEvent(sessionId, null)?.hash || null;
282
+ const timeline = buildCheckpointTimeline({
283
+ sessionId,
284
+ turns: binding,
285
+ checkpoints,
286
+ headHash,
287
+ });
288
+ return {
289
+ binding,
290
+ checkpoints,
291
+ headHash,
292
+ timeline,
293
+ messages: readVerifiedMessages(sessionId),
294
+ };
295
+ }
296
+
297
+ function printTimelineActionResult(result, asJson) {
298
+ if (asJson) {
299
+ console.log(JSON.stringify(result, null, 2));
300
+ return;
301
+ }
302
+ if (result?.ok === false) {
303
+ logger.error(
304
+ chalk.red(
305
+ `${result.code || "TIMELINE_ACTION_FAILED"}: ${result.error || "request rejected"}`,
306
+ ),
307
+ );
308
+ return;
309
+ }
310
+ logger.log(
311
+ chalk.green(
312
+ `${result.mode === "preview" ? "Preview" : "Completed"}: ${result.action} at ${result.turnId}`,
313
+ ),
314
+ );
315
+ for (const warning of result.warnings || []) {
316
+ logger.log(chalk.yellow(` ${warning}`));
317
+ }
318
+ }
319
+
128
320
  const tag = (engine) => chalk.dim(engine.kind === "git" ? "[git]" : "[copy]");
129
321
 
130
- export function registerCheckpointCommand(program) {
322
+ function isCodeRestoreAction(action) {
323
+ return action === "restore-code" || action === "restore-both";
324
+ }
325
+
326
+ function workspaceStaleError(message = "workspace changed; preview again") {
327
+ const error = new Error(message);
328
+ error.code = "TIMELINE_WORKSPACE_STALE";
329
+ return error;
330
+ }
331
+
332
+ function restoreWorkspaceStaleError(
333
+ message = "workspace changed before the restore lock was acquired; retry the restore",
334
+ ) {
335
+ const error = new Error(message);
336
+ error.code = "CHECKPOINT_WORKSPACE_STALE";
337
+ return error;
338
+ }
339
+
340
+ function directRestoreTargetCount(preview) {
341
+ const groups = [preview?.modified, preview?.added, preview?.deleted];
342
+ if (groups.some((group) => !Array.isArray(group))) {
343
+ throw restoreWorkspaceStaleError(
344
+ "checkpoint restore target count is unavailable; retry the restore",
345
+ );
346
+ }
347
+ const total = groups.reduce((sum, group) => sum + group.length, 0);
348
+ if (!Number.isSafeInteger(total)) {
349
+ throw restoreWorkspaceStaleError(
350
+ "checkpoint restore target count is invalid; retry the restore",
351
+ );
352
+ }
353
+ return total;
354
+ }
355
+
356
+ function directRestorePlan({
357
+ engine,
358
+ checkpointId,
359
+ checkpointNamespace,
360
+ preview,
361
+ authorization,
362
+ }) {
363
+ const checkpointIdentity = preview?.checkpointIdentity;
364
+ const workspaceBinding = preview?.workspaceBinding;
365
+ const workspaceRoot = workspaceBinding?.workspaceRoot;
366
+ if (
367
+ typeof checkpointIdentity !== "string" ||
368
+ checkpointIdentity.length === 0 ||
369
+ !workspaceRoot
370
+ ) {
371
+ throw restoreWorkspaceStaleError(
372
+ "checkpoint immutable identity or workspace scope is unavailable; retry the restore",
373
+ );
374
+ }
375
+ const targetCount = directRestoreTargetCount(preview);
376
+ return {
377
+ restoreKind: engine.kind,
378
+ restoreSurface: "direct",
379
+ checkpointId,
380
+ checkpointIdentity,
381
+ checkpointNamespace,
382
+ workspaceRoot,
383
+ workspaceBinding,
384
+ targetCount,
385
+ confirmationDigest: computeCheckpointRestoreDigest(
386
+ "cc-checkpoint-restore-direct-confirmation-v1",
387
+ {
388
+ authorization,
389
+ restoreKind: engine.kind,
390
+ checkpointId,
391
+ checkpointIdentity,
392
+ checkpointNamespace,
393
+ workspaceBinding,
394
+ targetCount,
395
+ },
396
+ ),
397
+ };
398
+ }
399
+
400
+ export function registerCheckpointCommand(program, dependencies = {}) {
401
+ const withWorkspaceLockSync =
402
+ dependencies.withWorkspaceLockSync || withCanonicalWorkspaceLockSync;
403
+ const createCheckpointRestoreSagaStore =
404
+ dependencies.createCheckpointRestoreSagaStore ||
405
+ ((options) => new CheckpointRestoreSagaStore(options));
406
+ const workspaceLockOwnerDigest =
407
+ dependencies.computeCheckpointRestoreWorkspaceLockOwnerDigest ||
408
+ computeCheckpointRestoreWorkspaceLockOwnerDigest;
409
+ const runCheckpointRestore =
410
+ dependencies.runCheckpointRestoreOperation || runCheckpointRestoreOperation;
131
411
  const cp = program
132
412
  .command("checkpoint")
133
413
  .description("Snapshot / rewind file state (git-plumbing, copy fallback)");
134
414
 
415
+ registerManagedCheckpointCommands(cp);
416
+ registerCheckpointRestoreRecoveryCommands(
417
+ cp,
418
+ dependencies.checkpointRestoreRecovery,
419
+ );
420
+
135
421
  cp.command("create [paths...]")
136
422
  .description(
137
423
  "Snapshot the work tree (git) or the given files/dirs (fallback)",
@@ -223,6 +509,566 @@ export function registerCheckpointCommand(program) {
223
509
  }
224
510
  });
225
511
 
512
+ cp.command("timeline")
513
+ .description(
514
+ "Project persisted turns, checkpoints, side effects, and rewind actions",
515
+ )
516
+ .option("-d, --dir <dir>", "Target directory", ".")
517
+ .option("-s, --session <id>", "Checkpoint/session binding", "default")
518
+ .option("--json", "Output the canonical versioned projection as JSON")
519
+ .action(async (options) => {
520
+ try {
521
+ const dir = resolve(options.dir);
522
+ const engine = await pickEngine(dir, options.session);
523
+ const { timeline } = loadTimelineContext(engine, options.session);
524
+ if (options.json) {
525
+ console.log(JSON.stringify(timeline, null, 2));
526
+ return;
527
+ }
528
+
529
+ const projection = projectCheckpointTimeline(timeline);
530
+ if (projection.entries.length === 0) {
531
+ logger.log(
532
+ chalk.gray(
533
+ timeline.unboundMarkers.length > 0
534
+ ? `${timeline.unboundMarkers.length} checkpoint/marker(s) are not bound to a persisted turn.`
535
+ : "No persisted checkpoint timeline for this session.",
536
+ ),
537
+ );
538
+ return;
539
+ }
540
+ for (const entry of projection.entries) {
541
+ const coverage =
542
+ entry.coverage === "full"
543
+ ? chalk.green(entry.coverage)
544
+ : entry.coverage === "partial"
545
+ ? chalk.yellow(entry.coverage)
546
+ : chalk.red(entry.coverage);
547
+ logger.log(
548
+ `${chalk.cyan(entry.turnId)} ${coverage} ` +
549
+ `${entry.markerKinds.join(", ") || "no markers"} ` +
550
+ `${entry.enabledActions.join(", ") || "no actions"}`,
551
+ );
552
+ if (entry.excludedPaths.length > 0) {
553
+ logger.log(
554
+ chalk.yellow(` excluded: ${entry.excludedPaths.join(", ")}`),
555
+ );
556
+ }
557
+ if (entry.irreversibleSideEffects.length > 0) {
558
+ logger.log(
559
+ chalk.red(
560
+ ` irreversible: ${entry.irreversibleSideEffects.join(", ")}`,
561
+ ),
562
+ );
563
+ }
564
+ }
565
+ } catch (err) {
566
+ logger.error(chalk.red(`checkpoint timeline failed: ${err.message}`));
567
+ process.exitCode = 1;
568
+ }
569
+ });
570
+
571
+ cp.command("action")
572
+ .description(
573
+ "Preview or commit a CLI-authored checkpoint timeline submission",
574
+ )
575
+ .requiredOption(
576
+ "--submission <json>",
577
+ "Exact action envelope embedded in checkpoint timeline --json",
578
+ )
579
+ .option("-d, --dir <dir>", "Target directory", ".")
580
+ .option("-s, --session <id>", "Checkpoint/session binding", "default")
581
+ .option("--preview", "Validate and preview without writing")
582
+ .option("--confirm", "Commit after an IDE/user confirmation")
583
+ .option("--json", "Output the versioned result as JSON")
584
+ .action(async (options) => {
585
+ let output;
586
+ try {
587
+ if (options.preview === options.confirm) {
588
+ const error = new Error(
589
+ "choose exactly one of --preview or --confirm",
590
+ );
591
+ error.code = "TIMELINE_CONFIRMATION_REQUIRED";
592
+ throw error;
593
+ }
594
+ if (String(options.submission).length > 16_384) {
595
+ const error = new Error("timeline submission is too large");
596
+ error.code = "TIMELINE_SUBMISSION_INVALID";
597
+ throw error;
598
+ }
599
+ let submittedEnvelope;
600
+ try {
601
+ submittedEnvelope = JSON.parse(options.submission);
602
+ } catch {
603
+ const error = new Error("timeline submission must be valid JSON");
604
+ error.code = "TIMELINE_SUBMISSION_INVALID";
605
+ throw error;
606
+ }
607
+
608
+ const dir = resolve(options.dir);
609
+ const engine = await pickEngine(dir, options.session);
610
+ const planForContext = (authoritativeContext) => {
611
+ const validation = options.preview
612
+ ? validateCheckpointTimelineSubmission(
613
+ authoritativeContext.timeline,
614
+ submittedEnvelope,
615
+ )
616
+ : validateCheckpointTimelineConfirmationSubmission(
617
+ authoritativeContext.timeline,
618
+ submittedEnvelope,
619
+ );
620
+ if (!validation.ok) {
621
+ const error = new Error(
622
+ validation.code === "TIMELINE_STALE"
623
+ ? "checkpoint timeline is stale; refresh before retrying"
624
+ : "checkpoint timeline submission was rejected",
625
+ );
626
+ error.code = validation.code;
627
+ throw error;
628
+ }
629
+ const authoritativeSubmission = validation.submission;
630
+ const checkpointIdentity =
631
+ authoritativeSubmission.checkpointIdentity || null;
632
+ let codePreview = null;
633
+ if (isCodeRestoreAction(authoritativeSubmission.action)) {
634
+ if (!checkpointIdentity) {
635
+ const error = new Error(
636
+ "checkpoint immutable identity is unavailable; refresh or recreate it",
637
+ );
638
+ error.code = "TIMELINE_CHECKPOINT_IDENTITY_INVALID";
639
+ throw error;
640
+ }
641
+ codePreview = engine.status(authoritativeSubmission.checkpointId, {
642
+ expectedIdentity: checkpointIdentity,
643
+ includeWorkspaceBinding: true,
644
+ });
645
+ }
646
+ const authoritativePlan = planCheckpointTimelineAction({
647
+ timeline: authoritativeContext.timeline,
648
+ submission: authoritativeSubmission,
649
+ messages: authoritativeContext.messages,
650
+ codePreview,
651
+ });
652
+ if (!authoritativePlan.ok) {
653
+ const error = new Error(
654
+ authoritativePlan.code === "TIMELINE_STALE"
655
+ ? "checkpoint timeline is stale; refresh before retrying"
656
+ : "checkpoint timeline submission was rejected",
657
+ );
658
+ error.code = authoritativePlan.code;
659
+ throw error;
660
+ }
661
+ return {
662
+ submission: authoritativeSubmission,
663
+ planned: authoritativePlan,
664
+ codePreview,
665
+ };
666
+ };
667
+
668
+ let context = loadTimelineContext(engine, options.session);
669
+ let { submission, planned } = planForContext(context);
670
+ if (options.preview) {
671
+ output = planned.preview;
672
+ printTimelineActionResult(output, options.json);
673
+ return;
674
+ }
675
+
676
+ if (
677
+ !checkpointTimelineConfirmationsMatch(
678
+ planned.preview.confirmationSubmission,
679
+ submittedEnvelope,
680
+ )
681
+ ) {
682
+ const error = new Error(
683
+ isCodeRestoreAction(submission.action)
684
+ ? "workspace changed after checkpoint preview; preview again"
685
+ : "timeline confirmation no longer matches the current plan",
686
+ );
687
+ error.code = isCodeRestoreAction(submission.action)
688
+ ? "TIMELINE_WORKSPACE_STALE"
689
+ : "TIMELINE_CONFIRMATION_INVALID";
690
+ throw error;
691
+ }
692
+
693
+ let checkpointIdentity = submission.checkpointIdentity || null;
694
+ let restoreExecution = null;
695
+ let restoreOperationId = null;
696
+
697
+ const executeUnderSessionAuthority = ({
698
+ operationId = null,
699
+ workspaceLease = null,
700
+ commitIntent = null,
701
+ restoreWorkspace = null,
702
+ } = {}) => {
703
+ let durableSessionCommitHash = null;
704
+ const transactionResult = withSessionAuthorityTransaction(
705
+ options.session,
706
+ context.headHash,
707
+ (transaction) => {
708
+ workspaceLease?.assertOwned();
709
+ const intent = transaction.appendAuthorityEvent(
710
+ CHECKPOINT_TIMELINE_INTENT_EVENT,
711
+ {
712
+ ...(operationId ? { operationId } : {}),
713
+ revision: context.timeline.revision,
714
+ action: submission.action,
715
+ turnId: submission.turnId,
716
+ checkpointId: submission.checkpointId || null,
717
+ checkpointIdentity,
718
+ workspaceDir: dir,
719
+ workspaceScopeIdentity:
720
+ planned.workspaceBinding?.scopeIdentity || null,
721
+ workspacePrestateIdentity:
722
+ planned.workspaceBinding?.prestateIdentity || null,
723
+ workspaceWritePlanIdentity:
724
+ planned.workspaceBinding?.writePlanIdentity || null,
725
+ workspaceTargetPoststateIdentity:
726
+ planned.workspaceBinding?.targetPoststateIdentity || null,
727
+ confirmationDigest:
728
+ planned.preview.confirmationSubmission.digest,
729
+ },
730
+ );
731
+ const result = {};
732
+ try {
733
+ if (commitIntent) {
734
+ try {
735
+ commitIntent(
736
+ checkpointRestoreDigest(
737
+ "cc-checkpoint-restore-intent-commit-v1",
738
+ intent.hash,
739
+ ),
740
+ );
741
+ } catch (error) {
742
+ // The transcript intent append precedes the short saga CAS.
743
+ // If the CAS fails, recovery must reconcile the durable
744
+ // transcript instead of treating this as a pre-intent abort.
745
+ if (error && typeof error === "object") {
746
+ error.checkpointRestoreSessionIntentCommitted = true;
747
+ // Let the orchestrator attach the post-settlement saga
748
+ // position rather than leaking this failed CAS's stale
749
+ // prepared-phase snapshot as the recovery status.
750
+ error.checkpointRestoreSagaPhase = null;
751
+ error.checkpointRestoreSagaSeq = null;
752
+ error.checkpointRestoreSagaHeadHash = null;
753
+ }
754
+ throw error;
755
+ }
756
+ }
757
+
758
+ if (restoreWorkspace) {
759
+ workspaceLease?.assertOwned();
760
+ result.code = restoreWorkspace();
761
+ transaction.retainRecoveryEvidence({
762
+ safetyId: result.code?.safetyId,
763
+ safetyIdentity: result.code?.safetyIdentity,
764
+ safetyPlanIdentity: result.code?.safetyPlanIdentity,
765
+ safetyCoverage: result.code?.safetyCoverage,
766
+ restorePhase: "workspace-applied",
767
+ createdPaths: result.code?.createdPaths,
768
+ });
769
+ workspaceLease?.assertOwned();
770
+ }
771
+
772
+ if (planned.commit.branchPlan) {
773
+ result.branch = createBranchSession({
774
+ branchSessionId: planned.commit.branchPlan.branchSessionId,
775
+ parentSessionId: options.session,
776
+ parentTurnId: submission.turnId,
777
+ messages: planned.commit.messages,
778
+ meta: { title: `Branch of ${options.session}` },
779
+ });
780
+ transaction.retainRecoveryEvidence({
781
+ branchSessionId:
782
+ result.branch?.branchSessionId ||
783
+ planned.commit.branchPlan.branchSessionId,
784
+ });
785
+ } else if (planned.commit.messages) {
786
+ context.binding.pruneFromOffset(
787
+ planned.commit.bindingPruneOffset,
788
+ );
789
+ const committed = transaction.appendAuthorityEvent(
790
+ TURN_BINDING_TIMELINE_EVENT,
791
+ {
792
+ ...(operationId ? { operationId } : {}),
793
+ action: submission.action,
794
+ sourceRevision: context.timeline.revision,
795
+ turnId: submission.turnId,
796
+ messages: planned.commit.messages,
797
+ binding: context.binding.toJSON(),
798
+ },
799
+ );
800
+ result.conversation = {
801
+ messages: planned.commit.messages.length,
802
+ commitHash: committed.hash,
803
+ };
804
+ }
805
+
806
+ workspaceLease?.assertOwned();
807
+ const completedAudit = transaction.appendAuthorityEvent(
808
+ CHECKPOINT_TIMELINE_AUDIT_EVENT,
809
+ {
810
+ ...(operationId ? { operationId } : {}),
811
+ revision: context.timeline.revision,
812
+ action: submission.action,
813
+ turnId: submission.turnId,
814
+ checkpointId: submission.checkpointId || null,
815
+ checkpointIdentity,
816
+ workspaceDir: dir,
817
+ workspaceScopeIdentity:
818
+ planned.workspaceBinding?.scopeIdentity || null,
819
+ workspacePrestateIdentity:
820
+ planned.workspaceBinding?.prestateIdentity || null,
821
+ workspaceWritePlanIdentity:
822
+ planned.workspaceBinding?.writePlanIdentity || null,
823
+ workspaceTargetPoststateIdentity:
824
+ planned.workspaceBinding?.targetPoststateIdentity || null,
825
+ confirmationDigest:
826
+ planned.preview.confirmationSubmission.digest,
827
+ status: "completed",
828
+ branchSessionId: result.branch?.branchSessionId || null,
829
+ safetyCheckpointId: result.code?.safetyId || null,
830
+ safetyCheckpointIdentity:
831
+ result.code?.safetyIdentity || null,
832
+ safetyPlanIdentity: result.code?.safetyPlanIdentity || null,
833
+ safetyCoverage: result.code?.safetyCoverage || null,
834
+ },
835
+ );
836
+ durableSessionCommitHash = completedAudit.hash;
837
+ } catch (error) {
838
+ if (error && typeof error === "object") {
839
+ error.safetyId ||= result.code?.safetyId || null;
840
+ error.safetyIdentity ||= result.code?.safetyIdentity || null;
841
+ error.safetyPlanIdentity ||=
842
+ result.code?.safetyPlanIdentity || null;
843
+ error.safetyCoverage ||= result.code?.safetyCoverage || null;
844
+ if (result.code && !error.restorePhase) {
845
+ error.restorePhase = "workspace-applied";
846
+ }
847
+ if (!Array.isArray(error.createdPaths)) {
848
+ error.createdPaths = Array.isArray(
849
+ result.code?.createdPaths,
850
+ )
851
+ ? [...result.code.createdPaths]
852
+ : [];
853
+ }
854
+ error.branchSessionId ||=
855
+ result.branch?.branchSessionId ||
856
+ planned.commit.branchPlan?.branchSessionId ||
857
+ null;
858
+ }
859
+ try {
860
+ transaction.appendAuthorityEvent(
861
+ CHECKPOINT_TIMELINE_AUDIT_EVENT,
862
+ {
863
+ ...(operationId ? { operationId } : {}),
864
+ revision: context.timeline.revision,
865
+ action: submission.action,
866
+ turnId: submission.turnId,
867
+ checkpointId: submission.checkpointId || null,
868
+ checkpointIdentity,
869
+ workspaceDir: dir,
870
+ workspaceScopeIdentity:
871
+ planned.workspaceBinding?.scopeIdentity || null,
872
+ workspacePrestateIdentity:
873
+ planned.workspaceBinding?.prestateIdentity || null,
874
+ workspaceWritePlanIdentity:
875
+ planned.workspaceBinding?.writePlanIdentity || null,
876
+ workspaceTargetPoststateIdentity:
877
+ planned.workspaceBinding?.targetPoststateIdentity ||
878
+ null,
879
+ confirmationDigest:
880
+ planned.preview.confirmationSubmission.digest,
881
+ status: "failed",
882
+ failureCode: checkpointRestoreErrorCode(error),
883
+ workspaceState: restoreWorkspace
884
+ ? "unknown"
885
+ : "unchanged",
886
+ branchSessionId:
887
+ result.branch?.branchSessionId ||
888
+ planned.commit.branchPlan?.branchSessionId ||
889
+ null,
890
+ safetyCheckpointId:
891
+ result.code?.safetyId || error?.safetyId || null,
892
+ safetyCheckpointIdentity:
893
+ result.code?.safetyIdentity ||
894
+ error?.safetyIdentity ||
895
+ null,
896
+ safetyPlanIdentity:
897
+ result.code?.safetyPlanIdentity ||
898
+ error?.safetyPlanIdentity ||
899
+ null,
900
+ safetyCoverage:
901
+ result.code?.safetyCoverage ||
902
+ error?.safetyCoverage ||
903
+ null,
904
+ createdPaths: Array.isArray(error?.createdPaths)
905
+ ? error.createdPaths.slice(0, 256)
906
+ : [],
907
+ },
908
+ );
909
+ } catch (auditError) {
910
+ // An authority append can fail after bytes reach the transcript.
911
+ // Retain the first operation error as the transaction's nested
912
+ // diagnosis and let a poisoned writer/final settlement report
913
+ // commitState=unknown instead of appending from a stale head.
914
+ if (error && typeof error === "object") {
915
+ error.checkpointAuditError = auditError;
916
+ }
917
+ }
918
+ throw error;
919
+ }
920
+ return result;
921
+ },
922
+ );
923
+
924
+ if (operationId) {
925
+ workspaceLease?.assertOwned();
926
+ if (!durableSessionCommitHash) {
927
+ const error = new Error(
928
+ "checkpoint restore session settlement hash is unavailable",
929
+ );
930
+ error.code = "CHECKPOINT_RESTORE_SESSION_BOUNDARY_MISSING";
931
+ error.commitState = "unknown";
932
+ throw error;
933
+ }
934
+ return {
935
+ result: transactionResult,
936
+ sessionCommitDigest: checkpointRestoreDigest(
937
+ "cc-checkpoint-restore-session-commit-v1",
938
+ durableSessionCommitHash,
939
+ ),
940
+ };
941
+ }
942
+ return transactionResult;
943
+ };
944
+
945
+ const buildTimelineRestorePlan = () => {
946
+ const workspaceRoot = planned.workspaceBinding?.workspaceRoot;
947
+ if (!workspaceRoot) {
948
+ throw workspaceStaleError(
949
+ "checkpoint restore scope is unavailable; preview again",
950
+ );
951
+ }
952
+ return {
953
+ restoreKind: engine.kind,
954
+ restoreSurface: "timeline",
955
+ checkpointId: submission.checkpointId,
956
+ checkpointIdentity,
957
+ checkpointNamespace: options.session,
958
+ workspaceRoot,
959
+ workspaceBinding: planned.workspaceBinding,
960
+ targetCount: checkpointRestoreTargetCount(planned),
961
+ confirmationDigest: planned.preview.confirmationSubmission.digest,
962
+ sessionId: options.session,
963
+ timelineEntryId: submission.turnId,
964
+ };
965
+ };
966
+
967
+ let result;
968
+ if (isCodeRestoreAction(submission.action)) {
969
+ const initialRestorePlan = buildTimelineRestorePlan();
970
+ restoreExecution = runCheckpointRestore({
971
+ plan: initialRestorePlan,
972
+ revalidate: () => {
973
+ // Both the session head and the full workspace write plan can
974
+ // change while this process waits for the workspace lock.
975
+ const lockedContext = loadTimelineContext(
976
+ engine,
977
+ options.session,
978
+ );
979
+ const lockedAction = planForContext(lockedContext);
980
+ if (
981
+ !checkpointTimelineConfirmationsMatch(
982
+ lockedAction.planned.preview.confirmationSubmission,
983
+ submittedEnvelope,
984
+ )
985
+ ) {
986
+ throw workspaceStaleError(
987
+ "workspace or checkpoint timeline changed while waiting for the restore lock; preview again",
988
+ );
989
+ }
990
+ context = lockedContext;
991
+ submission = lockedAction.submission;
992
+ planned = lockedAction.planned;
993
+ checkpointIdentity = submission.checkpointIdentity || null;
994
+ return buildTimelineRestorePlan();
995
+ },
996
+ restore: ({ expectedIdentity, expectedWorkspaceBinding, hooks }) =>
997
+ engine.restore(submission.checkpointId, {
998
+ expectedIdentity,
999
+ expectedWorkspaceBinding,
1000
+ ...hooks,
1001
+ }),
1002
+ withSessionAuthority: (authority) => {
1003
+ try {
1004
+ return executeUnderSessionAuthority(authority);
1005
+ } catch (error) {
1006
+ const retained = error?.transactionRecoveryEvidence;
1007
+ if (
1008
+ error &&
1009
+ typeof error === "object" &&
1010
+ retained &&
1011
+ typeof retained === "object"
1012
+ ) {
1013
+ error.safetyId ||= retained.safetyId || null;
1014
+ error.safetyIdentity ||= retained.safetyIdentity || null;
1015
+ error.safetyPlanIdentity ||=
1016
+ retained.safetyPlanIdentity || null;
1017
+ error.safetyCoverage ||= retained.safetyCoverage || null;
1018
+ error.restorePhase ||= retained.restorePhase || null;
1019
+ }
1020
+ throw error;
1021
+ }
1022
+ },
1023
+ dependencies: {
1024
+ withWorkspaceLockSync,
1025
+ createSagaStore: createCheckpointRestoreSagaStore,
1026
+ computeWorkspaceLockOwnerDigest: workspaceLockOwnerDigest,
1027
+ },
1028
+ });
1029
+ restoreOperationId = restoreExecution.operationId;
1030
+ result = restoreExecution.result;
1031
+ } else {
1032
+ result = executeUnderSessionAuthority();
1033
+ }
1034
+ let nextContext = null;
1035
+ let nextContextWarning = null;
1036
+ try {
1037
+ nextContext = loadTimelineContext(engine, options.session);
1038
+ } catch (reloadError) {
1039
+ if (restoreExecution?.saga?.phase !== "completed") throw reloadError;
1040
+ nextContextWarning = boundedCheckpointRestoreText(
1041
+ `restore completed, but the next timeline revision could not be reloaded: ${reloadError?.code || reloadError?.message || "reload failed"}`,
1042
+ "restore completed, but the next timeline revision could not be reloaded",
1043
+ 512,
1044
+ );
1045
+ }
1046
+ output = {
1047
+ schema: CHECKPOINT_TIMELINE_RESULT_SCHEMA,
1048
+ version: CHECKPOINT_TIMELINE_RESULT_VERSION,
1049
+ ok: true,
1050
+ mode: "executed",
1051
+ action: submission.action,
1052
+ sessionId: options.session,
1053
+ turnId: submission.turnId,
1054
+ revision: context.timeline.revision,
1055
+ nextRevision: nextContext?.timeline?.revision || null,
1056
+ ...(restoreOperationId ? { operationId: restoreOperationId } : {}),
1057
+ result,
1058
+ warnings: [
1059
+ ...planned.preview.warnings,
1060
+ ...(restoreExecution?.warnings || []),
1061
+ ...(nextContextWarning ? [nextContextWarning] : []),
1062
+ ],
1063
+ };
1064
+ printTimelineActionResult(output, options.json);
1065
+ } catch (error) {
1066
+ output = timelineActionError(error);
1067
+ printTimelineActionResult(output, options.json);
1068
+ process.exitCode = 1;
1069
+ }
1070
+ });
1071
+
226
1072
  cp.command("show <id>")
227
1073
  .description("Show a checkpoint's files, or its diff vs current state")
228
1074
  .option("-d, --dir <dir>", "Target directory", ".")
@@ -307,12 +1153,18 @@ export function registerCheckpointCommand(program) {
307
1153
  return;
308
1154
  }
309
1155
 
310
- // Destructive: overwrites current files. Require --force when not a TTY;
311
- // prompt when interactive.
1156
+ // Destructive: bind the exact workspace state that is displayed (or
1157
+ // immediately preflighted for --force), then require the engine to
1158
+ // observe the same full state before safety creation or file writes.
1159
+ // Require --force when not a TTY; prompt when interactive.
1160
+ const restorePreview = engine.status(id, {
1161
+ includeWorkspaceBinding: true,
1162
+ });
312
1163
  if (!options.force) {
313
- const d = engine.status(id);
314
1164
  const willChange =
315
- d.modified.length + d.deleted.length + (d.added?.length || 0);
1165
+ restorePreview.modified.length +
1166
+ restorePreview.deleted.length +
1167
+ (restorePreview.added?.length || 0);
316
1168
  if (process.stdin.isTTY) {
317
1169
  const { confirm } = await import("@inquirer/prompts");
318
1170
  const ok = await confirm({
@@ -334,9 +1186,50 @@ export function registerCheckpointCommand(program) {
334
1186
  }
335
1187
  }
336
1188
 
337
- const r = engine.restore(id);
1189
+ const authorization = options.force ? "force" : "interactive";
1190
+ const initialPlan = directRestorePlan({
1191
+ engine,
1192
+ checkpointId: id,
1193
+ checkpointNamespace: options.session,
1194
+ preview: restorePreview,
1195
+ authorization,
1196
+ });
1197
+ const execution = runCheckpointRestore({
1198
+ plan: initialPlan,
1199
+ revalidate: () => {
1200
+ const lockedPreview = engine.status(id, {
1201
+ expectedIdentity: initialPlan.checkpointIdentity,
1202
+ includeWorkspaceBinding: true,
1203
+ });
1204
+ return directRestorePlan({
1205
+ engine,
1206
+ checkpointId: id,
1207
+ checkpointNamespace: options.session,
1208
+ preview: lockedPreview,
1209
+ authorization,
1210
+ });
1211
+ },
1212
+ restore: ({ expectedIdentity, expectedWorkspaceBinding, hooks }) =>
1213
+ engine.restore(id, {
1214
+ expectedIdentity,
1215
+ expectedWorkspaceBinding,
1216
+ ...hooks,
1217
+ }),
1218
+ dependencies: {
1219
+ withWorkspaceLockSync,
1220
+ createSagaStore: createCheckpointRestoreSagaStore,
1221
+ computeWorkspaceLockOwnerDigest: workspaceLockOwnerDigest,
1222
+ },
1223
+ });
1224
+ const r = execution.result;
1225
+ const directOutput = {
1226
+ ...r,
1227
+ operationId: execution.operationId,
1228
+ phase: execution.saga.phase,
1229
+ warnings: execution.warnings,
1230
+ };
338
1231
  if (options.json) {
339
- console.log(JSON.stringify(r, null, 2));
1232
+ console.log(JSON.stringify(directOutput, null, 2));
340
1233
  return;
341
1234
  }
342
1235
  logger.log(
@@ -362,8 +1255,43 @@ export function registerCheckpointCommand(program) {
362
1255
  chalk.red(` missing blobs (skipped): ${r.missingBlob.join(", ")}`),
363
1256
  );
364
1257
  }
1258
+ logger.log(
1259
+ chalk.gray(
1260
+ ` restore operation: ${execution.operationId} (${execution.saga.phase})`,
1261
+ ),
1262
+ );
1263
+ for (const warning of execution.warnings) {
1264
+ logger.log(chalk.yellow(` ${warning}`));
1265
+ }
365
1266
  } catch (err) {
366
- logger.error(chalk.red(`checkpoint restore failed: ${err.message}`));
1267
+ if (options.json) {
1268
+ console.log(
1269
+ JSON.stringify(
1270
+ {
1271
+ ok: false,
1272
+ code: err?.code || "CHECKPOINT_RESTORE_FAILED",
1273
+ error: err?.message || String(err),
1274
+ operationId:
1275
+ err?.checkpointRestoreOperationId || err?.operationId || null,
1276
+ phase: err?.checkpointRestoreSagaPhase || null,
1277
+ blockingOperationId:
1278
+ err?.ownerTransactionId ||
1279
+ err?.retainedOwner?.transactionId ||
1280
+ err?.priorOwner?.transactionId ||
1281
+ null,
1282
+ recoveryRequired: Boolean(
1283
+ err?.checkpointRestoreRecoveryRequired ||
1284
+ err?.workspaceLockRetained,
1285
+ ),
1286
+ workspaceLockRetained: err?.workspaceLockRetained === true,
1287
+ },
1288
+ null,
1289
+ 2,
1290
+ ),
1291
+ );
1292
+ } else {
1293
+ logger.error(chalk.red(`checkpoint restore failed: ${err.message}`));
1294
+ }
367
1295
  process.exitCode = 1;
368
1296
  }
369
1297
  });