chainlesschain 0.162.198 → 0.162.200

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 (195) hide show
  1. package/bin/chainlesschain.js +14 -6
  2. package/package.json +4 -1
  3. package/scripts/command-lifecycle-report.mjs +94 -0
  4. package/src/assets/web-panel/assets/{AIOps-CSN-D2xb.js → AIOps-DcQ0bWKy.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-CBSMlGzv.js → ActionButton-GecwfFPt.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-3yr3Nt2t.js → Analytics-CD6iSt9v.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-1b-o3lMH.js → AppLayout-CDEtuEYf.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-Dr8rJi17.js → Artifacts-DS3jAjeW.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-2V689HC2.js → Audit-CcSJA048.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-DIxkNrD_.js → BackgroundAgents-DRo9Morb.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-Pg6BcwrE.js → Backup-Vw5MrWft.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-CLUpqyfH.js → BaseInput-DNHIu823.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-qVS8rD4G.js → Chat-DvAsO8-b.js} +5 -5
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-ti49X12Q.js → ChatBubbleRenderer-9aDuObay.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-Bs9AaEay.js → Checkbox-CKCa7tvn.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-Dvc1mq8q.js → Codegen-CIFvZdaT.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-C4_biO7A.js → Col-C79yz7bK.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-al25XQUV.js → Community-DVvZskLJ.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-D-ZDB8M1.js → Compact-oaew61hV.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-6lIfDz1W.js → Compliance-DqA7wmRx.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-DdI48XMJ.js → Cowork-B-qGadxa.js} +2 -2
  22. package/src/assets/web-panel/assets/{Cron-DF5HZd2g.js → Cron-CUlCl4sS.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-DuxeSvt3.js → Crosschain-CNOlr9DU.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-B9yHkUTd.js → DID-DJqFCT_3.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-Z5EuI3IM.js → Dashboard-CznGpphf.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-vuRfO3dY.js → Dropdown-_cJw218E.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-QFLCc1uL.js → EmailListRenderer-Dr-1BZ9C.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BZ7EXkFJ.js → FamilyGuardDashboard-Dxf4xtSk.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-DycIEg2s.js → Federation-DOiG3i_1.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-Ba0H_7yG.js → FormItemContext-BzbMcFB9.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer--JgSTK-C.js → GenericCardRenderer-VbBrYttP.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-DEvTbldE.js → Git-CLG8E6ED.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-BJIljy18.js → Governance-LGJQfk_q.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-CVyW3G3q.js → Inference-DlQKx9lF.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-v8-borge.js → KnowledgeGraph-DU8vEouV.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-BCdS7gGo.js → Logs-FZIQOdln.js} +2 -2
  37. package/src/assets/web-panel/assets/MarkdownRenderer-BJNWIrbw.js +1 -0
  38. package/src/assets/web-panel/assets/{Marketplace-AN6tGA2B.js → Marketplace-C_xd-zZI.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-DGViXASN.js → McpTools-q-YktphS.js} +5 -5
  40. package/src/assets/web-panel/assets/{Memory-Bpvmx9X4.js → Memory-Cq9OhDin.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-CTP-DOTC.js → MobileBridge-B03_R98T.js} +1 -1
  42. package/src/assets/web-panel/assets/{MobileProjects-C8qfktxn.js → MobileProjects-DZrk-qmF.js} +1 -1
  43. package/src/assets/web-panel/assets/{Mtc-ndYr0M1s.js → Mtc-BidCKW28.js} +2 -2
  44. package/src/assets/web-panel/assets/{MtcAudit-Ci0-YK7W.js → MtcAudit-r-iaMVM7.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-BehSTFW7.js → Multisig-CgTUFvff.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-B91_YBLv.js → NLProgramming-B7NvzfAV.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-BQlJ0-gq.js → Notes-80CWNqJI.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-CDgYMjYK.js → NotificationSettings-0H6xdiY3.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-BJkSlKeH.js → OrderTableRenderer-CKP4AFWy.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-B-b3cWCp.js → Organization-B8sxCV_h.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-CILUL4nL.js → Overflow-CW9JBBhQ.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-BTCFBkF0.js → P2P-bdSQV7oZ.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-BAR6AUx5.js → PdhVaultBrowser-DQad42nW.js} +3 -3
  54. package/src/assets/web-panel/assets/{Permissions-RRf6HbWJ.js → Permissions-CueexxTR.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-BGTMiICa.js → PersonalDataHub-fqxflhR8.js} +6 -6
  56. package/src/assets/web-panel/assets/{Pipeline-945qY9YF.js → Pipeline-KFwwnIMC.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-DPZwI6lJ.js → Privacy-ClnD9buY.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-BPH2NRKc.js → ProjectInit-CZEz6sm3.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-BZCRNCvb.js → ProjectSettings-B6NzpmOI.js} +2 -2
  60. package/src/assets/web-panel/assets/{Projects-BTI__tBt.js → Projects-DYyuwPCs.js} +1 -1
  61. package/src/assets/web-panel/assets/Providers-C3tz_jdh.js +1 -0
  62. package/src/assets/web-panel/assets/{QrScannerModal-N6rbqt1r.js → QrScannerModal-BzuOBbqB.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-DrwjPS7M.js → QuickAsk-CmNO9qSj.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-Cog9Wd99.js → Recommend-VJNj3_NF.js} +1 -1
  65. package/src/assets/web-panel/assets/{RemoteSession-DC9pynjM.js → RemoteSession-CrbdbSBF.js} +2 -2
  66. package/src/assets/web-panel/assets/{Reputation-D4th4gKS.js → Reputation-DTyMd45j.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-ogiWR6v9.js → Row-DHrQ-Icz.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-uYlk-2Oj.js → RssFeed-DqWxY9c5.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-DYzzwvtM.js → Search-ctF1Ks3J.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-Da7YOyX6.js → Security-BrQz8uo5.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-CLI1VM1X.js → Services-D4scVFar.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-DK77dzDC.js → Skeleton-oUScaOjv.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-C_z7Lmhl.js → Skills-CL-y0eLt.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-D6413Q8L.js → Sla-DQExhwXj.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-C07ydbj2.js → SpeechSettings-iNp_I7kN.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-DGOm2W22.js → SyncSettings-CTDlMo0A.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-Cr_PVyLM.js → Tasks-4kb8l3sc.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-BhL2mZ0t.js → Templates-BXcL9oXW.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-CPk5oyUr.js → Tenant-DLE8eS0D.js} +1 -1
  80. package/src/assets/web-panel/assets/{Terminal-ClhqUsqV.js → Terminal-DGpUZPPK.js} +2 -2
  81. package/src/assets/web-panel/assets/{TimelineRenderer-BCC7MV5a.js → TimelineRenderer-C1pWXGPC.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-DD1Jt4oO.js → Tokens-BYfbfqhZ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-BCydFvN2.js → Trigger-K9YfLOCw.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-DDHT1noa.js → Trust-Ctkq77Hy.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-CWPZC7oI.js → UkeySign-C6_CSe9J.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-9Ea0nJR0.js → VideoEditing-Be3rpOWs.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-BjxhLxTf.js → Wallet-D0UIplxk.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-C6uCye67.js → WebAuthn-CF9bM9I3.js} +3 -3
  89. package/src/assets/web-panel/assets/{WorkflowEditor-d2g4reYo.js → WorkflowEditor-D0H1XVPY.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-frTc6ScX.js → chat-Cgzzbe0o.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-B5K6lG3v.js → colors-BwNxEVS0.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-Cdn46r8D.js → compact-item-D60Z4Hhs.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-DU1jqVQi.js → createContext-MFk58XB0.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-BJiw369i.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-DdNH-aW_.js → hasIn-CRj2SvGO.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DM5FmPZU.js → index--s45_1cb.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-D4l82Me1.js → index--tquQ2ZG.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CQorP1Ng.js → index-1T1rhokn.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CHmkkdfT.js → index-B-M82_rx.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CGiwfwB9.js → index-BE_el1Zs.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BwlIxAmX.js → index-BhRkR7IO.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Cj6P9Nst.js → index-Bo0y96-K.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BoFak7le.js → index-CJgu5JUK.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Dca_i7H8.js → index-CLWwdebO.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BVLL-mq_.js → index-CNAK5QG_.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-LaivuXyF.js → index-CQjJjPRD.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-t_OBzIP4.js → index-CTDbAfae.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BcGwGIaR.js → index-CVI_9sRK.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-D23xGYjM.js → index-CY14oMQK.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-VDM2KKo9.js → index-CbiTJkZf.js} +1 -1
  111. package/src/assets/web-panel/assets/index-CiMouosn.js +1 -0
  112. package/src/assets/web-panel/assets/{index-32ajXmTb.js → index-CqWpxMqx.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-PjAS0sIZ.js → index-CvB8lYUR.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-7ehytj1K.js → index-D51XwtCY.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DtBCCkC4.js → index-D6HvK_1O.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-Be4OtL-N.js → index-D9jVIwLJ.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CUoNAmE8.js → index-DA4tE98u.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-cYaWV4Mq.js → index-DBwOtXw0.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-MM4Zz2OE.js → index-DKdNzTIb.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-DIVyTmZ3.js → index-DRySdmvN.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CtRPi4YC.js → index-DWzyTev7.js} +1 -1
  122. package/src/assets/web-panel/assets/index-DXcKlwy7.js +1 -0
  123. package/src/assets/web-panel/assets/{index-kVO_MDm-.js → index-DYjs7jAP.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D4miNkWv.js → index-DbROzMBp.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-yZRuZpwK.js → index-DhFtk5PR.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BXKhhx9V.js → index-Di2AbMLg.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BC4eGkar.js → index-DvmocQsM.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-NmEXVjzt.js → index-Dw-o0zEF.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DRzBBdQ0.js → index-DysPoP38.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-HjCvXHf5.js → index-LX9pJxm_.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-gg3QPC3i.js → index-OI_fXWx0.js} +3 -3
  132. package/src/assets/web-panel/assets/{index-mgU3Q-lN.js → index-eDTOX8Xj.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-D1qIC4GR.js → index-gWKDsTzF.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-DftZuyA7.js → index-q_GDUVAA.js} +1 -1
  135. package/src/assets/web-panel/assets/{initDefaultProps-DwLTRNdo.js → initDefaultProps-C61kZqEd.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-BchZDXnh.js → motion-DZnT5U1L.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-e8M-zZFl.js → move-L8wzwbel.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-Ci40fQb3.js → mtc-parser-DLdYSejc.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-C7110_f2.js → omit-D53cbS59.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-skteMgnM.js → pickAttrs-Bbc5HPtu.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-MGZ-lh2B.js → placementArrow-BkvmO860.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-N4Sd7uy-.js → responsiveObserve-u2y1ryS1.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-C7HDGRaa.js → slide-BBqj7svU.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-BhRexlgy.js → statusUtils-GN0mqu2d.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-ChEoQkN2.js → styleChecker-BvwPKoBT.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-CDbG1s2Y.js → useFlexGapSupport-CCt8tnfY.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-CUIx0tcJ.js → useFs-DXAxl2SV.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-bkO7L7ec.js → usePersonalDataHub-DihlR2dj.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-B_ZvABIG.js → vnode-D7BOX2gi.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-D5shjpS8.js → zoom-CVbO-nL7.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/command-help-index.json +1 -1
  153. package/src/commands/mcp.js +119 -0
  154. package/src/commands/session-show.js +8 -10
  155. package/src/commands/session.js +60 -52
  156. package/src/data/changelog.json +27 -1
  157. package/src/gateways/ws/session-protocol.js +14 -4
  158. package/src/gateways/ws/ws-agent-handler.js +31 -0
  159. package/src/harness/jsonl-session-store.js +1147 -130
  160. package/src/harness/mcp-client.js +44 -11
  161. package/src/harness/session-index.js +80 -80
  162. package/src/harness/session-list-index.js +147 -2
  163. package/src/lib/background-interaction-journal.js +2 -2
  164. package/src/lib/command-lifecycle-report.js +516 -0
  165. package/src/lib/mcp-stdio-environment.js +48 -0
  166. package/src/lib/mcp-stdio-executable-identity.js +552 -17
  167. package/src/lib/mcp-stdio-package-materialization.js +1424 -0
  168. package/src/lib/packer/native-update-state.js +979 -1
  169. package/src/lib/packer/pack-update-applier.js +1050 -125
  170. package/src/lib/packer/pkg-config-generator.js +1 -0
  171. package/src/lib/paths.js +53 -0
  172. package/src/lib/process-execution-broker/index.js +180 -37
  173. package/src/lib/process-execution-broker/platform-sandbox.js +291 -24
  174. package/src/lib/recent-session.js +17 -17
  175. package/src/lib/secure-file-identity.js +47 -0
  176. package/src/lib/secure-fs.js +21 -2
  177. package/src/lib/session-anti-rollback-anchor.js +766 -0
  178. package/src/lib/session-host-lease.js +492 -0
  179. package/src/lib/session-persistence-failure.js +109 -0
  180. package/src/lib/session-picker.js +26 -3
  181. package/src/lib/session-search.js +25 -11
  182. package/src/lib/side-effect-ledger-store.js +2 -2
  183. package/src/lib/skill-execution-authority.js +13 -9
  184. package/src/lib/turn-binding-store.js +2 -2
  185. package/src/repl/agent-repl.js +309 -39
  186. package/src/runtime/agent-core.js +88 -5
  187. package/src/runtime/cleanup-deadline.js +143 -0
  188. package/src/runtime/headless-runner.js +357 -139
  189. package/src/runtime/headless-stream.js +207 -28
  190. package/src/runtime/output-backpressure.js +53 -0
  191. package/src/assets/web-panel/assets/MarkdownRenderer-CU-JB2Ns.js +0 -1
  192. package/src/assets/web-panel/assets/Providers-DDCf_nIw.js +0 -1
  193. package/src/assets/web-panel/assets/devWarning-CP-jEUyw.js +0 -1
  194. package/src/assets/web-panel/assets/index-CzrCHrFy.js +0 -1
  195. package/src/assets/web-panel/assets/index-OJsGskZw.js +0 -1
@@ -44,8 +44,14 @@ import {
44
44
  MCP_STDIO_LOCAL_CODE_TRUST_REQUIRED_CODE,
45
45
  issueMcpStdioExecutionAuthority,
46
46
  materializeApprovedMcpStdioInvocation,
47
+ resolveMcpStdioExecutionApproval,
47
48
  } from "../lib/mcp-stdio-execution-authority.js";
48
49
  import { prepareMcpStdioExecutableIdentity } from "../lib/mcp-stdio-executable-identity.js";
50
+ import {
51
+ materializeMcpStdioNpmPackage,
52
+ parseExactNpmPackageSpec,
53
+ } from "../lib/mcp-stdio-package-materialization.js";
54
+ import { executionBroker } from "../lib/process-execution-broker/index.js";
49
55
  import {
50
56
  CATALOG as REGISTRY_CATALOG,
51
57
  CATEGORIES as REGISTRY_CATEGORIES,
@@ -807,6 +813,119 @@ export function registerMcpCommand(program) {
807
813
  }
808
814
  });
809
815
 
816
+ mcp
817
+ .command("materialize-package <name>")
818
+ .description(
819
+ "Replace one exact JavaScript package launcher with a content-addressed, guarded dependency capsule",
820
+ )
821
+ .requiredOption(
822
+ "--package <name@version>",
823
+ "Exact npm registry package version to install (ranges and tags are rejected)",
824
+ )
825
+ .option(
826
+ "--bin <name>",
827
+ "Select one exported bin when the package has several",
828
+ )
829
+ .option(
830
+ "--scope <scope>",
831
+ `Configuration scope: ${MCP_CONFIG_SCOPES.join(" | ")}`,
832
+ )
833
+ .option(
834
+ "--json",
835
+ "Output the materialized generation and closure identity as JSON",
836
+ )
837
+ .action(async (name, options) => {
838
+ try {
839
+ const exact = parseExactNpmPackageSpec(options.package);
840
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
841
+ if (!ctx.db) throw new Error("Database not available");
842
+ const configStore = new MCPServerConfig(ctx.db.getDatabase());
843
+ const scope = options.scope
844
+ ? normalizeMcpConfigScope(options.scope)
845
+ : undefined;
846
+ const rows = await effectiveMcpRows(configStore, { scope });
847
+ const row = rows.find((entry) => entry.name === name);
848
+ if (!row) {
849
+ throw new Error(
850
+ `${notFoundWithSuggestion(
851
+ name,
852
+ rows.map((entry) => entry.name),
853
+ { noun: "Server" },
854
+ )}. Use 'mcp add' first.`,
855
+ );
856
+ }
857
+ if (inferTransport(row) !== "stdio") {
858
+ throw new Error(
859
+ `MCP server "${name}" does not use the stdio transport`,
860
+ );
861
+ }
862
+
863
+ const authorized = authorizeMcpRowForConnect(row);
864
+ const approval = consumeMcpStdioExecutionAuthority(
865
+ authorized.mcpStdioExecutionAuthority,
866
+ { serverName: name, config: authorized },
867
+ );
868
+ const invocation = materializeApprovedMcpStdioInvocation(approval);
869
+ const approvalRecord = resolveMcpStdioExecutionApproval(approval);
870
+ const materialized = materializeMcpStdioNpmPackage({
871
+ approvalRecord,
872
+ config: invocation,
873
+ packageSpec: exact.spec,
874
+ ...(options.bin ? { binName: options.bin } : {}),
875
+ env: process.env,
876
+ processBrokerRunSync: (command, args, spawnOptions) =>
877
+ executionBroker.spawnSync(command, args, {
878
+ ...spawnOptions,
879
+ origin: `mcp:package-materialization:${name}`,
880
+ policy: "allow",
881
+ scope: "mcp",
882
+ shell: false,
883
+ }),
884
+ });
885
+ const prepared = prepareMcpStdioExecutableIdentity({
886
+ serverName: name,
887
+ config: invocation,
888
+ approval,
889
+ cwd: process.cwd(),
890
+ env: process.env,
891
+ retrust: true,
892
+ });
893
+ const result = {
894
+ name,
895
+ package: exact.spec,
896
+ generation: materialized.generation,
897
+ manifestDigest: materialized.manifestDigest,
898
+ identityDigest: prepared.identityDigest,
899
+ closure: materialized.identity,
900
+ command: prepared.identity.command,
901
+ entrypoints: prepared.identity.entrypoints,
902
+ };
903
+ if (options.json) {
904
+ console.log(JSON.stringify(result, null, 2));
905
+ } else {
906
+ logger.log(
907
+ chalk.green(
908
+ `Materialized and trusted ${exact.spec} for MCP server "${name}".`,
909
+ ),
910
+ );
911
+ logger.log(
912
+ ` ${chalk.gray("Generation:")} ${materialized.generation}`,
913
+ );
914
+ logger.log(
915
+ ` ${chalk.gray("Dependency closure:")} sha256:${materialized.identity.closureDigest} (${materialized.identity.fileCount} files, ${materialized.identity.totalBytes} bytes)`,
916
+ );
917
+ logger.log(
918
+ ` ${chalk.gray("Execution capsule:")} sha256:${materialized.identity.capsule.sha256} (${materialized.identity.capsule.bytes} bytes, ${materialized.identity.capsule.inputCount} bundled inputs)`,
919
+ );
920
+ }
921
+ await shutdown();
922
+ } catch (err) {
923
+ logger.error(`Failed: ${err.message}`);
924
+ process.exitCode = 1;
925
+ await shutdown();
926
+ }
927
+ });
928
+
810
929
  mcp
811
930
  .command("trust-executable <name>")
812
931
  .description(
@@ -1,13 +1,11 @@
1
1
  import chalk from "chalk";
2
2
  import { numericOption } from "../lib/cli-numeric.js";
3
- import { feature } from "../lib/feature-flags.js";
4
3
  import { logger } from "../lib/logger.js";
5
4
  import { getPrLinks } from "../lib/pr-link-store.js";
6
5
  import {
7
6
  getJsonlSessionMetadata,
8
7
  rebuildMessages,
9
- resolveSessionId,
10
- sessionHasPersistedEvidence,
8
+ resolveSessionAuthority,
11
9
  } from "../harness/jsonl-session-store.js";
12
10
 
13
11
  export function registerSessionShowSubcommand(session, program) {
@@ -23,14 +21,14 @@ export function registerSessionShowSubcommand(session, program) {
23
21
  try {
24
22
  let sess = null;
25
23
 
26
- const jsonlId = feature("JSONL_SESSION") ? resolveSessionId(id) : null;
27
- if (
28
- !jsonlId &&
29
- feature("JSONL_SESSION") &&
30
- sessionHasPersistedEvidence(id)
31
- ) {
24
+ // The feature flag controls creation/migration, not authority. Once a
25
+ // canonical namespace witness exists it must fence the legacy DB even
26
+ // if JSONL_SESSION is later disabled.
27
+ const authority = resolveSessionAuthority(id);
28
+ const jsonlId = authority?.readable ? authority.id : null;
29
+ if (authority && !authority.readable) {
32
30
  logger.error(
33
- `Session ${id} has canonical persistence evidence but no readable transcript.`,
31
+ `Session ${authority.id} has canonical persistence evidence but no readable transcript (${authority.presence}).`,
34
32
  );
35
33
  process.exitCode = 1;
36
34
  return;
@@ -47,18 +47,17 @@ import {
47
47
  getSessionManagerStatsV2,
48
48
  } from "../lib/session-manager.js";
49
49
  import {
50
- listJsonlSessions,
50
+ listSessionAuthoritySummaries,
51
+ listSessionEvidenceIds,
51
52
  rebuildMessages,
52
53
  getJsonlSessionMetadata,
53
- resolveSessionId,
54
- sessionHasPersistedEvidence,
54
+ resolveSessionAuthority,
55
55
  deleteJsonlSession,
56
56
  migrateLegacySessions,
57
57
  migrateLegacySessionsBatch,
58
58
  validateJsonlSession,
59
59
  validateAllJsonlSessions,
60
60
  } from "../harness/jsonl-session-store.js";
61
- import { feature } from "../lib/feature-flags.js";
62
61
  import {
63
62
  listWorkflowSessions,
64
63
  readWorkflowSession,
@@ -234,26 +233,24 @@ export function registerSessionCommand(program) {
234
233
  const ctx = await bootstrap({ verbose: program.opts().verbose });
235
234
  const limit = Math.max(1, parseInt(options.limit) || 20);
236
235
  let sessions = [];
236
+ const canonicalIds = new Set(listSessionEvidenceIds());
237
237
 
238
238
  // Merge DB sessions + JSONL sessions
239
239
  if (ctx.db) {
240
240
  const db = ctx.db.getDatabase();
241
241
  sessions.push(
242
- ...listSessions(db, { limit }).map((s) => ({
243
- ...s,
244
- _store: "db",
245
- })),
242
+ ...listSessions(db, { limit })
243
+ .filter((s) => !canonicalIds.has(s?.id))
244
+ .map((s) => ({
245
+ ...s,
246
+ _store: "db",
247
+ })),
246
248
  );
247
249
  }
248
250
 
249
- if (feature("JSONL_SESSION")) {
250
- sessions.push(
251
- ...listJsonlSessions({ limit }).map((s) => ({
252
- ...s,
253
- _store: "jsonl",
254
- })),
255
- );
256
- }
251
+ // Existing canonical sessions remain authoritative even if the
252
+ // creation/migration feature flag is later disabled.
253
+ sessions.push(...listSessionAuthoritySummaries({ limit }));
257
254
 
258
255
  // Deduplicate by id (JSONL takes precedence) and rank by real time.
259
256
  sessions = rankSessions(sessions, limit);
@@ -324,11 +321,14 @@ export function registerSessionCommand(program) {
324
321
  try {
325
322
  ctx = await bootstrap({ verbose: program.opts().verbose });
326
323
  if (ctx.db) {
324
+ const canonicalIds = new Set(listSessionEvidenceIds());
327
325
  local.push(
328
- ...listSessions(ctx.db.getDatabase(), { limit }).map((item) => ({
329
- ...item,
330
- _store: "db",
331
- })),
326
+ ...listSessions(ctx.db.getDatabase(), { limit })
327
+ .filter((item) => !canonicalIds.has(item?.id))
328
+ .map((item) => ({
329
+ ...item,
330
+ _store: "db",
331
+ })),
332
332
  );
333
333
  }
334
334
  } catch (error) {
@@ -338,12 +338,7 @@ export function registerSessionCommand(program) {
338
338
  // JSONL is the canonical transcript store and can be read without
339
339
  // bootstrapping legacy native DB/config packages (some of which
340
340
  // write banners directly to stdout and would corrupt --json).
341
- local.push(
342
- ...listJsonlSessions({ limit }).map((item) => ({
343
- ...item,
344
- _store: "jsonl",
345
- })),
346
- );
341
+ local.push(...listSessionAuthoritySummaries({ limit }));
347
342
  local = rankSessions(local, limit);
348
343
  } catch (error) {
349
344
  sourceErrors.local = error?.message || String(error);
@@ -613,15 +608,14 @@ export function registerSessionCommand(program) {
613
608
  id = picked.id;
614
609
  }
615
610
 
616
- // Try JSONL first
617
- const jsonlId = feature("JSONL_SESSION") ? resolveSessionId(id) : null;
618
- if (
619
- !jsonlId &&
620
- feature("JSONL_SESSION") &&
621
- sessionHasPersistedEvidence(id)
622
- ) {
611
+ // Try the complete canonical namespace first. The feature flag cannot
612
+ // make an existing/damaged canonical generation disappear and thereby
613
+ // authorize a legacy fallback.
614
+ const authority = resolveSessionAuthority(id);
615
+ const jsonlId = authority?.readable ? authority.id : null;
616
+ if (authority && !authority.readable) {
623
617
  logger.error(
624
- `Session ${id} has canonical persistence evidence but no readable transcript.`,
618
+ `Session ${authority.id} has canonical persistence evidence but no readable transcript (${authority.presence}).`,
625
619
  );
626
620
  logger.error(
627
621
  "Refusing legacy fallback. Inspect or explicitly delete the damaged JSONL session before reusing its id.",
@@ -735,11 +729,14 @@ export function registerSessionCommand(program) {
735
729
  // Canonical content source: append-only JSONL event log. The legacy DB
736
730
  // is consulted only when no matching transcript exists.
737
731
  const store = await import("../harness/jsonl-session-store.js");
738
- const sid =
739
- id === "last" ? store.getLastSessionId() : store.resolveSessionId(id);
740
- if (!sid && id !== "last" && store.sessionHasPersistedEvidence(id)) {
732
+ const requestedId = id === "last" ? store.getLastSessionId() : id;
733
+ const authority = requestedId
734
+ ? store.resolveSessionAuthority(requestedId)
735
+ : null;
736
+ const sid = authority?.readable ? authority.id : null;
737
+ if (authority && !authority.readable) {
741
738
  throw new Error(
742
- `Session ${id} has canonical persistence evidence but no readable transcript`,
739
+ `Session ${authority.id} has canonical persistence evidence but no readable transcript (${authority.presence})`,
743
740
  );
744
741
  }
745
742
  if (sid) {
@@ -820,7 +817,10 @@ export function registerSessionCommand(program) {
820
817
  try {
821
818
  const sessionIndex = await import("../harness/session-index.js");
822
819
  indexDb = sessionIndex.openIndex();
823
- sessionIndex.syncIndex(indexDb);
820
+ const sync = sessionIndex.syncIndex(indexDb);
821
+ if (sync.rejected > 0) {
822
+ indexDiagnostic = `${sync.rejected} canonical session(s) were excluded because verification failed`;
823
+ }
824
824
  matches = sessionIndex
825
825
  .searchSessions(indexDb, query, { limit })
826
826
  .map((hit) => ({
@@ -841,7 +841,7 @@ export function registerSessionCommand(program) {
841
841
  });
842
842
  for (const s of sessions) {
843
843
  if (matches.length >= limit) break;
844
- for (const ev of store.readEvents(s.id)) {
844
+ for (const ev of store.readVerifiedEvents(s.id)) {
845
845
  if (matches.length >= limit) break;
846
846
  if (
847
847
  ev.type !== "user_message" &&
@@ -921,8 +921,8 @@ export function registerSessionCommand(program) {
921
921
  .action(async (id, options) => {
922
922
  let ctx = null;
923
923
  try {
924
- const jsonlId =
925
- resolveSessionId(id) || (sessionHasPersistedEvidence(id) ? id : null);
924
+ const authority = resolveSessionAuthority(id);
925
+ const jsonlId = authority?.id || null;
926
926
  let db = null;
927
927
  try {
928
928
  ctx = await bootstrap({ verbose: program.opts().verbose });
@@ -985,10 +985,11 @@ export function registerSessionCommand(program) {
985
985
  Array.isArray(title) ? title.join(" ") : title,
986
986
  ).trim();
987
987
  if (!normalized) throw new Error("A non-empty title is required");
988
- const jsonlId = resolveSessionId(id);
989
- if (!jsonlId && sessionHasPersistedEvidence(id)) {
988
+ const authority = resolveSessionAuthority(id);
989
+ const jsonlId = authority?.readable ? authority.id : null;
990
+ if (authority && !authority.readable) {
990
991
  throw new Error(
991
- `Session ${id} has canonical persistence evidence but no readable transcript`,
992
+ `Session ${authority.id} has canonical persistence evidence but no readable transcript (${authority.presence})`,
992
993
  );
993
994
  }
994
995
  let result;
@@ -2175,14 +2176,17 @@ async function mirrorSessions(ids) {
2175
2176
 
2176
2177
  const pushed = [];
2177
2178
  const errors = [];
2178
- const { readFileSync, existsSync } = await import("node:fs");
2179
2179
  for (const id of ids) {
2180
2180
  try {
2181
- if (store.isUnsafeSessionId(id)) throw new Error("unsafe session id");
2182
- const file = store.sessionPath(id);
2183
- if (!existsSync(file)) throw new Error("session not found");
2184
- const bytes = readFileSync(file, "utf-8");
2185
- pushed.push(await mirror.push(id, bytes));
2181
+ const authority = store.resolveSessionAuthority(id);
2182
+ if (!authority) throw new Error("session not found");
2183
+ if (!authority.readable) {
2184
+ throw new Error(
2185
+ `canonical session is not readable (${authority.presence})`,
2186
+ );
2187
+ }
2188
+ const bytes = store.readVerifiedTranscriptBytes(authority.id);
2189
+ pushed.push(await mirror.push(authority.id, bytes));
2186
2190
  } catch (err) {
2187
2191
  errors.push({ id, error: err.message });
2188
2192
  }
@@ -2232,7 +2236,11 @@ async function mirrorPruneSessions() {
2232
2236
  const { pruneMirror } = await import("../harness/session-mirror.js");
2233
2237
  const { mirror } = await loadConfiguredMirror();
2234
2238
  if (!mirror) return { target: null, deleted: [], kept: [] };
2235
- const keep = store.listSessionIds();
2239
+ // A damaged local generation must not cause automatic deletion of its last
2240
+ // off-box recovery copy. Only an explicit canonical tombstone is prunable.
2241
+ const keep = store
2242
+ .listSessionEvidenceIds()
2243
+ .filter((id) => store.getSessionPresence(id) !== "tombstoned");
2236
2244
  const res = await pruneMirror(mirror, { keep });
2237
2245
  return { target: mirror.target, ...res };
2238
2246
  }
@@ -1,6 +1,32 @@
1
1
  {
2
2
  "source": "CHANGELOG.md",
3
3
  "releases": [
4
+ {
5
+ "productVersion": null,
6
+ "cliVersion": "0.162.200",
7
+ "cliVersions": ["0.162.198", "0.162.200"],
8
+ "date": "2026-08-07",
9
+ "title": "",
10
+ "sections": [
11
+ {
12
+ "heading": "Fixed — cc CLI 0.162.200: release-gate isolation and carried reliability fixes",
13
+ "body": "> `chainlesschain` **0.162.198 → 0.162.200** (release candidate,\n> 2026-08-07; `0.162.199` failed before npm upload and its tag remains\n> immutable). CLI-only release metadata; `@chainlesschain/personal-data-hub`\n> remains **0.4.57** and `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **Carries the complete 0.162.199 candidate**: command lifecycle telemetry and\n alias observation policy, canonical session authority, fixed MCP package\n capsules, native update recovery, and portable reliability gates are all\n included because `0.162.199` never reached npm.\n- **Release-gate isolation**: the Agent SDK real-CLI E2E now places its\n rollback-resistant security anchor beside, rather than inside,\n `CHAINLESSCHAIN_HOME`. The fixture therefore matches the production\n fail-closed layout after redirecting `HOME` and no longer hides the `agent`\n command behind compatibility registration.\n- **Pre-release evidence**: implementation SHA `bf6924013d1c` passed the full\n [npm release dry-run](https://github.com/chainlesschain/chainlesschain/actions/runs/31189959290),\n including core packages, Agent SDK real-CLI E2E, Personal Data Hub, Web Panel,\n the complete CLI suite, and credential-free npm package validation. The final\n `0.162.200` version commit must pass the exact-SHA CLI CI and CLI Strict\n Sandbox matrices before tag `v-npm-0-162-200` is created."
14
+ }
15
+ ]
16
+ },
17
+ {
18
+ "productVersion": null,
19
+ "cliVersion": "0.162.199",
20
+ "cliVersions": ["0.162.198", "0.162.199"],
21
+ "date": "2026-08-07",
22
+ "title": "",
23
+ "sections": [
24
+ {
25
+ "heading": "Fixed — cc CLI 0.162.199: session authority, MCP capsules, and recovery reliability",
26
+ "body": "> `chainlesschain` **0.162.198 → 0.162.199** (not published, 2026-08-07;\n> the release workflow failed before package creation or npm upload and tag\n> `v-npm-0-162-199` remains immutable). CLI-only release metadata;\n> `@chainlesschain/personal-data-hub` remains **0.4.57** and\n> `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **Command lifecycle telemetry**: manifest-driven lifecycle metadata now\n records legacy and replacement routes, aggregates usage without changing\n aliases automatically, and keeps compatibility entries until their stated\n observation window and release-cycle requirements are satisfied.\n- **Canonical session authority**: host leases, transcript witnesses,\n anti-rollback anchors, compare-and-swap persistence, bounded cleanup, and\n descendant retirement harden concurrent resume and long-running session\n behavior across the covered CLI, background, and remote-host paths.\n- **Fixed MCP package execution**: approved JavaScript launchers are resolved\n to exact npm versions and complete transitive closures, then bundled into a\n guarded, content-addressed Node capsule. Runtime execution no longer depends\n on a live dynamic package launcher or mutable `node_modules` entrypoint.\n- **Native update recovery**: Windows and POSIX installer/OTA generations can\n recover interrupted activation, rollback, and rescue state while preserving\n exact lineage, owner-private locks, and Windows path/handle identity under\n Node 22.12 device projection.\n- **Portable reliability gates**: disk/pipe failure injection, process-tree\n cleanup, resource accounting, session stress, and platform path aliases are\n covered by the release matrices. Real hardware, terminal, SSH, and extended\n soak observations remain ongoing evidence rather than compatibility claims.\n- **Candidate evidence**: implementation SHA `7e7ce9182746` passed\n [CLI CI](https://github.com/chainlesschain/chainlesschain/actions/runs/31181229942),\n [CLI Strict Sandbox](https://github.com/chainlesschain/chainlesschain/actions/runs/31181328955),\n [CLI Background Interaction E2E](https://github.com/chainlesschain/chainlesschain/actions/runs/31181258842),\n and [CLI Session Host Consistency](https://github.com/chainlesschain/chainlesschain/actions/runs/31181258424)\n on Ubuntu, Windows, and macOS. Final SHA `23bd2e6e5758` also passed the\n exact-SHA release gates, but the\n [dedicated npm release](https://github.com/chainlesschain/chainlesschain/actions/runs/31187599603)\n stopped before package creation because its Agent SDK fixture placed the\n security anchor inside the redirected CLI home."
27
+ }
28
+ ]
29
+ },
4
30
  {
5
31
  "productVersion": null,
6
32
  "cliVersion": "0.162.198",
@@ -10,7 +36,7 @@
10
36
  "sections": [
11
37
  {
12
38
  "heading": "Fixed — cc CLI 0.162.198: interactive streaming and release portability",
13
- "body": "> `chainlesschain` **0.162.197 → 0.162.198** (release candidate, 2026-08-06).\n> CLI-only release metadata; `@chainlesschain/personal-data-hub` remains\n> **0.4.57** and `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **Interactive output backpressure**: REPL, headless streaming, provider\n pacing, and TTY writers now wait for saturated output streams to drain and\n clean up pending listeners across completion, interruption, and session\n transitions instead of allowing unbounded interactive writes.\n- **Canonical session controls**: the CLI-owned session projection and bounded\n reply routes now support the completed VS Code and JetBrains workbench and\n rewind journeys while preserving CLI authority over persisted mutations.\n- **Portable release gates**: Windows path-alias fixtures, state-path mocks,\n Skill metadata fixtures, POSIX executable-bit setup, and the deprecated\n agent-core shim are aligned with the three-platform CLI CI and Strict\n Sandbox contracts.\n- **Release readback hardening**: public npm verification remains independent\n of undeclared runtime dependencies, retries bounded registry propagation,\n and binds provenance and registry bytes to the immutable publish artifact.\n- **Candidate evidence**: merged implementation SHA `0b7a5471e7a9` passed\n [CLI CI](https://github.com/chainlesschain/chainlesschain/actions/runs/31071519048)\n and [CLI Strict Sandbox](https://github.com/chainlesschain/chainlesschain/actions/runs/31071522429)\n on Ubuntu, Windows, and macOS. The final `0.162.198` version commit must pass\n both gates again on its own exact SHA before tag `v-npm-0-162-198` is\n created; local, older-SHA, and partial results remain supplementary only."
39
+ "body": "> `chainlesschain` **0.162.197 → 0.162.198** (published, 2026-08-06).\n> CLI-only release metadata; `@chainlesschain/personal-data-hub` remains\n> **0.4.57** and `@chainlesschain/agent-sdk` remains **0.1.7**.\n\n- **Interactive output backpressure**: REPL, headless streaming, provider\n pacing, and TTY writers now wait for saturated output streams to drain and\n clean up pending listeners across completion, interruption, and session\n transitions instead of allowing unbounded interactive writes.\n- **Canonical session controls**: the CLI-owned session projection and bounded\n reply routes now support the completed VS Code and JetBrains workbench and\n rewind journeys while preserving CLI authority over persisted mutations.\n- **Portable release gates**: Windows path-alias fixtures, state-path mocks,\n Skill metadata fixtures, POSIX executable-bit setup, and the deprecated\n agent-core shim are aligned with the three-platform CLI CI and Strict\n Sandbox contracts.\n- **Release readback hardening**: public npm verification remains independent\n of undeclared runtime dependencies, retries bounded registry propagation,\n and binds provenance and registry bytes to the immutable publish artifact.\n- **Exact release evidence**: tag `v-npm-0-162-198` points to final release SHA\n [`3c0f62fa17242cfa3123ab502a9bf5d1cbed8481`](https://github.com/chainlesschain/chainlesschain/commit/3c0f62fa17242cfa3123ab502a9bf5d1cbed8481).\n The same SHA passed [CLI CI](https://github.com/chainlesschain/chainlesschain/actions/runs/31078499968)\n and [CLI Strict Sandbox](https://github.com/chainlesschain/chainlesschain/actions/runs/31078499270)\n on Ubuntu, Windows, and macOS. The\n [dedicated npm release](https://github.com/chainlesschain/chainlesschain/actions/runs/31081337370)\n completed the exact-SHA gate, immutable tarball, CycloneDX SBOM, Trusted\n Publishing, signed provenance, registry readback, and npmmirror sync; the\n [independent public readback](https://github.com/chainlesschain/chainlesschain/actions/runs/31082366544)\n re-downloaded the package and matched registry bytes and publishing identity."
14
40
  }
15
41
  ]
16
42
  },
@@ -6,6 +6,7 @@ import {
6
6
  } from "../../runtime/runtime-events.js";
7
7
  import { createSessionRecord } from "../../runtime/contracts/session-record.js";
8
8
  import { loadSideEffectLedger } from "../../lib/side-effect-ledger-store.js";
9
+ import { acquireSessionHostLease } from "../../lib/session-host-lease.js";
9
10
  import { reconcileSideEffects } from "../../lib/side-effect-ledger.js";
10
11
  import {
11
12
  formatMcpLedgerRecoveryNotice,
@@ -532,11 +533,20 @@ async function ensureSessionHandler(server, ws, session) {
532
533
  });
533
534
  } else {
534
535
  const { WSAgentHandler } = await import("./ws-agent-handler.js");
535
- handler = new WSAgentHandler({
536
- session,
537
- interaction: session.interaction,
538
- db: server.sessionManager.db,
536
+ const sessionHostLease = acquireSessionHostLease(session.id, {
537
+ hostKind: "ws",
539
538
  });
539
+ try {
540
+ handler = new WSAgentHandler({
541
+ session,
542
+ interaction: session.interaction,
543
+ db: server.sessionManager.db,
544
+ sessionHostLease,
545
+ });
546
+ } catch (error) {
547
+ sessionHostLease.release();
548
+ throw error;
549
+ }
540
550
  }
541
551
 
542
552
  server.sessionHandlers.set(session.id, handler);
@@ -79,6 +79,7 @@ export class WSAgentHandler {
79
79
  approvalGate,
80
80
  agentLoop: runAgentLoop,
81
81
  canonicalSessionStore,
82
+ sessionHostLease = null,
82
83
  }) {
83
84
  this.session = session;
84
85
  this.interaction = interaction;
@@ -86,6 +87,25 @@ export class WSAgentHandler {
86
87
  this._processing = false;
87
88
  this._abortController = null;
88
89
  this._activeRequestId = null;
90
+ this._sessionHostLease = sessionHostLease;
91
+ this._onSessionHostLeaseAbort = null;
92
+ if (sessionHostLease?.signal) {
93
+ this._onSessionHostLeaseAbort = () => {
94
+ const reason =
95
+ sessionHostLease.signal.reason ||
96
+ createAbortError("Session host lease was lost");
97
+ if (this._abortController && !this._abortController.signal.aborted) {
98
+ this._abortController.abort(reason);
99
+ }
100
+ this.interaction?.rejectAllPending?.(reason);
101
+ };
102
+ sessionHostLease.signal.addEventListener(
103
+ "abort",
104
+ this._onSessionHostLeaseAbort,
105
+ { once: true },
106
+ );
107
+ if (sessionHostLease.signal.aborted) this._onSessionHostLeaseAbort();
108
+ }
89
109
  // P0-2: monotonic sequence for crash-safe side-effect ledger op ids. The
90
110
  // session id + a per-op nonce keep ids unique across turns and processes.
91
111
  this._sideEffectSeq = 0;
@@ -486,6 +506,7 @@ export class WSAgentHandler {
486
506
 
487
507
  try {
488
508
  const { session } = this;
509
+ this._sessionHostLease?.assert?.();
489
510
 
490
511
  if (session.canonicalJsonlSession === true) {
491
512
  canonicalTurn = this._claimCanonicalTurn(userMessage, requestId);
@@ -648,6 +669,7 @@ export class WSAgentHandler {
648
669
  })
649
670
  .start(opId);
650
671
  persistSideEffectLedger(session.id, sideEffectLedger);
672
+ this._sessionHostLease?.assert?.();
651
673
  }
652
674
  }
653
675
  break;
@@ -884,6 +906,15 @@ export class WSAgentHandler {
884
906
  reason: "session_closed",
885
907
  });
886
908
  }
909
+ if (this._sessionHostLease?.signal && this._onSessionHostLeaseAbort) {
910
+ this._sessionHostLease.signal.removeEventListener(
911
+ "abort",
912
+ this._onSessionHostLeaseAbort,
913
+ );
914
+ }
915
+ this._onSessionHostLeaseAbort = null;
916
+ this._sessionHostLease?.release?.();
917
+ this._sessionHostLease = null;
887
918
  }
888
919
 
889
920
  /**