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
@@ -7,6 +7,296 @@ import {
7
7
  import { createSessionRecord } from "../../runtime/contracts/session-record.js";
8
8
  import { loadSideEffectLedger } from "../../lib/side-effect-ledger-store.js";
9
9
  import { reconcileSideEffects } from "../../lib/side-effect-ledger.js";
10
+ import {
11
+ formatMcpLedgerRecoveryNotice,
12
+ loadMcpLedgerRecovery,
13
+ } from "../../lib/mcp-call-ledger-store.js";
14
+ import { isProxy } from "node:util/types";
15
+ import {
16
+ MCP_RECOVERY_INVALID_CODE,
17
+ classifyMcpRecoveryAdmission,
18
+ } from "../../lib/mcp-ledger-recovery-admission.js";
19
+ import { readSessionHostResumeState } from "../../lib/session-host-snapshot.js";
20
+ import { sanitizePersistedMessages } from "../../lib/session-message-provenance.js";
21
+
22
+ const PAYLOAD_DIGEST = /^sha256:[0-9a-f]{64}$/;
23
+ const RAW_AUTHORITY_HASH = /^[0-9a-f]{64}$/;
24
+ const MCP_REPLAY_DENY_FIELDS = new Set([
25
+ "ledgerId",
26
+ "serverName",
27
+ "toolName",
28
+ "inputBytes",
29
+ "replayDigest",
30
+ ]);
31
+ const MCP_RECOVERY_REMEDIATIONS = new Set([
32
+ "inspect_transcript",
33
+ "adjudicate_started_calls",
34
+ "exact_replay_denied",
35
+ ]);
36
+ const RESUME_RECOVERY_NOTICE = Symbol("cc.resume-recovery-notice");
37
+
38
+ function captureCanonicalHostSystemPrefix(session) {
39
+ if (Array.isArray(session?._canonicalHostSystemPrefix)) {
40
+ const explicit = sanitizePersistedMessages(
41
+ session._canonicalHostSystemPrefix,
42
+ { strict: true },
43
+ );
44
+ if (explicit.some((message) => message.role !== "system")) {
45
+ throw new TypeError("Canonical WS host prefix is invalid");
46
+ }
47
+ return Object.freeze(explicit.map((message) => Object.freeze(message)));
48
+ }
49
+ const persisted = sanitizePersistedMessages(session?.messages || [], {
50
+ strict: true,
51
+ });
52
+ const firstMessage = persisted[0] || null;
53
+ const prefix = [];
54
+ if (firstMessage?.role === "system") {
55
+ // A WS session is created with exactly one host-owned system prompt. Any
56
+ // later leading systems may be canonical summaries or recovery notices
57
+ // serialized by the DB compatibility mirror; they must not be promoted
58
+ // into the host prefix after a process restart.
59
+ prefix.push(Object.freeze(firstMessage));
60
+ }
61
+ const frozenPrefix = Object.freeze(prefix);
62
+ Object.defineProperty(session, "_canonicalHostSystemPrefix", {
63
+ configurable: true,
64
+ value: frozenPrefix,
65
+ });
66
+ return frozenPrefix;
67
+ }
68
+
69
+ function replaceResumeRecoveryNotice(session, notice) {
70
+ const previous = session?._resumeRecoveryNoticeMessage || null;
71
+ const messages = (
72
+ Array.isArray(session?.messages) ? session.messages : []
73
+ ).filter(
74
+ (message) =>
75
+ message !== previous && message?.[RESUME_RECOVERY_NOTICE] !== true,
76
+ );
77
+ let insertionIndex = 0;
78
+ while (messages[insertionIndex]?.role === "system") insertionIndex += 1;
79
+
80
+ let recoveryMessage = null;
81
+ if (typeof notice === "string" && notice.trim()) {
82
+ recoveryMessage = { role: "system", content: notice };
83
+ Object.defineProperty(recoveryMessage, RESUME_RECOVERY_NOTICE, {
84
+ value: true,
85
+ });
86
+ messages.splice(insertionIndex, 0, recoveryMessage);
87
+ }
88
+ session.messages = messages;
89
+ Object.defineProperty(session, "_resumeRecoveryNoticeMessage", {
90
+ configurable: true,
91
+ writable: true,
92
+ value: recoveryMessage,
93
+ });
94
+ }
95
+
96
+ function recoveryErrorCode(error, fallbackCode) {
97
+ try {
98
+ return typeof error?.code === "string" && error.code
99
+ ? error.code
100
+ : fallbackCode;
101
+ } catch {
102
+ return fallbackCode;
103
+ }
104
+ }
105
+
106
+ function ownDataValue(record, key, fallback = null) {
107
+ if (!record || typeof record !== "object" || isProxy(record)) {
108
+ const error = new TypeError(`MCP recovery ${key} record is not plain data`);
109
+ error.code = MCP_RECOVERY_INVALID_CODE;
110
+ throw error;
111
+ }
112
+ const descriptor = Object.getOwnPropertyDescriptor(record, key);
113
+ if (!descriptor) return fallback;
114
+ if (!("value" in descriptor)) {
115
+ const error = new TypeError(`MCP recovery ${key} must be a data property`);
116
+ error.code = MCP_RECOVERY_INVALID_CODE;
117
+ throw error;
118
+ }
119
+ return descriptor.value;
120
+ }
121
+
122
+ function recoveryString(value, fallback) {
123
+ if (value == null) return fallback;
124
+ if (typeof value === "string") return value;
125
+ const error = new TypeError("MCP recovery scalar must be a string");
126
+ error.code = MCP_RECOVERY_INVALID_CODE;
127
+ throw error;
128
+ }
129
+
130
+ function snapshotMcpRecord(record) {
131
+ const effectContract = ownDataValue(record, "effectContract", null);
132
+ let effect = "unknown";
133
+ if (effectContract != null) {
134
+ if (typeof effectContract !== "object" || isProxy(effectContract)) {
135
+ const error = new TypeError("MCP recovery effect contract is malformed");
136
+ error.code = MCP_RECOVERY_INVALID_CODE;
137
+ throw error;
138
+ }
139
+ effect = recoveryString(
140
+ ownDataValue(effectContract, "effect", "unknown"),
141
+ "unknown",
142
+ );
143
+ }
144
+ return Object.freeze({
145
+ ledgerId: recoveryString(ownDataValue(record, "ledgerId", null), null),
146
+ serverName: recoveryString(
147
+ ownDataValue(record, "serverName", "unknown"),
148
+ "unknown",
149
+ ),
150
+ toolName: recoveryString(
151
+ ownDataValue(record, "toolName", "unknown"),
152
+ "unknown",
153
+ ),
154
+ effect,
155
+ });
156
+ }
157
+
158
+ function snapshotMcpIncident(incident) {
159
+ return Object.freeze({
160
+ code: recoveryString(
161
+ ownDataValue(incident, "code", MCP_RECOVERY_INVALID_CODE),
162
+ MCP_RECOVERY_INVALID_CODE,
163
+ ),
164
+ ledgerId: recoveryString(ownDataValue(incident, "ledgerId", null), null),
165
+ });
166
+ }
167
+
168
+ function snapshotMcpReplayDeny(entry) {
169
+ if (!entry || typeof entry !== "object" || isProxy(entry)) {
170
+ const error = new TypeError("MCP replay deny entry is malformed");
171
+ error.code = MCP_RECOVERY_INVALID_CODE;
172
+ throw error;
173
+ }
174
+ const descriptors = Object.getOwnPropertyDescriptors(entry);
175
+ const fields = Object.keys(descriptors);
176
+ if (
177
+ fields.length !== MCP_REPLAY_DENY_FIELDS.size ||
178
+ fields.some((field) => !MCP_REPLAY_DENY_FIELDS.has(field)) ||
179
+ [...MCP_REPLAY_DENY_FIELDS].some(
180
+ (field) => !descriptors[field] || !("value" in descriptors[field]),
181
+ )
182
+ ) {
183
+ const error = new TypeError("MCP replay deny entry schema is invalid");
184
+ error.code = MCP_RECOVERY_INVALID_CODE;
185
+ throw error;
186
+ }
187
+ const snapshot = Object.freeze({
188
+ ledgerId: recoveryString(descriptors.ledgerId.value, null),
189
+ serverName: recoveryString(descriptors.serverName.value, null),
190
+ toolName: recoveryString(descriptors.toolName.value, null),
191
+ inputBytes: descriptors.inputBytes.value,
192
+ replayDigest: recoveryString(descriptors.replayDigest.value, null),
193
+ });
194
+ if (
195
+ !snapshot.ledgerId ||
196
+ !snapshot.serverName ||
197
+ !snapshot.toolName ||
198
+ !Number.isInteger(snapshot.inputBytes) ||
199
+ snapshot.inputBytes < 0 ||
200
+ !PAYLOAD_DIGEST.test(snapshot.replayDigest || "")
201
+ ) {
202
+ const error = new TypeError("MCP replay deny identity is invalid");
203
+ error.code = MCP_RECOVERY_INVALID_CODE;
204
+ throw error;
205
+ }
206
+ return snapshot;
207
+ }
208
+
209
+ function strictMcpRecoverySnapshot(recovery) {
210
+ if (recovery == null) {
211
+ const error = new TypeError("MCP recovery projection is missing");
212
+ error.code = MCP_RECOVERY_INVALID_CODE;
213
+ throw error;
214
+ }
215
+ const admission = classifyMcpRecoveryAdmission(recovery);
216
+ if (admission.reasonCode) {
217
+ const error = new TypeError("MCP recovery projection is malformed");
218
+ error.code = admission.reasonCode;
219
+ throw error;
220
+ }
221
+
222
+ // classifyMcpRecoveryAdmission rejects proxies/accessors first. Capture the
223
+ // two authority arrays exactly once as own data descriptors so a formatter
224
+ // or time-varying getter can never turn an unsafe projection into clean state.
225
+ const descriptors = Object.getOwnPropertyDescriptors(recovery);
226
+ const unsettledSource = descriptors.unsettled?.value;
227
+ const incidentsSource = descriptors.incidents?.value;
228
+ const replayDeniedSource = descriptors.replayDenied?.value;
229
+ if (
230
+ !Array.isArray(unsettledSource) ||
231
+ !Array.isArray(incidentsSource) ||
232
+ !Array.isArray(replayDeniedSource)
233
+ ) {
234
+ const error = new TypeError("MCP recovery arrays are unavailable");
235
+ error.code = MCP_RECOVERY_INVALID_CODE;
236
+ throw error;
237
+ }
238
+ const unsettled = Object.freeze(unsettledSource.map(snapshotMcpRecord));
239
+ const incidents = Object.freeze(incidentsSource.map(snapshotMcpIncident));
240
+ const replayDenied = Object.freeze(
241
+ replayDeniedSource.map(snapshotMcpReplayDeny),
242
+ );
243
+ const headHash = recoveryString(
244
+ ownDataValue(recovery, "headHash", null),
245
+ null,
246
+ );
247
+ const recoveryDigest = recoveryString(
248
+ ownDataValue(recovery, "recoveryDigest", null),
249
+ null,
250
+ );
251
+ if (
252
+ (headHash != null && !RAW_AUTHORITY_HASH.test(headHash)) ||
253
+ (recoveryDigest != null && !PAYLOAD_DIGEST.test(recoveryDigest))
254
+ ) {
255
+ const error = new TypeError("MCP recovery authority digest is invalid");
256
+ error.code = MCP_RECOVERY_INVALID_CODE;
257
+ throw error;
258
+ }
259
+ const remediation = recoveryString(
260
+ ownDataValue(recovery, "remediation", null),
261
+ null,
262
+ );
263
+ if (remediation !== null && !MCP_RECOVERY_REMEDIATIONS.has(remediation)) {
264
+ const error = new TypeError("MCP recovery remediation is invalid");
265
+ error.code = MCP_RECOVERY_INVALID_CODE;
266
+ throw error;
267
+ }
268
+ return Object.freeze({
269
+ admission,
270
+ unsettled,
271
+ incidents,
272
+ replayDenied,
273
+ headHash,
274
+ recoveryDigest,
275
+ remediation,
276
+ });
277
+ }
278
+
279
+ function failClosedMcpRecovery(
280
+ error,
281
+ fallbackCode = "CC_MCP_LEDGER_EVENT_READ_FAILED",
282
+ ) {
283
+ const code = recoveryErrorCode(error, fallbackCode);
284
+ const incident = Object.freeze({ code, ledgerId: null });
285
+ return Object.freeze({
286
+ count: 1,
287
+ unsettled: Object.freeze([]),
288
+ incidents: Object.freeze([incident]),
289
+ replayDenied: Object.freeze([]),
290
+ blockMode: "all",
291
+ headHash: null,
292
+ recoveryDigest: null,
293
+ remediation: "inspect_transcript",
294
+ notice:
295
+ "MCP recovery notice — the durable MCP ledger could not be verified. " +
296
+ "Do NOT automatically retry prior MCP actions; inspect the session " +
297
+ `transcript first (${code}).`,
298
+ });
299
+ }
10
300
 
11
301
  /**
12
302
  * P0-2: on a bridge/IDE resume, surface any irreversible tool that was in flight
@@ -14,9 +304,9 @@ import { reconcileSideEffects } from "../../lib/side-effect-ledger.js";
14
304
  * + short key + reason, never argument values) plus a human-readable notice, or
15
305
  * null when nothing needs verification. PURE apart from reading the ledger.
16
306
  */
17
- function buildResumeRecovery(sessionId) {
307
+ function buildSideEffectResumeRecovery(sessionId, loadLedger) {
18
308
  try {
19
- const ledger = loadSideEffectLedger(sessionId);
309
+ const ledger = loadLedger(sessionId);
20
310
  const plan = reconcileSideEffects(ledger);
21
311
  if (!plan.inspect.length) return null;
22
312
  const items = plan.plans
@@ -40,12 +330,116 @@ function buildResumeRecovery(sessionId) {
40
330
  ` • [${it.kind}]${it.key ? ` (${it.key})` : ""} — ${it.reason}`,
41
331
  )
42
332
  .join("\n");
43
- return { count: items.length, items, notice };
44
- } catch {
45
- return null;
333
+ return { count: items.length, items, incidents: [], notice };
334
+ } catch (error) {
335
+ const code = recoveryErrorCode(
336
+ error,
337
+ "CC_SIDE_EFFECT_LEDGER_RECOVERY_FAILED",
338
+ );
339
+ return {
340
+ count: 1,
341
+ items: [],
342
+ incidents: [{ code }],
343
+ notice:
344
+ "Side-effect recovery notice — the durable side-effect ledger could " +
345
+ "not be verified. Do NOT automatically retry prior irreversible " +
346
+ `operations until the transcript is inspected (${code}).`,
347
+ };
46
348
  }
47
349
  }
48
350
 
351
+ function buildMcpResumeRecovery(sessionId, loadRecovery, formatNotice) {
352
+ try {
353
+ const snapshot = strictMcpRecoverySnapshot(loadRecovery(sessionId));
354
+ const unsettled = Object.freeze(
355
+ snapshot.unsettled.map((record) =>
356
+ Object.freeze({
357
+ ledgerId: record.ledgerId,
358
+ serverName: record.serverName,
359
+ toolName: record.toolName,
360
+ effect: record.effect,
361
+ status: "outcome_unknown",
362
+ }),
363
+ ),
364
+ );
365
+ const incidents = snapshot.incidents;
366
+ const requiresInspection =
367
+ unsettled.length > 0 ||
368
+ incidents.length > 0 ||
369
+ snapshot.replayDenied.length > 0 ||
370
+ snapshot.admission.blockMode != null;
371
+ let notice = null;
372
+ if (requiresInspection) {
373
+ const formatterProjection = Object.freeze({
374
+ unsettled: Object.freeze(
375
+ snapshot.unsettled.map((record) =>
376
+ Object.freeze({
377
+ ledgerId: record.ledgerId,
378
+ serverName: record.serverName,
379
+ toolName: record.toolName,
380
+ effectContract: Object.freeze({ effect: record.effect }),
381
+ }),
382
+ ),
383
+ ),
384
+ incidents,
385
+ replayDenied: snapshot.replayDenied,
386
+ });
387
+ notice = formatNotice(formatterProjection);
388
+ if (notice != null && typeof notice !== "string") {
389
+ const error = new TypeError(
390
+ "MCP recovery formatter must return a synchronous string or null",
391
+ );
392
+ error.code = MCP_RECOVERY_INVALID_CODE;
393
+ throw error;
394
+ }
395
+ notice ||=
396
+ "MCP recovery notice — durable MCP state requires inspection. Do NOT " +
397
+ "automatically retry prior MCP actions until recovery is adjudicated.";
398
+ }
399
+ return Object.freeze({
400
+ count: unsettled.length + incidents.length + snapshot.replayDenied.length,
401
+ unsettled,
402
+ incidents,
403
+ headHash: snapshot.headHash,
404
+ recoveryDigest: snapshot.recoveryDigest,
405
+ replayDenied: snapshot.replayDenied,
406
+ remediation: snapshot.remediation,
407
+ notice,
408
+ ...(snapshot.admission.blockMode
409
+ ? { blockMode: snapshot.admission.blockMode }
410
+ : {}),
411
+ });
412
+ } catch (error) {
413
+ return failClosedMcpRecovery(error);
414
+ }
415
+ }
416
+
417
+ /**
418
+ * Build the de-identified recovery payload shared by the IDE envelope and the
419
+ * resumed model. Dependencies are injectable so fail-closed recovery can be
420
+ * tested without touching a user's durable session directory.
421
+ */
422
+ export function buildResumeRecovery(sessionId, dependencies = {}) {
423
+ const sideEffects = buildSideEffectResumeRecovery(
424
+ sessionId,
425
+ dependencies.loadSideEffectLedger || loadSideEffectLedger,
426
+ );
427
+ const mcp = buildMcpResumeRecovery(
428
+ sessionId,
429
+ dependencies.loadMcpLedgerRecovery || loadMcpLedgerRecovery,
430
+ dependencies.formatMcpLedgerRecoveryNotice || formatMcpLedgerRecoveryNotice,
431
+ );
432
+ if (!sideEffects && !mcp) return null;
433
+
434
+ return {
435
+ count: (sideEffects?.count || 0) + (mcp?.count || 0),
436
+ items: sideEffects?.items || [],
437
+ sideEffectIncidents: sideEffects?.incidents || [],
438
+ ...(mcp ? { mcp } : {}),
439
+ notice: [sideEffects?.notice, mcp?.notice].filter(Boolean).join("\n\n"),
440
+ };
441
+ }
442
+
49
443
  // Build a unified envelope for a solicited WS response. The bridge correlates
50
444
  // by `requestId` (the inbound request's id) and unwraps `payload` for callers
51
445
  // so existing flat-shape consumers keep working unchanged.
@@ -57,10 +451,10 @@ function envelopeResponse(type, id, payload, sessionId) {
57
451
  });
58
452
  }
59
453
 
60
- function envelopeError(id, code, message, sessionId) {
454
+ function envelopeError(id, code, message, sessionId, details = {}) {
61
455
  return createCodingAgentEvent(
62
456
  CODING_AGENT_EVENT_TYPES.ERROR,
63
- { code, message },
457
+ { ...details, code, message },
64
458
  {
65
459
  requestId: id,
66
460
  sessionId: sessionId || null,
@@ -94,6 +488,18 @@ async function ensureSessionHandler(server, ws, session) {
94
488
  session.interaction = new WebSocketInteractionAdapter(ws, session.id, {
95
489
  enablePhase5Envelopes,
96
490
  envelopeBus: server.envelopeBus || null,
491
+ onPendingApprovalChange: ({ type, payload }) => {
492
+ if (
493
+ server.sessionManager &&
494
+ typeof server.sessionManager.recordSessionStateEvent === "function"
495
+ ) {
496
+ server.sessionManager.recordSessionStateEvent(
497
+ session.id,
498
+ type,
499
+ payload,
500
+ );
501
+ }
502
+ },
97
503
  });
98
504
 
99
505
  // Route MCP elicitation through the authenticated WS question channel. The
@@ -257,6 +663,20 @@ export async function handleSessionResume(server, id, ws, message) {
257
663
  }
258
664
 
259
665
  const { sessionId } = message;
666
+ const canonicalResume = readSessionHostResumeState(sessionId);
667
+ if (canonicalResume && !canonicalResume.snapshot.verified) {
668
+ server._send(
669
+ ws,
670
+ envelopeError(
671
+ id,
672
+ "CC_SESSION_HOST_SNAPSHOT_UNVERIFIED",
673
+ "Canonical JSONL session is not verified; resume was refused",
674
+ sessionId,
675
+ { sessionSnapshot: canonicalResume.snapshot },
676
+ ),
677
+ );
678
+ return;
679
+ }
260
680
  const session = server.sessionManager.resumeSession(sessionId);
261
681
 
262
682
  if (!session) {
@@ -272,28 +692,116 @@ export async function handleSessionResume(server, id, ws, message) {
272
692
  return;
273
693
  }
274
694
 
695
+ // A JSONL transcript is the cross-host fact source. A fully verified one
696
+ // replaces a stale DB/WS copy. The damaged case returned above before the
697
+ // manager or agent handler could be resumed; only a genuinely absent JSONL
698
+ // transcript keeps the legacy WS-store compatibility path.
699
+ const sessionSnapshot = canonicalResume?.snapshot || null;
700
+ if (canonicalResume) {
701
+ // Capture the fresh host-owned prefix exactly once. Canonical refreshes
702
+ // later in the WS handler must never rescan a message array that already
703
+ // contains a durable compact-summary system turn, or the summary would be
704
+ // mistaken for host context and duplicated after each claim/settlement.
705
+ let hostSystemPrefix;
706
+ try {
707
+ hostSystemPrefix = captureCanonicalHostSystemPrefix(session);
708
+ } catch {
709
+ server._send(
710
+ ws,
711
+ envelopeError(
712
+ id,
713
+ "CC_SESSION_HOST_PREFIX_INVALID",
714
+ "Canonical WS host system prefix is invalid; resume was refused",
715
+ sessionId,
716
+ { sessionSnapshot },
717
+ ),
718
+ );
719
+ return;
720
+ }
721
+ session.messages = [...hostSystemPrefix, ...canonicalResume.messages];
722
+ session.canonicalJsonlSession = true;
723
+ session.sessionHostSnapshot = sessionSnapshot;
724
+ } else {
725
+ session.canonicalJsonlSession = false;
726
+ session.sessionHostSnapshot = null;
727
+ }
728
+
729
+ // P0-2: reconcile the crash-safe side-effect ledger. If a dangerous tool was
730
+ // in flight when the prior worker died, warn the IDE client AND inject a
731
+ // system note so the resumed model does not silently replay it.
732
+ const recoveryDependencies = {
733
+ ...(server.resumeRecoveryDependencies || {}),
734
+ };
735
+ if (canonicalResume?.recovery) {
736
+ recoveryDependencies.loadMcpLedgerRecovery = () => canonicalResume.recovery;
737
+ }
738
+ let recovery = buildResumeRecovery(session.id, recoveryDependencies);
739
+ session.mcpLedgerRecovery = recovery?.mcp || {
740
+ count: 0,
741
+ unsettled: [],
742
+ incidents: [],
743
+ replayDenied: [],
744
+ notice: null,
745
+ };
746
+ session.mcpLedgerRecoveryRevision =
747
+ Number(session.mcpLedgerRecoveryRevision || 0) + 1;
748
+ replaceResumeRecoveryNotice(session, recovery?.notice || null);
749
+
750
+ // Recovery authority must be attached before a handler is created/refreshed
751
+ // or history is exposed. Otherwise an existing clean controller can admit a
752
+ // turn in the resume window before the unsafe projection reaches it.
275
753
  if (!server.sessionHandlers.has(sessionId)) {
276
754
  try {
277
755
  await ensureSessionHandler(server, ws, session);
278
756
  } catch (_err) {
279
- // Session resumed without live handler.
757
+ // Session resumed without live handler. A future handler still reads the
758
+ // already-attached fail-closed recovery authority from the session.
759
+ }
760
+ }
761
+ const handler = server.sessionHandlers.get(sessionId);
762
+ if (typeof handler?.refreshMcpRecoveryRuntime === "function") {
763
+ try {
764
+ await handler.refreshMcpRecoveryRuntime();
765
+ } catch (error) {
766
+ const failedMcp = failClosedMcpRecovery(
767
+ error,
768
+ "CC_MCP_RECOVERY_REFRESH_FAILED",
769
+ );
770
+ session.mcpLedgerRecovery = failedMcp;
771
+ session.mcpLedgerRecoveryRevision =
772
+ Number(session.mcpLedgerRecoveryRevision || 0) + 1;
773
+ recovery = Object.freeze({
774
+ ...recovery,
775
+ count:
776
+ Math.max(
777
+ 0,
778
+ Number(recovery?.count || 0) - Number(recovery?.mcp?.count || 0),
779
+ ) + failedMcp.count,
780
+ mcp: failedMcp,
781
+ notice: [recovery?.notice, failedMcp.notice]
782
+ .filter(Boolean)
783
+ .join("\n\n"),
784
+ });
785
+ replaceResumeRecoveryNotice(session, recovery.notice);
280
786
  }
281
787
  }
282
788
 
283
- const history = (session.messages || []).filter((m) => m.role !== "system");
789
+ const history = (
790
+ Array.isArray(session.messages) ? session.messages : []
791
+ ).filter((m) => m?.role !== "system");
284
792
  const record = createSessionRecord(session, {
285
793
  history,
286
794
  messageCount: history.length,
287
795
  status: "resumed",
288
796
  });
289
-
290
- // P0-2: reconcile the crash-safe side-effect ledger. If a dangerous tool was
291
- // in flight when the prior worker died, warn the IDE client AND inject a
292
- // system note so the resumed model does not silently replay it.
293
- const recovery = buildResumeRecovery(session.id);
294
- if (recovery && Array.isArray(session.messages)) {
295
- session.messages.push({ role: "system", content: recovery.notice });
296
- }
797
+ // Runtime-bus subscribers receive control-plane continuity metadata, not
798
+ // transcript content. The direct resume response below still carries the
799
+ // requested history to the authenticated IDE client.
800
+ const runtimeRecord = { ...record, history: [] };
801
+ const stateSnapshot =
802
+ typeof server.sessionManager.getSessionStateSnapshot === "function"
803
+ ? server.sessionManager.getSessionStateSnapshot(session.id)
804
+ : null;
297
805
 
298
806
  server.emit(
299
807
  RUNTIME_EVENTS.SESSION_RESUME,
@@ -303,8 +811,10 @@ export async function handleSessionResume(server, id, ws, message) {
303
811
  sessionId: session.id,
304
812
  historyCount: history.length,
305
813
  sessionType: session.type || null,
306
- record,
814
+ record: runtimeRecord,
815
+ ...(stateSnapshot ? { stateSnapshot } : {}),
307
816
  ...(recovery ? { recovery } : {}),
817
+ ...(sessionSnapshot ? { sessionSnapshot } : {}),
308
818
  },
309
819
  { kind: "server", sessionId: session.id },
310
820
  ),
@@ -319,7 +829,9 @@ export async function handleSessionResume(server, id, ws, message) {
319
829
  sessionId: session.id,
320
830
  history,
321
831
  record,
832
+ ...(stateSnapshot ? { stateSnapshot } : {}),
322
833
  ...(recovery ? { recovery } : {}),
834
+ ...(sessionSnapshot ? { sessionSnapshot } : {}),
323
835
  },
324
836
  session.id,
325
837
  ),
@@ -546,15 +1058,31 @@ export async function handleSessionInterrupt(server, id, ws, message) {
546
1058
  }
547
1059
 
548
1060
  const handler = server.sessionHandlers.get(sessionId);
549
- const result =
550
- handler && typeof handler.interrupt === "function"
551
- ? await handler.interrupt()
552
- : {
553
- sessionId,
554
- interrupted: true,
555
- wasProcessing: false,
556
- interruptedRequestId: null,
557
- };
1061
+ const handlerCanInterrupt =
1062
+ handler && typeof handler.interrupt === "function";
1063
+ const result = handlerCanInterrupt
1064
+ ? await handler.interrupt()
1065
+ : {
1066
+ sessionId,
1067
+ interrupted: true,
1068
+ wasProcessing: false,
1069
+ interruptedRequestId: null,
1070
+ };
1071
+
1072
+ if (
1073
+ !handlerCanInterrupt &&
1074
+ typeof server.sessionManager.recordSessionStateEvent === "function"
1075
+ ) {
1076
+ server.sessionManager.recordSessionStateEvent(
1077
+ sessionId,
1078
+ "run.interrupted",
1079
+ {
1080
+ requestId: result.interruptedRequestId,
1081
+ interruptedAt: new Date().toISOString(),
1082
+ reason: "client_interrupt",
1083
+ },
1084
+ );
1085
+ }
558
1086
 
559
1087
  server._send(
560
1088
  ws,