chainlesschain 0.162.188 → 0.162.193

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/README.md +61 -11
  2. package/bin/chainlesschain.js +7 -52
  3. package/completions/_cc +209 -0
  4. package/completions/cc.bash +18 -0
  5. package/completions/cc.fish +13 -0
  6. package/completions/cc.ps1 +226 -0
  7. package/package.json +10 -2
  8. package/src/assets/web-panel/assets/{AIOps-Brr1LVcE.js → AIOps-DBLkaTje.js} +1 -1
  9. package/src/assets/web-panel/assets/{ActionButton-DQU74DKG.js → ActionButton-BAy-Qebo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Analytics-CYp9178y.js → Analytics-Dfb1Mlau.js} +3 -3
  11. package/src/assets/web-panel/assets/{AppLayout-DW4SCYsW.js → AppLayout-BbFkN8m0.js} +5 -5
  12. package/src/assets/web-panel/assets/{Artifacts-CYlD_ed1.js → Artifacts-kM4-cEEH.js} +1 -1
  13. package/src/assets/web-panel/assets/{Audit-CWl1rZOi.js → Audit-BSQfYWf3.js} +1 -1
  14. package/src/assets/web-panel/assets/{BackgroundAgents-BOR-LPsa.js → BackgroundAgents-CWDbI_fG.js} +1 -1
  15. package/src/assets/web-panel/assets/{Backup-DLpG7j1X.js → Backup-BxLPbq_Q.js} +1 -1
  16. package/src/assets/web-panel/assets/{BaseInput-B35K9wdr.js → BaseInput-DuIbdrp6.js} +1 -1
  17. package/src/assets/web-panel/assets/{Chat-CwUJb9gB.js → Chat-NEmjGahU.js} +5 -5
  18. package/src/assets/web-panel/assets/{ChatBubbleRenderer-1v6aMS1m.js → ChatBubbleRenderer-DfJEo-5_.js} +1 -1
  19. package/src/assets/web-panel/assets/{Checkbox-pi3-tPNW.js → Checkbox-CaoeG3Ns.js} +1 -1
  20. package/src/assets/web-panel/assets/{Codegen-FyNF35eL.js → Codegen-BFf_g3xY.js} +1 -1
  21. package/src/assets/web-panel/assets/{Col-tGt_JDEr.js → Col-CNOd8mdQ.js} +1 -1
  22. package/src/assets/web-panel/assets/{Community-CC7LonQX.js → Community-BhpDqz-i.js} +1 -1
  23. package/src/assets/web-panel/assets/{Compact-BGXrHHjE.js → Compact-CQ42T7Z6.js} +1 -1
  24. package/src/assets/web-panel/assets/{Compliance-DSW0TBZ8.js → Compliance-DI5PcLMN.js} +1 -1
  25. package/src/assets/web-panel/assets/{Cowork-Bhk7rbvE.js → Cowork-wYYZe0wR.js} +3 -3
  26. package/src/assets/web-panel/assets/{Cron-DxyiQ2NZ.js → Cron-Dlq03DD_.js} +2 -2
  27. package/src/assets/web-panel/assets/{Crosschain-B2ZkxHok.js → Crosschain-BzqS8PP3.js} +1 -1
  28. package/src/assets/web-panel/assets/{DID-yOJV99eJ.js → DID-It55Yem7.js} +2 -2
  29. package/src/assets/web-panel/assets/{Dashboard-CKsttz7D.js → Dashboard-9HkH6oxn.js} +2 -2
  30. package/src/assets/web-panel/assets/{Dropdown-CVFldXSL.js → Dropdown-00e2YWRB.js} +1 -1
  31. package/src/assets/web-panel/assets/{EmailListRenderer-Bufv638J.js → EmailListRenderer-By-ugRDL.js} +1 -1
  32. package/src/assets/web-panel/assets/{FamilyGuardDashboard-4ncjoIjL.js → FamilyGuardDashboard-C396yu5m.js} +1 -1
  33. package/src/assets/web-panel/assets/{Federation-DsknEDoX.js → Federation-BME5sbZY.js} +1 -1
  34. package/src/assets/web-panel/assets/{FormItemContext-Cqe5jWXA.js → FormItemContext-B4TEZCr-.js} +1 -1
  35. package/src/assets/web-panel/assets/{GenericCardRenderer-NAJaFKxc.js → GenericCardRenderer-_9CX9ieY.js} +1 -1
  36. package/src/assets/web-panel/assets/{Git-CszKQpnl.js → Git-BrS6WVSr.js} +2 -2
  37. package/src/assets/web-panel/assets/{Governance-BXGodXi6.js → Governance-BMdCWnKF.js} +1 -1
  38. package/src/assets/web-panel/assets/{Inference-CkoYuG2c.js → Inference-Bcp3vzcA.js} +1 -1
  39. package/src/assets/web-panel/assets/{KnowledgeGraph-DFlEr_T0.js → KnowledgeGraph-DlLuqGY5.js} +1 -1
  40. package/src/assets/web-panel/assets/{Logs-CVaENddA.js → Logs-D-W_6x09.js} +2 -2
  41. package/src/assets/web-panel/assets/MarkdownRenderer-DElGPxCZ.js +1 -0
  42. package/src/assets/web-panel/assets/{Marketplace-CDlLT0fw.js → Marketplace-Dzn2guvI.js} +1 -1
  43. package/src/assets/web-panel/assets/{McpTools-DdwOyszN.js → McpTools-uPict-KL.js} +6 -6
  44. package/src/assets/web-panel/assets/{Memory-DKQnkKuG.js → Memory-BCw43kOb.js} +2 -2
  45. package/src/assets/web-panel/assets/{MobileBridge-DGseqlzJ.js → MobileBridge-DmV8Wv7F.js} +1 -1
  46. package/src/assets/web-panel/assets/{MobileProjects-COBbEOlj.js → MobileProjects-C-HaCmSM.js} +1 -1
  47. package/src/assets/web-panel/assets/{Mtc-O61Vwyli.js → Mtc-C6jxJ34Y.js} +5 -5
  48. package/src/assets/web-panel/assets/{MtcAudit-Dw2SyasS.js → MtcAudit-Za8ExwhQ.js} +5 -5
  49. package/src/assets/web-panel/assets/{Multisig-hSu_l8kf.js → Multisig-KKDbuEgb.js} +3 -3
  50. package/src/assets/web-panel/assets/{NLProgramming-CX1Epurr.js → NLProgramming-Dj97zbCk.js} +1 -1
  51. package/src/assets/web-panel/assets/{Notes-R9xX8o8_.js → Notes-DBXvMraU.js} +4 -4
  52. package/src/assets/web-panel/assets/{NotificationSettings-jtSNLCuK.js → NotificationSettings-DOxITLYl.js} +1 -1
  53. package/src/assets/web-panel/assets/OrderTableRenderer-7DVjZwMM.js +1 -0
  54. package/src/assets/web-panel/assets/{Organization-Pu2WO-U3.js → Organization-D1i73mjb.js} +4 -4
  55. package/src/assets/web-panel/assets/{Overflow-BjnqUyFp.js → Overflow-kW6Q3rvg.js} +1 -1
  56. package/src/assets/web-panel/assets/{P2P-jjkvz44c.js → P2P-C-v_8p2v.js} +2 -2
  57. package/src/assets/web-panel/assets/PdhVaultBrowser-tUbbY64W.js +7 -0
  58. package/src/assets/web-panel/assets/{Permissions-D4yDpivd.js → Permissions-DkHxEZ58.js} +4 -4
  59. package/src/assets/web-panel/assets/{PersonalDataHub-0qsL6iH1.js → PersonalDataHub-DWuMPGrK.js} +5 -5
  60. package/src/assets/web-panel/assets/{Pipeline-Cx7Ybrk2.js → Pipeline-30IYXWWm.js} +1 -1
  61. package/src/assets/web-panel/assets/{Privacy-PbfR_M_V.js → Privacy-DZNQ4RrH.js} +1 -1
  62. package/src/assets/web-panel/assets/{ProjectInit-CyV6Gsub.js → ProjectInit-De2MCElf.js} +2 -2
  63. package/src/assets/web-panel/assets/{ProjectSettings-C7KZ2Wdk.js → ProjectSettings-5uHk9wsC.js} +2 -2
  64. package/src/assets/web-panel/assets/{Projects-DQDjO-yK.js → Projects-XjDfrFLb.js} +1 -1
  65. package/src/assets/web-panel/assets/{Providers-DyFVBBMX.js → Providers-Bgwj6gcE.js} +1 -1
  66. package/src/assets/web-panel/assets/{QrScannerModal-CzB1BC9_.js → QrScannerModal-gKql9umv.js} +1 -1
  67. package/src/assets/web-panel/assets/{QuickAsk-Bk636mC1.js → QuickAsk-BWvmwkh7.js} +1 -1
  68. package/src/assets/web-panel/assets/{Recommend-DoWxHIT3.js → Recommend-Uok4hZPd.js} +1 -1
  69. package/src/assets/web-panel/assets/{RemoteSession-oOVIv9wq.js → RemoteSession-DLJzTk9a.js} +3 -3
  70. package/src/assets/web-panel/assets/{Reputation-BucoReGG.js → Reputation-ZVwIPMSO.js} +1 -1
  71. package/src/assets/web-panel/assets/{Row-DzmOdJU7.js → Row-CN04HxWR.js} +1 -1
  72. package/src/assets/web-panel/assets/{RssFeed-C1tK7KGU.js → RssFeed-BdSrEG4g.js} +3 -3
  73. package/src/assets/web-panel/assets/{Search-CSnInOqk.js → Search-5PwVd0IR.js} +1 -1
  74. package/src/assets/web-panel/assets/{Security-dlejr15l.js → Security-DdBo4zjN.js} +3 -3
  75. package/src/assets/web-panel/assets/{Services-BioPZuNh.js → Services-D3letU7M.js} +2 -2
  76. package/src/assets/web-panel/assets/{Skeleton-DWMibwpC.js → Skeleton--Jb83f1v.js} +1 -1
  77. package/src/assets/web-panel/assets/{Skills-BAAnx1B2.js → Skills-Bg-CulHX.js} +1 -1
  78. package/src/assets/web-panel/assets/{Sla-jWNp4hNO.js → Sla-7QOa7S-X.js} +1 -1
  79. package/src/assets/web-panel/assets/{SpeechSettings-y5kqKha-.js → SpeechSettings-DQwppjRw.js} +1 -1
  80. package/src/assets/web-panel/assets/{SyncSettings-B9GNsc3e.js → SyncSettings-dNPQGL-s.js} +2 -2
  81. package/src/assets/web-panel/assets/{Tasks-BDBYKRen.js → Tasks-Ggs-Z48q.js} +1 -1
  82. package/src/assets/web-panel/assets/{Templates-DRiE5eaN.js → Templates-78TYHgRO.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tenant-BGlAvExF.js → Tenant-xHwwv9vO.js} +1 -1
  84. package/src/assets/web-panel/assets/{Terminal-B8uzrbNY.js → Terminal-BJXSJfm4.js} +2 -2
  85. package/src/assets/web-panel/assets/{TimelineRenderer-Df48iveY.js → TimelineRenderer-fLbjRhJw.js} +1 -1
  86. package/src/assets/web-panel/assets/{Tokens-CcmHndN6.js → Tokens-oMSBSBmB.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trigger-DPkWxmQ2.js → Trigger-CfnY_wX_.js} +1 -1
  88. package/src/assets/web-panel/assets/{Trust-DTb5a5AV.js → Trust-AdyTgYKO.js} +1 -1
  89. package/src/assets/web-panel/assets/{UkeySign-CBmg5vch.js → UkeySign-C5K_81dS.js} +1 -1
  90. package/src/assets/web-panel/assets/{VideoEditing-B0mZrz4O.js → VideoEditing-vcGVDqki.js} +1 -1
  91. package/src/assets/web-panel/assets/{Wallet-Bxs7_mpd.js → Wallet-hhOc3hlY.js} +4 -4
  92. package/src/assets/web-panel/assets/{WebAuthn-C8x3cMxU.js → WebAuthn-CVloC11s.js} +3 -3
  93. package/src/assets/web-panel/assets/{WorkflowEditor-DPrNznrP.js → WorkflowEditor-CYeE32R5.js} +1 -1
  94. package/src/assets/web-panel/assets/{chat-D3bYWu7S.js → chat-CNROR5bN.js} +1 -1
  95. package/src/assets/web-panel/assets/{colors-DY-PwMu4.js → colors-Cjx-cnwU.js} +1 -1
  96. package/src/assets/web-panel/assets/{compact-item-LDk10Kw6.js → compact-item-DOIfelvD.js} +1 -1
  97. package/src/assets/web-panel/assets/{createContext-C-2MZnFq.js → createContext-DfA7UZ8u.js} +1 -1
  98. package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +1 -0
  99. package/src/assets/web-panel/assets/{hasIn-BQIBjcnB.js → hasIn-BMSCzcfM.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CQVb2dWp.js → index-5-HXgOX5.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BdXnYMCZ.js → index-AWg-0M1S.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cx6D_dx2.js → index-B4iYzpkL.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-_HRO_cIu.js → index-B5Udeb_6.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DlRYqt3S.js → index-B7gf77CJ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BrnRO9yE.js → index-BEMwBBHk.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-VCh5zNJo.js → index-BM1y_9hM.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BRI3ngNg.js → index-BUonmKSE.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C3GNvExG.js → index-BbQ2eQ8H.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DSvo_bp0.js → index-BemJ2u_E.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-L6qixyLc.js → index-BolaOQxx.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BI4KgcYC.js → index-BxOk9vkG.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CY4KnaO9.js → index-By61ojUx.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-L3smcoQX.js → index-C2K9SNVX.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BX2b9Orc.js → index-C3L5gdiD.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Cz4b6Z_7.js → index-C7xn0Nub.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-COG61sRv.js → index-CAnvhwg6.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C7FC8cP2.js → index-CEKMcOyU.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BN-xdSWZ.js → index-CNC5onm4.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DY2FIrmz.js → index-CVL27kXC.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CiTvBAr-.js → index-CVm1_i3t.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DhRt9cYJ.js → index-CdYBye8B.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-B5pgtZnY.js → index-ClNMrqEY.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-7xKu7Fns.js → index-Cs6l7uRu.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D4K1weKc.js → index-CshQbilz.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-k7C_oDCO.js → index-Cyweh0Hy.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D3Oq-DLL.js → index-DBpWXFed.js} +3 -3
  127. package/src/assets/web-panel/assets/{index-DYyLJPlF.js → index-DHtpHZAQ.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Dh-tkpKQ.js → index-DLmn0BoK.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-8JC9BJa1.js → index-DPAWBrMf.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Dd2Km97U.js → index-DjEsxO5h.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-KFZO_lcx.js → index-FBc_CJBd.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DTIZpPtG.js → index-Icdoqmzt.js} +1 -1
  133. package/src/assets/web-panel/assets/index-Q2IajL54.js +1 -0
  134. package/src/assets/web-panel/assets/index-bRkHgOMc.js +1 -0
  135. package/src/assets/web-panel/assets/{index-lmm9p-jm.js → index-dCd8cSUq.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-HasPt4-h.js → index-m2vG9gG_.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-CaslYch6.js → index-mTpHoEzr.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-CbR6ROOa.js → index-ti_lnTWl.js} +1 -1
  139. package/src/assets/web-panel/assets/{initDefaultProps-zQPSHf2C.js → initDefaultProps-Bu8k7H1Y.js} +1 -1
  140. package/src/assets/web-panel/assets/{motion-CKCStGVk.js → motion-s3iVK41k.js} +1 -1
  141. package/src/assets/web-panel/assets/{move-BufVDGYF.js → move-B6B-E5Jz.js} +1 -1
  142. package/src/assets/web-panel/assets/{mtc-parser-DcaFxy5D.js → mtc-parser-BiYgTidA.js} +1 -1
  143. package/src/assets/web-panel/assets/{omit-EScpkGdo.js → omit-pU1RdUDA.js} +1 -1
  144. package/src/assets/web-panel/assets/{pickAttrs-72hG_qfT.js → pickAttrs-Cdoq_SeM.js} +1 -1
  145. package/src/assets/web-panel/assets/{placementArrow-CMFWiH20.js → placementArrow-DIuvAn2K.js} +1 -1
  146. package/src/assets/web-panel/assets/{responsiveObserve-DKQHS41p.js → responsiveObserve-8w16YR2D.js} +1 -1
  147. package/src/assets/web-panel/assets/{slide-QVAFHTIQ.js → slide-VZ01cZe3.js} +1 -1
  148. package/src/assets/web-panel/assets/{statusUtils-DIz38e2G.js → statusUtils-lh8YMN8Z.js} +1 -1
  149. package/src/assets/web-panel/assets/{styleChecker-zK5cyLby.js → styleChecker-CmDyreec.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFlexGapSupport-DhZngk62.js → useFlexGapSupport-hiJWMU5y.js} +1 -1
  151. package/src/assets/web-panel/assets/{useFs-BvV2cvkg.js → useFs-Thnu-Iaj.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-CRmxb9l3.js → usePersonalDataHub-LBdOxjwY.js} +1 -1
  153. package/src/assets/web-panel/assets/{vnode-CgQIbobP.js → vnode-Cg6lFY_X.js} +1 -1
  154. package/src/assets/web-panel/assets/{zoom-D4XrrO0R.js → zoom-DVfsR1YO.js} +1 -1
  155. package/src/assets/web-panel/index.html +1 -1
  156. package/src/cli-help.js +181 -0
  157. package/src/command-help-index.json +181 -0
  158. package/src/command-manifest.json +1107 -175
  159. package/src/command-surface-policy.js +197 -0
  160. package/src/commands/agent.js +98 -33
  161. package/src/commands/artifacts.js +400 -2
  162. package/src/commands/background-session.js +41 -3
  163. package/src/commands/checkpoint-managed.js +1059 -0
  164. package/src/commands/checkpoint-restore-recovery.js +1476 -0
  165. package/src/commands/checkpoint.js +950 -22
  166. package/src/commands/compact.js +101 -25
  167. package/src/commands/config.js +506 -20
  168. package/src/commands/doctor.js +4 -1
  169. package/src/commands/hub.js +1 -1
  170. package/src/commands/mcp.js +688 -24
  171. package/src/commands/pack.js +16 -2
  172. package/src/commands/plugin.js +20 -12
  173. package/src/commands/session-mcp-recovery.js +218 -0
  174. package/src/commands/session.js +470 -110
  175. package/src/commands/setup.js +36 -10
  176. package/src/commands/skill.js +181 -110
  177. package/src/commands/status.js +21 -5
  178. package/src/commands/team-distributed.js +3324 -0
  179. package/src/commands/team.js +1130 -74
  180. package/src/commands/update.js +68 -6
  181. package/src/constants.js +11 -0
  182. package/src/data/changelog.json +26 -0
  183. package/src/gateways/ws/action-protocol.js +10 -0
  184. package/src/gateways/ws/session-protocol.js +555 -27
  185. package/src/gateways/ws/ws-agent-handler.js +541 -14
  186. package/src/gateways/ws/ws-session-gateway.js +129 -22
  187. package/src/gateways/ws/ws-session-state.js +431 -0
  188. package/src/harness/background-task-manager.js +233 -36
  189. package/src/harness/jsonl-session-store.js +2551 -167
  190. package/src/harness/mcp-client.js +802 -61
  191. package/src/harness/prompt-compressor.js +227 -27
  192. package/src/harness/session-index.js +89 -38
  193. package/src/harness/session-list-index.js +254 -0
  194. package/src/harness/structured-handoff.js +410 -0
  195. package/src/lazy-dispatch.js +747 -84
  196. package/src/lib/__tests__/logger.test.js +50 -2
  197. package/src/lib/advisor-runtime.js +1047 -0
  198. package/src/lib/agent-core.js +2 -0
  199. package/src/lib/agent-sandbox.js +120 -26
  200. package/src/lib/agent-session-export.js +20 -0
  201. package/src/lib/agent-team/task-lease.js +271 -3
  202. package/src/lib/agent-team/team-adjudication.js +1501 -0
  203. package/src/lib/agent-team/team-budget.js +4 -1
  204. package/src/lib/agent-team/team-control-store.js +582 -0
  205. package/src/lib/agent-team/team-distributed-queue.js +5246 -0
  206. package/src/lib/agent-team/team-process-checkpoint.js +211 -0
  207. package/src/lib/agent-team/team-runner.js +543 -24
  208. package/src/lib/agent-team/team-worktree.js +1403 -95
  209. package/src/lib/artifact-store.js +131 -8
  210. package/src/lib/background-agent-supervisor.js +185 -13
  211. package/src/lib/background-interaction-journal.js +37 -9
  212. package/src/lib/background-launch-profile.js +1058 -0
  213. package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
  214. package/src/lib/checkpoint-restore-orchestrator.js +987 -0
  215. package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
  216. package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
  217. package/src/lib/checkpoint-restore-recovery.js +884 -0
  218. package/src/lib/checkpoint-restore-retention.js +126 -0
  219. package/src/lib/checkpoint-restore-saga.js +5079 -0
  220. package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
  221. package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
  222. package/src/lib/checkpoint-store.js +1688 -97
  223. package/src/lib/checkpoint-timeline-authority.js +522 -0
  224. package/src/lib/checkpoint-timeline.js +642 -0
  225. package/src/lib/config-keys.js +18 -119
  226. package/src/lib/config-manager.js +446 -27
  227. package/src/lib/config-redaction.js +57 -0
  228. package/src/lib/config-schema.js +853 -0
  229. package/src/lib/cowork-mcp-tools.js +5 -0
  230. package/src/lib/cowork-task-runner.js +458 -63
  231. package/src/lib/delivery-coordinator.js +1234 -0
  232. package/src/lib/delivery-evidence.js +450 -0
  233. package/src/lib/doctor-checkup.js +199 -14
  234. package/src/lib/executable-path.js +34 -0
  235. package/src/lib/fatal-handler.js +16 -0
  236. package/src/lib/file-checkpoint.js +4909 -186
  237. package/src/lib/file-lines.js +125 -0
  238. package/src/lib/headless-config-command.js +16 -5
  239. package/src/lib/hook-runner.cjs +139 -38
  240. package/src/lib/hooks-v2-workspace-context.js +10 -0
  241. package/src/lib/impacted-gate-selector.js +424 -0
  242. package/src/lib/interaction-adapter.js +62 -0
  243. package/src/lib/jsonl-session-store.js +1 -35
  244. package/src/lib/logger.js +66 -14
  245. package/src/lib/managed-checkpoint-render.js +60 -0
  246. package/src/lib/managed-tool-checkpoint.js +194 -0
  247. package/src/lib/mcp-call-ledger-store.js +1069 -0
  248. package/src/lib/mcp-call-ledger.js +747 -0
  249. package/src/lib/mcp-client.js +5 -0
  250. package/src/lib/mcp-conflict-scheduler.js +468 -0
  251. package/src/lib/mcp-effect-contract.js +102 -0
  252. package/src/lib/mcp-headers-helper-trust.js +145 -0
  253. package/src/lib/mcp-headers-helper.js +616 -0
  254. package/src/lib/mcp-host-recovery-runtime.js +131 -0
  255. package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
  256. package/src/lib/mcp-recovery-adjudication.js +443 -0
  257. package/src/lib/output-context.js +86 -0
  258. package/src/lib/packer/file-identity.js +170 -0
  259. package/src/lib/packer/index.js +3 -0
  260. package/src/lib/packer/native-update-state.js +277 -0
  261. package/src/lib/packer/pack-update-applier.js +1983 -136
  262. package/src/lib/packer/pack-update-checker.js +34 -0
  263. package/src/lib/packer/pack-update-downloader.js +875 -86
  264. package/src/lib/packer/pack-update-signature.js +86 -0
  265. package/src/lib/packer/pkg-config-generator.js +6 -0
  266. package/src/lib/paths.js +65 -10
  267. package/src/lib/plan-mode.js +831 -14
  268. package/src/lib/plan-persistence.js +540 -0
  269. package/src/lib/plugin-runtime/hooks.js +227 -69
  270. package/src/lib/plugin-runtime/plugin-options.js +189 -44
  271. package/src/lib/pr-automation-policy.js +146 -8
  272. package/src/lib/process-execution-broker/credential-agent.js +7 -0
  273. package/src/lib/process-execution-broker/index.js +491 -13
  274. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +28 -1
  275. package/src/lib/process-execution-broker/linux-generic-bwrap.js +28 -4
  276. package/src/lib/process-execution-broker/platform-sandbox.js +92 -70
  277. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  278. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  279. package/src/lib/process-execution-broker/windows-sandbox.cs +284 -19
  280. package/src/lib/process-execution-broker/workspace-transaction.js +4459 -0
  281. package/src/lib/project-instructions.js +165 -29
  282. package/src/lib/project-mcp-trust.js +67 -0
  283. package/src/lib/public-ide-capability-manifest.js +272 -0
  284. package/src/lib/public-ide-capability-validation.js +351 -0
  285. package/src/lib/secret-store.js +267 -43
  286. package/src/lib/secure-file-identity.js +433 -0
  287. package/src/lib/secure-fs.js +1089 -0
  288. package/src/lib/security-audit.js +58 -0
  289. package/src/lib/service-manager.js +34 -13
  290. package/src/lib/session-budget-runtime.js +1452 -0
  291. package/src/lib/session-host-snapshot.js +388 -0
  292. package/src/lib/session-message-provenance.js +429 -0
  293. package/src/lib/session-projection.js +804 -0
  294. package/src/lib/session-resource-budget.js +1495 -0
  295. package/src/lib/settings-hooks.cjs +138 -22
  296. package/src/lib/settings-loader.cjs +25 -2
  297. package/src/lib/side-effect-ledger-store.js +45 -23
  298. package/src/lib/skill-execution-identity.js +217 -0
  299. package/src/lib/skill-loader.js +299 -18
  300. package/src/lib/sub-agent-context.js +236 -28
  301. package/src/lib/sub-agent-registry.js +5 -0
  302. package/src/lib/subagent-contract.js +94 -0
  303. package/src/lib/todo-manager.js +185 -18
  304. package/src/lib/todo-persistence.js +417 -0
  305. package/src/lib/turn-binding-store.js +41 -23
  306. package/src/lib/turn-binding.js +160 -2
  307. package/src/lib/with-file-lock.js +165 -24
  308. package/src/lib/ws-chat-handler.js +21 -0
  309. package/src/program-base.js +18 -0
  310. package/src/repl/advisor-command.js +103 -0
  311. package/src/repl/agent-repl.js +2175 -146
  312. package/src/repl/btw-command.js +93 -10
  313. package/src/repl/clipboard-image.js +119 -0
  314. package/src/repl/config-summary.js +64 -108
  315. package/src/repl/prompt-editor.js +233 -0
  316. package/src/repl/prompt-interactions.js +344 -0
  317. package/src/repl/prompt-stash.js +354 -0
  318. package/src/repl/prompt-suggestions.js +312 -0
  319. package/src/repl/repl-keybindings.js +227 -0
  320. package/src/repl/session-recap.js +217 -0
  321. package/src/repl/slash-command-registry.js +22 -0
  322. package/src/repl/terminal-layout.js +88 -0
  323. package/src/runtime/agent-core.js +1630 -447
  324. package/src/runtime/coding-agent-contract-shared.cjs +13 -1
  325. package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
  326. package/src/runtime/diagnostics.js +32 -13
  327. package/src/runtime/headless-runner.js +310 -118
  328. package/src/runtime/headless-stream.js +356 -95
  329. package/src/runtime/mcp-config.js +148 -14
  330. package/src/runtime/policies/agent-policy.js +14 -0
  331. package/src/runtime/status-diagnostics-lite.js +137 -0
  332. package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +0 -1
  333. package/src/assets/web-panel/assets/OrderTableRenderer-BU2Yqq5H.js +0 -1
  334. package/src/assets/web-panel/assets/PdhVaultBrowser-69ca_WeR.js +0 -7
  335. package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +0 -1
  336. package/src/assets/web-panel/assets/index-C-C7DaG6.js +0 -1
  337. package/src/assets/web-panel/assets/index-DkfWzWtd.js +0 -1
@@ -0,0 +1,1069 @@
1
+ /**
2
+ * Durable adapter for MCP call-ledger records.
3
+ *
4
+ * Each started/settled record is appended to the canonical tamper-evident
5
+ * session transcript. The payload already contains digests rather than raw
6
+ * tool input/output. Recovery folds the newest record per ledger id and treats
7
+ * every surviving `started` call as outcome-unknown; callers must inspect it
8
+ * instead of automatically replaying the MCP operation.
9
+ */
10
+ import { isProxy } from "node:util/types";
11
+ import {
12
+ appendAuthorityEvent as storeAppendAuthorityEvent,
13
+ readVerifiedEvents as storeReadVerifiedEvents,
14
+ readVerifiedProjection as storeReadVerifiedProjection,
15
+ } from "../harness/jsonl-session-store.js";
16
+ import {
17
+ canonicalizeMcpNetworkScopes,
18
+ canonicalizeMcpResourceScopes,
19
+ LedgerFailureAction,
20
+ MCP_CALL_LEDGER_OUTPUT_KINDS,
21
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS,
22
+ MCP_CALL_LEDGER_SCHEMA_VERSION,
23
+ McpCallStatus,
24
+ McpEffect,
25
+ computeMcpExactReplayDigest,
26
+ normalizeMcpLedgerProtocolText,
27
+ normalizeMcpEffectContract,
28
+ sha256PayloadDigest,
29
+ snapshotMcpJsonRpcInput,
30
+ } from "./mcp-call-ledger.js";
31
+
32
+ export const MCP_CALL_LEDGER_EVENT = "mcp_call_ledger";
33
+ export const MCP_CALL_LEDGER_EVENT_SCHEMA_VERSION = 1;
34
+ export const MCP_CALL_RECOVERY_ADJUDICATION_EVENT =
35
+ "mcp_call_recovery_adjudication";
36
+ export const MCP_CALL_RECOVERY_ADJUDICATION_SCHEMA_VERSION = 1;
37
+ export const McpCallRecoveryDecision = Object.freeze({
38
+ CONFIRMED_APPLIED: "confirmed_applied",
39
+ CONFIRMED_NOT_APPLIED: "confirmed_not_applied",
40
+ });
41
+ export const MCP_CALL_RECOVERY_AUTHORITY = "local-cli-tty";
42
+ export const MCP_CALL_RECOVERY_CONFIRMATION = "typed-digest-host-stopped";
43
+
44
+ const TERMINAL = new Set([
45
+ McpCallStatus.COMPLETED,
46
+ McpCallStatus.FAILED,
47
+ McpCallStatus.CANCELLED,
48
+ ]);
49
+ const PAYLOAD_DIGEST = /^sha256:[0-9a-f]{64}$/;
50
+ const RAW_AUTHORITY_HASH = /^[0-9a-f]{64}$/;
51
+ const OUTPUT_KINDS = new Set(MCP_CALL_LEDGER_OUTPUT_KINDS);
52
+ const RECORD_FIELDS = new Set([
53
+ "schemaVersion",
54
+ "ledgerId",
55
+ "sessionId",
56
+ "turnId",
57
+ "toolName",
58
+ "serverName",
59
+ "inputDigest",
60
+ "inputBytes",
61
+ "effectContract",
62
+ "resourceScopes",
63
+ "networkScopes",
64
+ "prewritePolicy",
65
+ "prewritePersistence",
66
+ "status",
67
+ "startedAt",
68
+ "settledAt",
69
+ "outputSummary",
70
+ "outputDigest",
71
+ "errorSummary",
72
+ "settlementPersistence",
73
+ ]);
74
+ const EFFECT_CONTRACT_FIELDS = new Set([
75
+ "schemaVersion",
76
+ "effect",
77
+ "classification",
78
+ "readOnly",
79
+ "sideEffecting",
80
+ "destructive",
81
+ "idempotent",
82
+ "openWorld",
83
+ "trusted",
84
+ "source",
85
+ ]);
86
+ const OUTPUT_SUMMARY_FIELDS = new Set(["sha256", "bytes", "kind"]);
87
+ const ERROR_SUMMARY_FIELDS = new Set(["name", "code", "messageDigest"]);
88
+ const ADJUDICATION_FIELDS = new Set([
89
+ "schemaVersion",
90
+ "requestId",
91
+ "sessionId",
92
+ "ledgerId",
93
+ "decision",
94
+ "expectedHeadHash",
95
+ "expectedRecoveryDigest",
96
+ "authority",
97
+ "confirmation",
98
+ "reasonDigest",
99
+ ]);
100
+ const RECOVERY_PROJECTION_FIELDS = new Set([
101
+ "sessionId",
102
+ "records",
103
+ "unsettled",
104
+ "incidents",
105
+ "adjudications",
106
+ "replayDenied",
107
+ "verified",
108
+ "headHash",
109
+ "recoveryDigest",
110
+ "remediation",
111
+ ]);
112
+ const RECOVERY_REMEDIATIONS = new Set([
113
+ "inspect_transcript",
114
+ "adjudicate_started_calls",
115
+ "exact_replay_denied",
116
+ ]);
117
+ const RECOVERY_DIGEST_SCHEMA_VERSION = 1;
118
+
119
+ export const MCP_LEDGER_RECOVERY_PROJECTION_INVALID_CODE =
120
+ "CC_MCP_LEDGER_RECOVERY_PROJECTION_INVALID";
121
+
122
+ const VERIFIED_PROJECTION_AUTHORITY_FIELDS = new Set([
123
+ "headHash",
124
+ "eventCount",
125
+ "readMessages",
126
+ ]);
127
+
128
+ export class McpCallLedgerStoreError extends Error {
129
+ constructor(code, message, options = {}) {
130
+ super(message, options.cause ? { cause: options.cause } : undefined);
131
+ this.name = "McpCallLedgerStoreError";
132
+ this.code = code;
133
+ this.sessionId = normalizeMcpLedgerProtocolText(options.sessionId, null);
134
+ this.ledgerId = normalizeMcpLedgerProtocolText(
135
+ options.ledgerId,
136
+ null,
137
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.ledgerId,
138
+ );
139
+ }
140
+ }
141
+
142
+ function validTimestamp(value) {
143
+ return typeof value === "string" && Number.isFinite(Date.parse(value));
144
+ }
145
+
146
+ function isPlainObject(value) {
147
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
148
+ const prototype = Object.getPrototypeOf(value);
149
+ return prototype === Object.prototype || prototype === null;
150
+ }
151
+
152
+ function hasOnlyFields(value, allowedFields) {
153
+ return (
154
+ isPlainObject(value) &&
155
+ Object.keys(value).every((field) => allowedFields.has(field))
156
+ );
157
+ }
158
+
159
+ function hasExactFields(value, requiredFields) {
160
+ if (!hasOnlyFields(value, requiredFields)) return false;
161
+ const fields = Object.keys(value);
162
+ return (
163
+ fields.length === requiredFields.size &&
164
+ [...requiredFields].every((field) =>
165
+ Object.prototype.hasOwnProperty.call(value, field),
166
+ )
167
+ );
168
+ }
169
+
170
+ function canonicalScopes(value, canonicalize) {
171
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
172
+ return null;
173
+ }
174
+ return Object.freeze(canonicalize(value));
175
+ }
176
+
177
+ function isCanonicalProtocolText(value, maxLength, nullable = false) {
178
+ if (value === null) return nullable;
179
+ if (typeof value !== "string") return false;
180
+ return value === normalizeMcpLedgerProtocolText(value, null, maxLength);
181
+ }
182
+
183
+ function canonicalOutputSummary(value) {
184
+ if (value === null) return null;
185
+ if (
186
+ !hasOnlyFields(value, OUTPUT_SUMMARY_FIELDS) ||
187
+ !PAYLOAD_DIGEST.test(String(value.sha256 || "")) ||
188
+ !Number.isInteger(value.bytes) ||
189
+ value.bytes < 0 ||
190
+ !OUTPUT_KINDS.has(value.kind)
191
+ ) {
192
+ return false;
193
+ }
194
+ return Object.freeze({
195
+ sha256: value.sha256,
196
+ bytes: value.bytes,
197
+ kind: value.kind,
198
+ });
199
+ }
200
+
201
+ function canonicalErrorSummary(value) {
202
+ if (value === null) return null;
203
+ if (
204
+ !hasOnlyFields(value, ERROR_SUMMARY_FIELDS) ||
205
+ !isCanonicalProtocolText(
206
+ value.name,
207
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.errorName,
208
+ ) ||
209
+ (value.code !== null &&
210
+ !isCanonicalProtocolText(
211
+ value.code,
212
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.errorCode,
213
+ )) ||
214
+ !PAYLOAD_DIGEST.test(String(value.messageDigest || ""))
215
+ ) {
216
+ return false;
217
+ }
218
+ return Object.freeze({
219
+ name: value.name,
220
+ code: value.code,
221
+ messageDigest: value.messageDigest,
222
+ });
223
+ }
224
+
225
+ function canonicalRecord(record) {
226
+ if (!hasOnlyFields(record, RECORD_FIELDS)) return null;
227
+ if (!hasOnlyFields(record.effectContract, EFFECT_CONTRACT_FIELDS))
228
+ return null;
229
+ if (
230
+ record.effectContract.schemaVersion !== undefined &&
231
+ record.effectContract.schemaVersion !== MCP_CALL_LEDGER_SCHEMA_VERSION
232
+ ) {
233
+ return null;
234
+ }
235
+
236
+ const effectContract = normalizeMcpEffectContract(record.effectContract);
237
+ const resourceScopes = canonicalScopes(
238
+ record.resourceScopes,
239
+ canonicalizeMcpResourceScopes,
240
+ );
241
+ const networkScopes = canonicalScopes(
242
+ record.networkScopes,
243
+ canonicalizeMcpNetworkScopes,
244
+ );
245
+ const outputSummary = canonicalOutputSummary(record.outputSummary);
246
+ const errorSummary = canonicalErrorSummary(record.errorSummary);
247
+ const effectSourceValid =
248
+ record.effectContract.source == null ||
249
+ isCanonicalProtocolText(
250
+ record.effectContract.source,
251
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.identifier,
252
+ );
253
+ const baseValid =
254
+ record.schemaVersion === MCP_CALL_LEDGER_SCHEMA_VERSION &&
255
+ isCanonicalProtocolText(
256
+ record.ledgerId,
257
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.ledgerId,
258
+ ) &&
259
+ isCanonicalProtocolText(
260
+ record.sessionId,
261
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.identifier,
262
+ true,
263
+ ) &&
264
+ isCanonicalProtocolText(
265
+ record.turnId,
266
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.identifier,
267
+ true,
268
+ ) &&
269
+ isCanonicalProtocolText(
270
+ record.toolName,
271
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.identifier,
272
+ ) &&
273
+ isCanonicalProtocolText(
274
+ record.serverName,
275
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.identifier,
276
+ ) &&
277
+ effectSourceValid &&
278
+ PAYLOAD_DIGEST.test(String(record.inputDigest || "")) &&
279
+ Number.isInteger(record.inputBytes) &&
280
+ record.inputBytes >= 0 &&
281
+ Object.values(McpEffect).includes(effectContract.effect) &&
282
+ resourceScopes !== null &&
283
+ networkScopes !== null &&
284
+ outputSummary !== false &&
285
+ errorSummary !== false &&
286
+ (record.outputDigest === null ||
287
+ PAYLOAD_DIGEST.test(String(record.outputDigest || ""))) &&
288
+ (outputSummary === null
289
+ ? record.outputDigest === null
290
+ : record.outputDigest === outputSummary.sha256) &&
291
+ Object.values(LedgerFailureAction).includes(record.prewritePolicy) &&
292
+ (![McpEffect.WRITE, McpEffect.DESTRUCTIVE].includes(
293
+ effectContract.effect,
294
+ ) ||
295
+ record.prewritePolicy === LedgerFailureAction.FAIL_CLOSED) &&
296
+ ["pending", "persisted", "failed-open", "failed-closed"].includes(
297
+ record.prewritePersistence,
298
+ ) &&
299
+ validTimestamp(record.startedAt) &&
300
+ [McpCallStatus.STARTED, ...TERMINAL].includes(record.status);
301
+ if (!baseValid) return null;
302
+
303
+ if (record.status === McpCallStatus.STARTED) {
304
+ if (
305
+ record.prewritePersistence === "pending" &&
306
+ record.settledAt === null &&
307
+ outputSummary === null &&
308
+ record.outputDigest === null &&
309
+ errorSummary === null &&
310
+ record.settlementPersistence == null
311
+ ) {
312
+ return Object.freeze({
313
+ schemaVersion: record.schemaVersion,
314
+ ledgerId: record.ledgerId,
315
+ sessionId: record.sessionId,
316
+ turnId: record.turnId,
317
+ toolName: record.toolName,
318
+ serverName: record.serverName,
319
+ inputDigest: record.inputDigest,
320
+ inputBytes: record.inputBytes,
321
+ effectContract,
322
+ resourceScopes,
323
+ networkScopes,
324
+ prewritePolicy: record.prewritePolicy,
325
+ prewritePersistence: record.prewritePersistence,
326
+ status: record.status,
327
+ startedAt: record.startedAt,
328
+ settledAt: null,
329
+ outputSummary: null,
330
+ outputDigest: null,
331
+ errorSummary: null,
332
+ });
333
+ }
334
+ return null;
335
+ }
336
+ if (
337
+ record.prewritePersistence !== "persisted" ||
338
+ !validTimestamp(record.settledAt) ||
339
+ record.settlementPersistence !== "pending"
340
+ ) {
341
+ return null;
342
+ }
343
+ return Object.freeze({
344
+ schemaVersion: record.schemaVersion,
345
+ ledgerId: record.ledgerId,
346
+ sessionId: record.sessionId,
347
+ turnId: record.turnId,
348
+ toolName: record.toolName,
349
+ serverName: record.serverName,
350
+ inputDigest: record.inputDigest,
351
+ inputBytes: record.inputBytes,
352
+ effectContract,
353
+ resourceScopes,
354
+ networkScopes,
355
+ prewritePolicy: record.prewritePolicy,
356
+ prewritePersistence: record.prewritePersistence,
357
+ status: record.status,
358
+ startedAt: record.startedAt,
359
+ settledAt: record.settledAt,
360
+ outputSummary,
361
+ outputDigest: record.outputDigest,
362
+ errorSummary,
363
+ settlementPersistence: record.settlementPersistence,
364
+ });
365
+ }
366
+
367
+ function phaseMatchesRecord(phase, record) {
368
+ return (
369
+ (phase === "started" && record.status === McpCallStatus.STARTED) ||
370
+ (phase === "settled" && TERMINAL.has(record.status))
371
+ );
372
+ }
373
+
374
+ const IMMUTABLE_RECORD_FIELDS = Object.freeze([
375
+ "schemaVersion",
376
+ "ledgerId",
377
+ "sessionId",
378
+ "turnId",
379
+ "toolName",
380
+ "serverName",
381
+ "inputDigest",
382
+ "inputBytes",
383
+ "effectContract",
384
+ "resourceScopes",
385
+ "networkScopes",
386
+ "prewritePolicy",
387
+ "startedAt",
388
+ ]);
389
+
390
+ function stableValue(value) {
391
+ if (Array.isArray(value)) return value.map(stableValue);
392
+ if (value && typeof value === "object") {
393
+ return Object.fromEntries(
394
+ Object.keys(value)
395
+ .sort()
396
+ .map((key) => [key, stableValue(value[key])]),
397
+ );
398
+ }
399
+ return value ?? null;
400
+ }
401
+
402
+ function stableSorted(values) {
403
+ return values.map(stableValue).sort((left, right) => {
404
+ const leftDigest = sha256PayloadDigest(left);
405
+ const rightDigest = sha256PayloadDigest(right);
406
+ const digestOrder =
407
+ leftDigest < rightDigest ? -1 : leftDigest > rightDigest ? 1 : 0;
408
+ if (digestOrder) return digestOrder;
409
+ const leftJson = JSON.stringify(left);
410
+ const rightJson = JSON.stringify(right);
411
+ return leftJson < rightJson ? -1 : leftJson > rightJson ? 1 : 0;
412
+ });
413
+ }
414
+
415
+ function canonicalAdjudication(value) {
416
+ if (
417
+ !hasExactFields(value, ADJUDICATION_FIELDS) ||
418
+ value.schemaVersion !== MCP_CALL_RECOVERY_ADJUDICATION_SCHEMA_VERSION ||
419
+ !isCanonicalProtocolText(
420
+ value.requestId,
421
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.identifier,
422
+ ) ||
423
+ !isCanonicalProtocolText(
424
+ value.sessionId,
425
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.identifier,
426
+ ) ||
427
+ !isCanonicalProtocolText(
428
+ value.ledgerId,
429
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.ledgerId,
430
+ ) ||
431
+ !Object.values(McpCallRecoveryDecision).includes(value.decision) ||
432
+ !RAW_AUTHORITY_HASH.test(String(value.expectedHeadHash || "")) ||
433
+ !PAYLOAD_DIGEST.test(String(value.expectedRecoveryDigest || "")) ||
434
+ value.authority !== MCP_CALL_RECOVERY_AUTHORITY ||
435
+ value.confirmation !== MCP_CALL_RECOVERY_CONFIRMATION ||
436
+ !PAYLOAD_DIGEST.test(String(value.reasonDigest || ""))
437
+ ) {
438
+ return null;
439
+ }
440
+ return Object.freeze({
441
+ schemaVersion: value.schemaVersion,
442
+ requestId: value.requestId,
443
+ sessionId: value.sessionId,
444
+ ledgerId: value.ledgerId,
445
+ decision: value.decision,
446
+ expectedHeadHash: value.expectedHeadHash,
447
+ expectedRecoveryDigest: value.expectedRecoveryDigest,
448
+ authority: value.authority,
449
+ confirmation: value.confirmation,
450
+ reasonDigest: value.reasonDigest,
451
+ });
452
+ }
453
+
454
+ function replayToolNamesFromRecord(record) {
455
+ const toolName = record?.toolName;
456
+ const serverName = record?.serverName;
457
+ if (typeof toolName !== "string" || typeof serverName !== "string") {
458
+ return [];
459
+ }
460
+ const aliasPrefix = `mcp__${serverName}__`;
461
+ if (!toolName.startsWith(aliasPrefix)) return [toolName];
462
+ const stripped = toolName.slice(aliasPrefix.length);
463
+ // Historical records did not identify whether toolName was the raw host
464
+ // name or the model-facing alias. Preserve both exact candidates so either
465
+ // interpretation remains denied; new writes use the raw name in agent-core.
466
+ return stripped && stripped !== toolName ? [toolName, stripped] : [toolName];
467
+ }
468
+
469
+ export function deriveMcpExactReplayDenies(record) {
470
+ return Object.freeze(
471
+ replayToolNamesFromRecord(record).map((toolName) =>
472
+ Object.freeze({
473
+ ledgerId: record.ledgerId,
474
+ serverName: record.serverName,
475
+ toolName,
476
+ inputBytes: record.inputBytes,
477
+ replayDigest: computeMcpExactReplayDigest({ ...record, toolName }),
478
+ }),
479
+ ),
480
+ );
481
+ }
482
+
483
+ function exactReplayKey(value) {
484
+ return JSON.stringify([
485
+ value?.serverName || null,
486
+ value?.toolName || null,
487
+ Number.isInteger(value?.inputBytes) ? value.inputBytes : null,
488
+ value?.replayDigest || computeMcpExactReplayDigest(value),
489
+ ]);
490
+ }
491
+
492
+ function exactReplayKeysFromRecord(record) {
493
+ return deriveMcpExactReplayDenies(record).map(exactReplayKey);
494
+ }
495
+
496
+ /** Deterministic digest of the complete active MCP recovery authority. */
497
+ export function computeMcpRecoveryDigest(recovery = {}) {
498
+ const unsettled = Array.isArray(recovery.unsettled) ? recovery.unsettled : [];
499
+ const incidents = Array.isArray(recovery.incidents) ? recovery.incidents : [];
500
+ const adjudications = Array.isArray(recovery.adjudications)
501
+ ? recovery.adjudications
502
+ : [];
503
+ const replayDenied = Array.isArray(recovery.replayDenied)
504
+ ? recovery.replayDenied
505
+ : [];
506
+ return sha256PayloadDigest({
507
+ schemaVersion: RECOVERY_DIGEST_SCHEMA_VERSION,
508
+ sessionId: recovery.sessionId || null,
509
+ headHash: recovery.headHash || null,
510
+ unsettled: stableSorted(unsettled),
511
+ incidents: stableSorted(incidents),
512
+ adjudications: stableSorted(adjudications),
513
+ replayDenied: stableSorted(replayDenied),
514
+ });
515
+ }
516
+
517
+ function immutableRecordMatches(started, settled) {
518
+ return IMMUTABLE_RECORD_FIELDS.every(
519
+ (field) =>
520
+ JSON.stringify(stableValue(started?.[field])) ===
521
+ JSON.stringify(stableValue(settled?.[field])),
522
+ );
523
+ }
524
+
525
+ function invalidRecoveryProjection(reason, cause) {
526
+ const error = new TypeError(
527
+ `Verified MCP recovery projection is invalid (${reason})`,
528
+ cause ? { cause } : undefined,
529
+ );
530
+ error.code = MCP_LEDGER_RECOVERY_PROJECTION_INVALID_CODE;
531
+ return error;
532
+ }
533
+
534
+ /** Validate one canonical projection completion without invoking accessors. */
535
+ export function assertMcpVerifiedProjectionAuthority(
536
+ authority,
537
+ { acceptedCount, headHash },
538
+ ) {
539
+ if (
540
+ !authority ||
541
+ typeof authority !== "object" ||
542
+ Array.isArray(authority) ||
543
+ isProxy(authority) ||
544
+ (Object.getPrototypeOf(authority) !== Object.prototype &&
545
+ Object.getPrototypeOf(authority) !== null) ||
546
+ Object.getOwnPropertySymbols(authority).length > 0
547
+ ) {
548
+ throw invalidRecoveryProjection("completion-authority-not-plain");
549
+ }
550
+ const descriptors = Object.getOwnPropertyDescriptors(authority);
551
+ const fields = Object.keys(descriptors);
552
+ if (
553
+ fields.length !== VERIFIED_PROJECTION_AUTHORITY_FIELDS.size ||
554
+ fields.some(
555
+ (field) =>
556
+ !VERIFIED_PROJECTION_AUTHORITY_FIELDS.has(field) ||
557
+ !("value" in descriptors[field]) ||
558
+ !descriptors[field].enumerable,
559
+ )
560
+ ) {
561
+ throw invalidRecoveryProjection("completion-authority-malformed");
562
+ }
563
+ const projectedHeadHash = descriptors.headHash.value;
564
+ const projectedEventCount = descriptors.eventCount.value;
565
+ if (
566
+ (projectedHeadHash !== null &&
567
+ (typeof projectedHeadHash !== "string" ||
568
+ !RAW_AUTHORITY_HASH.test(projectedHeadHash))) ||
569
+ !Number.isSafeInteger(projectedEventCount) ||
570
+ projectedEventCount < 0 ||
571
+ typeof descriptors.readMessages.value !== "function" ||
572
+ projectedEventCount !== acceptedCount ||
573
+ projectedHeadHash !== headHash
574
+ ) {
575
+ throw invalidRecoveryProjection("completion-authority-mismatch");
576
+ }
577
+ return Object.freeze({
578
+ headHash: projectedHeadHash,
579
+ eventCount: projectedEventCount,
580
+ });
581
+ }
582
+
583
+ /**
584
+ * Copy a recovery authority through the strict MCP JSON boundary before any
585
+ * caller consumes it. This rejects Promises/thenables, Proxies, accessors,
586
+ * toJSON hooks and malformed projections without invoking user getters.
587
+ */
588
+ export function snapshotMcpLedgerRecoveryProjection(sessionId, recovery) {
589
+ let snapshot;
590
+ try {
591
+ snapshot = snapshotMcpJsonRpcInput(recovery);
592
+ } catch (cause) {
593
+ throw invalidRecoveryProjection("not-strict-synchronous-data", cause);
594
+ }
595
+
596
+ if (
597
+ !hasExactFields(snapshot, RECOVERY_PROJECTION_FIELDS) ||
598
+ snapshot.sessionId !== sessionId ||
599
+ snapshot.verified !== true ||
600
+ !Array.isArray(snapshot.records) ||
601
+ !Array.isArray(snapshot.unsettled) ||
602
+ !Array.isArray(snapshot.incidents) ||
603
+ !Array.isArray(snapshot.adjudications) ||
604
+ !Array.isArray(snapshot.replayDenied) ||
605
+ (snapshot.headHash !== null &&
606
+ (typeof snapshot.headHash !== "string" ||
607
+ !RAW_AUTHORITY_HASH.test(snapshot.headHash))) ||
608
+ typeof snapshot.recoveryDigest !== "string" ||
609
+ !PAYLOAD_DIGEST.test(snapshot.recoveryDigest) ||
610
+ (snapshot.remediation !== null &&
611
+ !RECOVERY_REMEDIATIONS.has(snapshot.remediation))
612
+ ) {
613
+ throw invalidRecoveryProjection("malformed-authority");
614
+ }
615
+
616
+ if (snapshot.recoveryDigest !== computeMcpRecoveryDigest(snapshot)) {
617
+ throw invalidRecoveryProjection("digest-mismatch");
618
+ }
619
+
620
+ const expectedRemediation =
621
+ snapshot.incidents.length > 0
622
+ ? "inspect_transcript"
623
+ : snapshot.unsettled.length > 0
624
+ ? "adjudicate_started_calls"
625
+ : snapshot.replayDenied.length > 0
626
+ ? "exact_replay_denied"
627
+ : null;
628
+ if (snapshot.remediation !== expectedRemediation) {
629
+ throw invalidRecoveryProjection("remediation-mismatch");
630
+ }
631
+ return snapshot;
632
+ }
633
+
634
+ /** Create the async sink accepted by `McpCallLedger`. */
635
+ export function createSessionMcpLedgerSink(sessionId, options = {}) {
636
+ const appendEvent = options.appendEvent || storeAppendAuthorityEvent;
637
+ if (
638
+ !isCanonicalProtocolText(
639
+ sessionId,
640
+ MCP_CALL_LEDGER_PROTOCOL_LIMITS.identifier,
641
+ )
642
+ ) {
643
+ throw new TypeError("MCP ledger session sink requires sessionId");
644
+ }
645
+ if (typeof appendEvent !== "function") {
646
+ throw new TypeError("MCP ledger session sink requires appendEvent");
647
+ }
648
+
649
+ return async (record, metadata = {}) => {
650
+ const canonical = canonicalRecord(record);
651
+ if (!canonical) {
652
+ throw new McpCallLedgerStoreError(
653
+ "CC_MCP_LEDGER_RECORD_INVALID",
654
+ "MCP ledger refused to persist an invalid record",
655
+ { sessionId, ledgerId: record?.ledgerId || null },
656
+ );
657
+ }
658
+ if (canonical.sessionId !== sessionId) {
659
+ throw new McpCallLedgerStoreError(
660
+ "CC_MCP_LEDGER_SESSION_MISMATCH",
661
+ "MCP ledger record session does not match its durable transcript",
662
+ { sessionId, ledgerId: canonical.ledgerId },
663
+ );
664
+ }
665
+ const phase = String(metadata.phase || "");
666
+ if (phase !== "started" && phase !== "settled") {
667
+ throw new McpCallLedgerStoreError(
668
+ "CC_MCP_LEDGER_PHASE_INVALID",
669
+ `MCP ledger event phase is invalid: ${phase || "(missing)"}`,
670
+ { sessionId, ledgerId: canonical.ledgerId },
671
+ );
672
+ }
673
+ if (!phaseMatchesRecord(phase, canonical)) {
674
+ throw new McpCallLedgerStoreError(
675
+ "CC_MCP_LEDGER_PHASE_STATUS_MISMATCH",
676
+ `MCP ledger event phase ${phase} does not match status ${canonical.status}`,
677
+ { sessionId, ledgerId: canonical.ledgerId },
678
+ );
679
+ }
680
+ try {
681
+ const written = await appendEvent(sessionId, MCP_CALL_LEDGER_EVENT, {
682
+ schemaVersion: MCP_CALL_LEDGER_EVENT_SCHEMA_VERSION,
683
+ phase,
684
+ record: canonical,
685
+ });
686
+ if (written === false) {
687
+ throw new Error("canonical session store rejected the event");
688
+ }
689
+ return true;
690
+ } catch (cause) {
691
+ throw new McpCallLedgerStoreError(
692
+ "CC_MCP_LEDGER_EVENT_PERSIST_FAILED",
693
+ `MCP ledger event persistence failed for ${sessionId}: ${cause.message}`,
694
+ { sessionId, ledgerId: canonical.ledgerId, cause },
695
+ );
696
+ }
697
+ };
698
+ }
699
+
700
+ /**
701
+ * Create an incremental MCP authority reducer. Every transcript event must be
702
+ * passed to `accept()` in canonical order so verified prefix linkage remains
703
+ * part of the projection. The retained heap is the active MCP authority state,
704
+ * not the complete transcript.
705
+ */
706
+ export function createMcpLedgerEventReducer(options = {}) {
707
+ const records = new Map();
708
+ const incidents = [];
709
+ const adjudications = new Map();
710
+ const adjudicationRequestIds = new Set();
711
+ const replayDenied = new Map();
712
+ const targetSessionId =
713
+ typeof options.sessionId === "string" ? options.sessionId : null;
714
+ const verified = options.verified === true;
715
+ const addIncident = (code, ledgerId = null) => {
716
+ incidents.push(Object.freeze({ code, ledgerId }));
717
+ };
718
+ let prefixHeadHash = null;
719
+
720
+ const accept = (event) => {
721
+ const priorHeadHash = prefixHeadHash;
722
+ const eventHeadHash = RAW_AUTHORITY_HASH.test(String(event?.hash || ""))
723
+ ? event.hash
724
+ : null;
725
+ const prefixLinked =
726
+ eventHeadHash !== null && (event?.prevHash ?? null) === priorHeadHash;
727
+ prefixHeadHash = eventHeadHash;
728
+ if (verified && !prefixLinked) {
729
+ addIncident("CC_MCP_RECOVERY_AUTHORITY_PREFIX_INVALID");
730
+ return;
731
+ }
732
+
733
+ if (event?.type === MCP_CALL_RECOVERY_ADJUDICATION_EVENT) {
734
+ const adjudication = canonicalAdjudication(event.data);
735
+ if (!adjudication) {
736
+ addIncident("CC_MCP_RECOVERY_ADJUDICATION_CORRUPT");
737
+ return;
738
+ }
739
+ if (!verified) {
740
+ addIncident(
741
+ "CC_MCP_RECOVERY_ADJUDICATION_UNVERIFIED",
742
+ adjudication.ledgerId,
743
+ );
744
+ return;
745
+ }
746
+ if (
747
+ targetSessionId === null ||
748
+ adjudication.sessionId !== targetSessionId ||
749
+ priorHeadHash !== adjudication.expectedHeadHash ||
750
+ event.prevHash !== adjudication.expectedHeadHash
751
+ ) {
752
+ addIncident(
753
+ "CC_MCP_RECOVERY_ADJUDICATION_HEAD_MISMATCH",
754
+ adjudication.ledgerId,
755
+ );
756
+ return;
757
+ }
758
+ if (incidents.length > 0) {
759
+ addIncident(
760
+ "CC_MCP_RECOVERY_ADJUDICATION_INCIDENTS_PRESENT",
761
+ adjudication.ledgerId,
762
+ );
763
+ return;
764
+ }
765
+
766
+ const currentSnapshots = [...records.values()];
767
+ const currentRecovery = {
768
+ sessionId: targetSessionId,
769
+ headHash: priorHeadHash,
770
+ unsettled: currentSnapshots.filter(
771
+ (record) =>
772
+ record.status === McpCallStatus.STARTED &&
773
+ !adjudications.has(record.ledgerId),
774
+ ),
775
+ incidents,
776
+ adjudications: [...adjudications.values()],
777
+ replayDenied: [...replayDenied.values()],
778
+ };
779
+ if (
780
+ adjudication.expectedRecoveryDigest !==
781
+ computeMcpRecoveryDigest(currentRecovery)
782
+ ) {
783
+ addIncident(
784
+ "CC_MCP_RECOVERY_ADJUDICATION_DIGEST_MISMATCH",
785
+ adjudication.ledgerId,
786
+ );
787
+ return;
788
+ }
789
+
790
+ const target = records.get(adjudication.ledgerId);
791
+ if (
792
+ !target ||
793
+ target.status !== McpCallStatus.STARTED ||
794
+ adjudications.has(adjudication.ledgerId) ||
795
+ adjudicationRequestIds.has(adjudication.requestId)
796
+ ) {
797
+ addIncident(
798
+ "CC_MCP_RECOVERY_ADJUDICATION_TARGET_INVALID",
799
+ adjudication.ledgerId,
800
+ );
801
+ return;
802
+ }
803
+
804
+ adjudications.set(adjudication.ledgerId, adjudication);
805
+ adjudicationRequestIds.add(adjudication.requestId);
806
+ if (adjudication.decision === McpCallRecoveryDecision.CONFIRMED_APPLIED) {
807
+ for (const deny of deriveMcpExactReplayDenies(target)) {
808
+ const key = exactReplayKey(deny);
809
+ if (!replayDenied.has(key)) replayDenied.set(key, deny);
810
+ }
811
+ }
812
+ return;
813
+ }
814
+
815
+ if (event?.type !== MCP_CALL_LEDGER_EVENT) return;
816
+ const envelope = event.data;
817
+ const record = canonicalRecord(envelope?.record);
818
+ if (
819
+ envelope?.schemaVersion !== MCP_CALL_LEDGER_EVENT_SCHEMA_VERSION ||
820
+ !record ||
821
+ !phaseMatchesRecord(envelope?.phase, record)
822
+ ) {
823
+ addIncident("CC_MCP_LEDGER_EVENT_CORRUPT", record?.ledgerId || null);
824
+ return;
825
+ }
826
+
827
+ if (targetSessionId !== null && record.sessionId !== targetSessionId) {
828
+ addIncident("CC_MCP_LEDGER_SESSION_MISMATCH", record.ledgerId);
829
+ return;
830
+ }
831
+
832
+ if (adjudications.has(record.ledgerId)) {
833
+ addIncident("CC_MCP_LEDGER_ADJUDICATED_REWRITTEN", record.ledgerId);
834
+ return;
835
+ }
836
+
837
+ if (
838
+ exactReplayKeysFromRecord(record).some((key) => replayDenied.has(key))
839
+ ) {
840
+ addIncident("CC_MCP_LEDGER_EXACT_REPLAY_RECORDED", record.ledgerId);
841
+ return;
842
+ }
843
+
844
+ const previous = records.get(record.ledgerId);
845
+ if (previous && TERMINAL.has(previous.status)) {
846
+ addIncident("CC_MCP_LEDGER_TERMINAL_REWRITTEN", record.ledgerId);
847
+ return;
848
+ }
849
+ if (previous && record.status === McpCallStatus.STARTED) {
850
+ addIncident("CC_MCP_LEDGER_DUPLICATE_START", record.ledgerId);
851
+ return;
852
+ }
853
+ if (!previous && record.status !== McpCallStatus.STARTED) {
854
+ addIncident("CC_MCP_LEDGER_START_MISSING", record.ledgerId);
855
+ return;
856
+ }
857
+ if (
858
+ previous &&
859
+ record.status !== McpCallStatus.STARTED &&
860
+ !immutableRecordMatches(previous, record)
861
+ ) {
862
+ addIncident("CC_MCP_LEDGER_RECORD_MISMATCH", record.ledgerId);
863
+ return;
864
+ }
865
+ records.set(record.ledgerId, Object.freeze({ ...record }));
866
+ };
867
+
868
+ const finish = () => {
869
+ const snapshots = [...records.values()];
870
+ const unsettled = snapshots.filter(
871
+ (record) =>
872
+ record.status === McpCallStatus.STARTED &&
873
+ !adjudications.has(record.ledgerId),
874
+ );
875
+ const denied = [...replayDenied.values()];
876
+ const recovery = {
877
+ sessionId: targetSessionId,
878
+ records: Object.freeze(snapshots),
879
+ unsettled: Object.freeze(unsettled),
880
+ incidents: Object.freeze(incidents),
881
+ adjudications: Object.freeze([...adjudications.values()]),
882
+ replayDenied: Object.freeze(denied),
883
+ verified,
884
+ headHash: prefixHeadHash,
885
+ };
886
+ const remediation =
887
+ incidents.length > 0
888
+ ? "inspect_transcript"
889
+ : unsettled.length > 0
890
+ ? "adjudicate_started_calls"
891
+ : denied.length > 0
892
+ ? "exact_replay_denied"
893
+ : null;
894
+ return Object.freeze({
895
+ ...recovery,
896
+ recoveryDigest: computeMcpRecoveryDigest(recovery),
897
+ remediation,
898
+ });
899
+ };
900
+
901
+ return Object.freeze({ accept, finish });
902
+ }
903
+
904
+ /**
905
+ * Batch compatibility wrapper around the incremental authority reducer.
906
+ */
907
+ export function reduceMcpLedgerEvents(events, options = {}) {
908
+ const reducer = createMcpLedgerEventReducer(options);
909
+ for (const event of Array.isArray(events) ? events : []) {
910
+ reducer.accept(event);
911
+ }
912
+ return reducer.finish();
913
+ }
914
+
915
+ export function loadMcpLedgerRecovery(sessionId, options = {}) {
916
+ const hasInjectedProjection = Object.prototype.hasOwnProperty.call(
917
+ options,
918
+ "readVerifiedProjection",
919
+ );
920
+ const hasInjectedLegacyReader = Object.prototype.hasOwnProperty.call(
921
+ options,
922
+ "readVerifiedEvents",
923
+ );
924
+ if (
925
+ (hasInjectedProjection &&
926
+ typeof options.readVerifiedProjection !== "function") ||
927
+ (hasInjectedLegacyReader &&
928
+ typeof options.readVerifiedEvents !== "function")
929
+ ) {
930
+ throw new McpCallLedgerStoreError(
931
+ "CC_MCP_LEDGER_EVENT_READ_FAILED",
932
+ `MCP ledger recovery failed for ${sessionId}: verified reader is invalid`,
933
+ {
934
+ sessionId,
935
+ cause: invalidRecoveryProjection("reader-not-callable"),
936
+ },
937
+ );
938
+ }
939
+ const hasCustomLegacyReader =
940
+ hasInjectedLegacyReader &&
941
+ options.readVerifiedEvents !== storeReadVerifiedEvents;
942
+ const readVerifiedProjection = hasInjectedProjection
943
+ ? options.readVerifiedProjection
944
+ : hasCustomLegacyReader
945
+ ? null
946
+ : storeReadVerifiedProjection;
947
+ const readVerifiedEvents =
948
+ options.readVerifiedEvents || storeReadVerifiedEvents;
949
+ try {
950
+ if (typeof readVerifiedProjection === "function") {
951
+ let projectionCreated = false;
952
+ let finishedProjection;
953
+ const returnedProjection = readVerifiedProjection(sessionId, () => {
954
+ if (projectionCreated) {
955
+ throw invalidRecoveryProjection("factory-reused");
956
+ }
957
+ projectionCreated = true;
958
+ let acceptedCount = 0;
959
+ let finished = false;
960
+ const reducer = createMcpLedgerEventReducer({
961
+ sessionId,
962
+ verified: true,
963
+ });
964
+ return Object.freeze({
965
+ accept(event) {
966
+ if (finished) {
967
+ throw invalidRecoveryProjection("accept-after-finish");
968
+ }
969
+ acceptedCount += 1;
970
+ reducer.accept(event);
971
+ },
972
+ finish(authority) {
973
+ if (finished) {
974
+ throw invalidRecoveryProjection("finish-reused");
975
+ }
976
+ finished = true;
977
+ const recovery = reducer.finish();
978
+ assertMcpVerifiedProjectionAuthority(authority, {
979
+ acceptedCount,
980
+ headHash: recovery.headHash,
981
+ });
982
+ finishedProjection = recovery;
983
+ return recovery;
984
+ },
985
+ });
986
+ });
987
+ if (
988
+ !projectionCreated ||
989
+ finishedProjection === undefined ||
990
+ returnedProjection !== finishedProjection
991
+ ) {
992
+ throw invalidRecoveryProjection("reader-bypassed-factory");
993
+ }
994
+ return snapshotMcpLedgerRecoveryProjection(sessionId, returnedProjection);
995
+ }
996
+ const verifiedEvents = snapshotMcpJsonRpcInput(
997
+ readVerifiedEvents(sessionId),
998
+ );
999
+ if (!Array.isArray(verifiedEvents)) {
1000
+ const invalid = new TypeError(
1001
+ "Verified MCP ledger events must be returned synchronously as an array",
1002
+ );
1003
+ invalid.code = "CC_MCP_LEDGER_VERIFIED_EVENTS_INVALID";
1004
+ throw invalid;
1005
+ }
1006
+ return snapshotMcpLedgerRecoveryProjection(
1007
+ sessionId,
1008
+ reduceMcpLedgerEvents(verifiedEvents, {
1009
+ sessionId,
1010
+ verified: true,
1011
+ }),
1012
+ );
1013
+ } catch (cause) {
1014
+ throw new McpCallLedgerStoreError(
1015
+ "CC_MCP_LEDGER_EVENT_READ_FAILED",
1016
+ `MCP ledger recovery failed for ${sessionId}: ${cause.message}`,
1017
+ { sessionId, cause },
1018
+ );
1019
+ }
1020
+ }
1021
+
1022
+ /** Bounded, content-free recovery notice for model/IDE presentation. */
1023
+ export function formatMcpLedgerRecoveryNotice(recovery, options = {}) {
1024
+ const maxItems = Math.max(1, Math.min(20, Number(options.maxItems) || 10));
1025
+ const unsettled = Array.isArray(recovery?.unsettled)
1026
+ ? recovery.unsettled.slice(0, maxItems)
1027
+ : [];
1028
+ const incidents = Array.isArray(recovery?.incidents)
1029
+ ? recovery.incidents.slice(0, maxItems)
1030
+ : [];
1031
+ const replayDenied = Array.isArray(recovery?.replayDenied)
1032
+ ? recovery.replayDenied.slice(0, maxItems)
1033
+ : [];
1034
+ if (
1035
+ unsettled.length === 0 &&
1036
+ incidents.length === 0 &&
1037
+ replayDenied.length === 0
1038
+ ) {
1039
+ return null;
1040
+ }
1041
+
1042
+ const lines = unsettled.map((record) => {
1043
+ const effect = record.effectContract?.effect || "unknown";
1044
+ return ` • ${record.ledgerId}: ${record.serverName}/${record.toolName} [${effect}] — outcome unknown; inspect before retry`;
1045
+ });
1046
+ for (const incident of incidents) {
1047
+ lines.push(
1048
+ ` • ledger incident ${incident.code}${incident.ledgerId ? ` (${incident.ledgerId})` : ""} — fail closed and inspect transcript`,
1049
+ );
1050
+ }
1051
+ for (const deny of replayDenied) {
1052
+ lines.push(
1053
+ ` • ${deny.ledgerId}: ${deny.serverName}/${deny.toolName} — exact replay denied (${deny.replayDigest})`,
1054
+ );
1055
+ }
1056
+ const omitted =
1057
+ Math.max(0, (recovery?.unsettled?.length || 0) - unsettled.length) +
1058
+ Math.max(0, (recovery?.incidents?.length || 0) - incidents.length) +
1059
+ Math.max(0, (recovery?.replayDenied?.length || 0) - replayDenied.length);
1060
+ if (omitted > 0)
1061
+ lines.push(` • ${omitted} additional ledger item(s) omitted`);
1062
+
1063
+ return (
1064
+ "MCP recovery notice — a previous run left MCP recovery authority that " +
1065
+ "must be enforced. Do NOT automatically retry denied or outcome-unknown " +
1066
+ "calls. Verify the external resource first and ask the user when uncertain:\n" +
1067
+ lines.join("\n")
1068
+ );
1069
+ }