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
@@ -34,7 +34,10 @@ import {
34
34
  materializeApprovedMcpStdioInvocation,
35
35
  renewMcpStdioExecutionAuthority,
36
36
  } from "../lib/mcp-stdio-execution-authority.js";
37
- import { prepareMcpStdioExecutableIdentity } from "../lib/mcp-stdio-executable-identity.js";
37
+ import {
38
+ MCP_STDIO_CAPSULE_CODE_SNAPSHOT_BOUNDARY,
39
+ prepareMcpStdioExecutableIdentity,
40
+ } from "../lib/mcp-stdio-executable-identity.js";
38
41
 
39
42
  /**
40
43
  * Injectable dependencies — overridable from tests.
@@ -1856,6 +1859,10 @@ export class MCPClient extends EventEmitter {
1856
1859
  let pluginWorkspaceRoot = null;
1857
1860
  let stdioExecutableIdentity = null;
1858
1861
  let stdioExecutableIdentityAuthority = null;
1862
+ let stdioExecutableEnvironment = null;
1863
+ let stdioExecutableWorkingDirectory = null;
1864
+ let stdioExecutableIdentityDigest = null;
1865
+ let stdioCapsuleSandboxExecutionContract = null;
1859
1866
  let runtimeConfig = sourceConfig;
1860
1867
  if (transportKind === "stdio") {
1861
1868
  const isPlugin = sourceConfig.origin === "plugin:mcp";
@@ -1884,7 +1891,7 @@ export class MCPClient extends EventEmitter {
1884
1891
  config: sourceConfig,
1885
1892
  approval: stdioExecutionApproval,
1886
1893
  cwd: pluginWorkspaceRoot || process.cwd(),
1887
- env: process.env,
1894
+ env: { ...process.env, ...this._agentIdentityEnv() },
1888
1895
  });
1889
1896
  runtimeConfig = {
1890
1897
  ...sourceConfig,
@@ -1893,6 +1900,11 @@ export class MCPClient extends EventEmitter {
1893
1900
  };
1894
1901
  stdioExecutableIdentity = prepared.identity;
1895
1902
  stdioExecutableIdentityAuthority = prepared.authority;
1903
+ stdioExecutableEnvironment = prepared.env;
1904
+ stdioExecutableWorkingDirectory = prepared.workingDirectory;
1905
+ stdioExecutableIdentityDigest = prepared.identityDigest;
1906
+ stdioCapsuleSandboxExecutionContract =
1907
+ prepared.sandboxExecutionContract || null;
1896
1908
  }
1897
1909
  const connectionHeaders = await this._connectionHeaders(
1898
1910
  name,
@@ -2292,11 +2304,14 @@ export class MCPClient extends EventEmitter {
2292
2304
  }
2293
2305
  const isPlugin = config.origin === "plugin:mcp";
2294
2306
  const spawnOptions = {
2295
- cwd: pluginWorkspaceRoot || process.cwd(),
2307
+ cwd:
2308
+ stdioExecutableWorkingDirectory ||
2309
+ pluginWorkspaceRoot ||
2310
+ process.cwd(),
2296
2311
  stdio: ["pipe", "pipe", "pipe"],
2297
2312
  // process.env < agent identity (CLAUDECODE / session id) < the
2298
2313
  // server's own config.env, so an explicit per-server override wins.
2299
- env: {
2314
+ env: stdioExecutableEnvironment || {
2300
2315
  ...process.env,
2301
2316
  ...this._agentIdentityEnv(),
2302
2317
  ...(config.env || {}),
@@ -2310,8 +2325,16 @@ export class MCPClient extends EventEmitter {
2310
2325
  // Broker's Job Object boundary so an unexpectedly exiting MCP root
2311
2326
  // cannot orphan grandchildren before taskkill can enumerate them.
2312
2327
  detached: process.platform !== "win32",
2313
- ...(process.platform === "win32"
2314
- ? { requiredBoundaries: ["process-tree"] }
2328
+ ...(process.platform === "win32" ||
2329
+ stdioCapsuleSandboxExecutionContract
2330
+ ? {
2331
+ requiredBoundaries: [
2332
+ ...(process.platform === "win32" ? ["process-tree"] : []),
2333
+ ...(stdioCapsuleSandboxExecutionContract
2334
+ ? [MCP_STDIO_CAPSULE_CODE_SNAPSHOT_BOUNDARY]
2335
+ : []),
2336
+ ],
2337
+ }
2315
2338
  : {}),
2316
2339
  pluginId: config.pluginId,
2317
2340
  pluginVersion: config.pluginVersion,
@@ -2320,19 +2343,29 @@ export class MCPClient extends EventEmitter {
2320
2343
  ? { sandboxPolicy: config.sandboxPolicy }
2321
2344
  : {}),
2322
2345
  mcpStdioExecutableIdentityAuthority: stdioExecutableIdentityAuthority,
2346
+ mcpStdioExecutableIdentityDigest: stdioExecutableIdentityDigest,
2323
2347
  };
2324
2348
  const sandboxExecutionContract =
2325
- !isPlugin || pluginWorkspaceRoot
2349
+ stdioCapsuleSandboxExecutionContract ||
2350
+ (!isPlugin || pluginWorkspaceRoot
2326
2351
  ? executionBroker.issueLinuxWorkspaceSandboxExecutionContract(
2327
2352
  config.command,
2328
2353
  config.args || [],
2329
2354
  { ...spawnOptions, detached: false },
2330
- pluginWorkspaceRoot || process.cwd(),
2355
+ stdioExecutableWorkingDirectory ||
2356
+ pluginWorkspaceRoot ||
2357
+ process.cwd(),
2331
2358
  )
2332
- : null;
2359
+ : null);
2360
+ const capsuleUsesPosixProcessGroup =
2361
+ Boolean(stdioCapsuleSandboxExecutionContract) &&
2362
+ process.platform !== "win32";
2333
2363
  const launchOptions = {
2334
2364
  ...spawnOptions,
2335
- detached: sandboxExecutionContract ? false : spawnOptions.detached,
2365
+ detached:
2366
+ sandboxExecutionContract && !capsuleUsesPosixProcessGroup
2367
+ ? false
2368
+ : spawnOptions.detached,
2336
2369
  ...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
2337
2370
  };
2338
2371
  const proc = _deps.spawn(config.command, config.args || [], {
@@ -2341,7 +2374,7 @@ export class MCPClient extends EventEmitter {
2341
2374
 
2342
2375
  entry.process = proc;
2343
2376
  entry._stdioTreeMode =
2344
- sandboxExecutionContract ||
2377
+ (sandboxExecutionContract && !capsuleUsesPosixProcessGroup) ||
2345
2378
  (process.platform === "win32" && proc?.sandboxReady?.then)
2346
2379
  ? "sandbox"
2347
2380
  : process.platform === "win32"
@@ -21,8 +21,8 @@ import { existsSync, readdirSync, statSync } from "node:fs";
21
21
  import { join, basename } from "node:path";
22
22
  import { createRequire } from "node:module";
23
23
  import { getHomeDir } from "../lib/paths.js";
24
- import { iterateFileLinesSync } from "../lib/file-lines.js";
25
24
  import { ensurePrivateDirectory, ensurePrivateFile } from "../lib/secure-fs.js";
25
+ import { readVerifiedProjection } from "./jsonl-session-store.js";
26
26
 
27
27
  const requireCjs = createRequire(import.meta.url);
28
28
 
@@ -98,84 +98,74 @@ function toIsoSafe(value) {
98
98
  return Number.isNaN(date.getTime()) ? "" : date.toISOString();
99
99
  }
100
100
 
101
- function summarizeSessionFile(id, filePath) {
102
- let startEvent = null;
103
- let lastEvent = null;
104
- let renamedTitle = null;
105
- let messageCount = 0;
106
- let eventCount = 0;
107
- let chainHash = "";
108
- const parts = [];
109
- let used = 0;
110
- for (const { line } of iterateFileLinesSync(filePath)) {
111
- let event;
112
- try {
113
- event = JSON.parse(line);
114
- } catch {
115
- continue;
116
- }
117
- eventCount += 1;
118
- lastEvent = event;
119
- if (!startEvent && event.type === "session_start") startEvent = event;
120
- if (event.type === "session_rename" && event.data?.title) {
121
- renamedTitle = String(event.data.title);
122
- }
123
- if (event.type === "user_message" || event.type === "assistant_message") {
124
- messageCount += 1;
125
- if (used < CONTENT_CAP) {
126
- const content = event.data?.content;
127
- const text =
128
- typeof content === "string"
129
- ? content
130
- : content == null
131
- ? ""
132
- : JSON.stringify(content);
133
- if (text) {
134
- const bounded = text.slice(0, CONTENT_CAP - used);
135
- parts.push(bounded);
136
- used += bounded.length;
101
+ function summarizeVerifiedSession(id) {
102
+ return readVerifiedProjection(id, () => {
103
+ let startEvent = null;
104
+ let lastEvent = null;
105
+ let renamedTitle = null;
106
+ let messageCount = 0;
107
+ let eventCount = 0;
108
+ let chainHash = "";
109
+ const parts = [];
110
+ let used = 0;
111
+ const acceptContent = (content) => {
112
+ if (used >= CONTENT_CAP) return;
113
+ const text =
114
+ typeof content === "string"
115
+ ? content
116
+ : content == null
117
+ ? ""
118
+ : JSON.stringify(content);
119
+ if (!text) return;
120
+ const bounded = text.slice(0, CONTENT_CAP - used);
121
+ parts.push(bounded);
122
+ used += bounded.length;
123
+ };
124
+ return {
125
+ accept(event) {
126
+ eventCount += 1;
127
+ lastEvent = event;
128
+ if (!startEvent && event.type === "session_start") startEvent = event;
129
+ if (event.type === "session_rename" && event.data?.title) {
130
+ renamedTitle = String(event.data.title);
137
131
  }
138
- }
139
- } else if (
140
- event.type === "ws_turn" &&
141
- event.data?.schemaVersion === 1 &&
142
- event.data?.outcome === "completed" &&
143
- event.data?.user?.role === "user" &&
144
- event.data?.assistant?.role === "assistant"
145
- ) {
146
- messageCount += 2;
147
- for (const message of [event.data?.user, event.data?.assistant]) {
148
- if (used >= CONTENT_CAP) break;
149
- const content = message?.content;
150
- const text =
151
- typeof content === "string"
152
- ? content
153
- : content == null
154
- ? ""
155
- : JSON.stringify(content);
156
- if (text) {
157
- const bounded = text.slice(0, CONTENT_CAP - used);
158
- parts.push(bounded);
159
- used += bounded.length;
132
+ if (
133
+ event.type === "user_message" ||
134
+ event.type === "assistant_message"
135
+ ) {
136
+ messageCount += 1;
137
+ acceptContent(event.data?.content);
138
+ } else if (
139
+ event.type === "ws_turn" &&
140
+ event.data?.schemaVersion === 1 &&
141
+ event.data?.outcome === "completed" &&
142
+ event.data?.user?.role === "user" &&
143
+ event.data?.assistant?.role === "assistant"
144
+ ) {
145
+ messageCount += 2;
146
+ acceptContent(event.data.user.content);
147
+ acceptContent(event.data.assistant.content);
160
148
  }
161
- }
162
- }
163
- if (typeof event.hash === "string") chainHash = event.hash;
164
- }
165
- if (!lastEvent) return null;
166
- return {
167
- id,
168
- title: renamedTitle || startEvent?.data?.title || "Untitled",
169
- provider: startEvent?.data?.provider || "",
170
- model: startEvent?.data?.model || "",
171
- message_count: messageCount,
172
- event_count: eventCount,
173
- created_at: toIsoSafe(startEvent?.timestamp),
174
- updated_at: toIsoSafe(lastEvent?.timestamp),
175
- last_ts: lastEvent?.timestamp || 0,
176
- content: parts.join("\n").slice(0, CONTENT_CAP),
177
- chain_hash: chainHash,
178
- };
149
+ if (typeof event.hash === "string") chainHash = event.hash;
150
+ },
151
+ finish() {
152
+ if (!lastEvent) return null;
153
+ return {
154
+ id,
155
+ title: renamedTitle || startEvent?.data?.title || "Untitled",
156
+ provider: startEvent?.data?.provider || "",
157
+ model: startEvent?.data?.model || "",
158
+ message_count: messageCount,
159
+ event_count: eventCount,
160
+ created_at: toIsoSafe(startEvent?.timestamp),
161
+ updated_at: toIsoSafe(lastEvent?.timestamp),
162
+ last_ts: lastEvent?.timestamp || 0,
163
+ content: parts.join("\n").slice(0, CONTENT_CAP),
164
+ chain_hash: chainHash,
165
+ };
166
+ },
167
+ };
168
+ });
179
169
  }
180
170
 
181
171
  const UPSERT_SESSION = `
@@ -195,7 +185,7 @@ ON CONFLICT(id) DO UPDATE SET
195
185
  export function indexOneSession(db, id, { mtimeMs = 0, sizeBytes = 0 } = {}) {
196
186
  const filePath = join(sessionsDir(), `${id}.jsonl`);
197
187
  if (!existsSync(filePath)) return false;
198
- const s = summarizeSessionFile(id, filePath);
188
+ const s = summarizeVerifiedSession(id);
199
189
  if (!s) return false;
200
190
  db.prepare(UPSERT_SESSION).run({
201
191
  id: s.id,
@@ -228,6 +218,7 @@ export function syncIndex(db, { force = false } = {}) {
228
218
  let scanned = 0;
229
219
  let updated = 0;
230
220
  let removed = 0;
221
+ let rejected = 0;
231
222
  const seen = new Set();
232
223
 
233
224
  if (existsSync(dir)) {
@@ -251,7 +242,16 @@ export function syncIndex(db, { force = false } = {}) {
251
242
  ) {
252
243
  continue; // unchanged
253
244
  }
254
- if (indexOneSession(db, id, { mtimeMs, sizeBytes: size })) updated++;
245
+ try {
246
+ if (indexOneSession(db, id, { mtimeMs, sizeBytes: size })) updated++;
247
+ } catch {
248
+ // The index is disposable. A damaged canonical source invalidates any
249
+ // older cached content immediately and is reported without exposing
250
+ // transcript text or local paths.
251
+ db.prepare("DELETE FROM sessions WHERE id=?").run(id);
252
+ db.prepare("DELETE FROM session_content WHERE id=?").run(id);
253
+ rejected++;
254
+ }
255
255
  }
256
256
  });
257
257
  const entries = [];
@@ -278,7 +278,7 @@ export function syncIndex(db, { force = false } = {}) {
278
278
  }
279
279
 
280
280
  const total = db.prepare("SELECT COUNT(*) c FROM sessions").get().c;
281
- return { scanned, updated, removed, total };
281
+ return { scanned, updated, removed, rejected, total };
282
282
  }
283
283
 
284
284
  const LIST_COLUMNS =
@@ -21,6 +21,11 @@ import { ensurePrivateFile } from "../lib/secure-fs.js";
21
21
  export const SESSION_INDEX_SCHEMA = 2;
22
22
  export const SESSION_INDEX_FILE = ".sessions-index-v2.ndjson";
23
23
  export const SESSION_TOMBSTONE_MARKER_SUFFIX = ".tombstone";
24
+ export const SESSION_TOMBSTONE_MARKER_SCHEMA =
25
+ "chainlesschain.session-tombstone/v1";
26
+ export const SESSION_GENERATION_AUTHORITY_FIELD = "_sessionGeneration";
27
+ export const SESSION_GENERATION_AUTHORITY_SCHEMA =
28
+ "chainlesschain.session-generation-authority/v1";
24
29
 
25
30
  // Used only by an opted-in child in the independent session-scale crash gate.
26
31
  // Keeping the injection immediately around the production sidecar/journal
@@ -59,10 +64,67 @@ export function emptySessionMeta(sessionId) {
59
64
  created_at_ms: 0,
60
65
  updated_at_ms: 0,
61
66
  last_hash: null,
67
+ transcript: null,
68
+ generation: null,
69
+ deleted_at_ms: null,
62
70
  deleted: false,
63
71
  };
64
72
  }
65
73
 
74
+ export function normalizeSessionGenerationAuthority(value) {
75
+ if (
76
+ !value ||
77
+ typeof value !== "object" ||
78
+ Array.isArray(value) ||
79
+ value.schema !== SESSION_GENERATION_AUTHORITY_SCHEMA ||
80
+ typeof value.sessionId !== "string" ||
81
+ value.sessionId.length === 0 ||
82
+ typeof value.generationId !== "string" ||
83
+ !/^generation-[0-9a-f-]{32,36}$/.test(value.generationId) ||
84
+ !Number.isSafeInteger(value.ordinal) ||
85
+ value.ordinal < 1
86
+ ) {
87
+ return null;
88
+ }
89
+ let predecessor = null;
90
+ if (value.predecessor !== null) {
91
+ const previous = value.predecessor;
92
+ if (
93
+ !previous ||
94
+ typeof previous !== "object" ||
95
+ Array.isArray(previous) ||
96
+ !["tombstone", "legacy-tombstone"].includes(previous.kind) ||
97
+ (previous.generationId !== null &&
98
+ (typeof previous.generationId !== "string" ||
99
+ !/^generation-[0-9a-f-]{32,36}$/.test(previous.generationId))) ||
100
+ (previous.headHash !== null &&
101
+ (typeof previous.headHash !== "string" ||
102
+ !/^[0-9a-f]{64}$/.test(previous.headHash))) ||
103
+ !Number.isSafeInteger(previous.eventCount) ||
104
+ previous.eventCount < 0 ||
105
+ (previous.tombstonedAtMs !== null &&
106
+ (!Number.isSafeInteger(previous.tombstonedAtMs) ||
107
+ previous.tombstonedAtMs < 0))
108
+ ) {
109
+ return null;
110
+ }
111
+ predecessor = {
112
+ kind: previous.kind,
113
+ generationId: previous.generationId,
114
+ headHash: previous.headHash,
115
+ eventCount: previous.eventCount,
116
+ tombstonedAtMs: previous.tombstonedAtMs,
117
+ };
118
+ }
119
+ return {
120
+ schema: SESSION_GENERATION_AUTHORITY_SCHEMA,
121
+ sessionId: value.sessionId,
122
+ generationId: value.generationId,
123
+ ordinal: value.ordinal,
124
+ predecessor,
125
+ };
126
+ }
127
+
66
128
  export function readSessionMeta(dir, sessionId) {
67
129
  const filePath = sessionMetaPath(dir, sessionId);
68
130
  if (!existsSync(filePath)) return null;
@@ -108,6 +170,11 @@ export function applyEventToSessionMeta(meta, event, lastHash) {
108
170
  ) {
109
171
  next.message_count = Math.max(0, Number(next.message_count) || 0) + 2;
110
172
  }
173
+ const generation = normalizeSessionGenerationAuthority(
174
+ event?.data?.[SESSION_GENERATION_AUTHORITY_FIELD],
175
+ );
176
+ if (generation?.sessionId === next.id) next.generation = generation;
177
+ next.deleted_at_ms = null;
111
178
  next.last_hash = typeof lastHash === "string" ? lastHash : null;
112
179
  return next;
113
180
  }
@@ -123,7 +190,26 @@ function writeMetaSnapshot(dir, meta) {
123
190
  // commits, so crashes can cause an extra candidate read but never hide a
124
191
  // successfully committed tombstone.
125
192
  if (meta.deleted === true) {
126
- writeFileSync(tombstoneMarker, "", { encoding: "utf8", mode: 0o600 });
193
+ const generation = normalizeSessionGenerationAuthority(meta.generation);
194
+ const marker = {
195
+ schema: SESSION_TOMBSTONE_MARKER_SCHEMA,
196
+ id: meta.id,
197
+ generation: generation?.sessionId === meta.id ? generation : null,
198
+ last_hash:
199
+ typeof meta.last_hash === "string" &&
200
+ /^[0-9a-f]{64}$/.test(meta.last_hash)
201
+ ? meta.last_hash
202
+ : null,
203
+ event_count: Math.max(0, Number(meta.event_count) || 0),
204
+ deleted_at_ms: Math.max(
205
+ 0,
206
+ Number(meta.deleted_at_ms || meta.updated_at_ms) || 0,
207
+ ),
208
+ };
209
+ writeFileSync(tombstoneMarker, `${JSON.stringify(marker)}\n`, {
210
+ encoding: "utf8",
211
+ mode: 0o600,
212
+ });
127
213
  ensurePrivateFile(tombstoneMarker);
128
214
  }
129
215
  // The owning transcript lock serializes this derived snapshot. It need not
@@ -137,6 +223,39 @@ function writeMetaSnapshot(dir, meta) {
137
223
  if (meta.deleted !== true) rmSync(tombstoneMarker, { force: true });
138
224
  }
139
225
 
226
+ /**
227
+ * Read the durable namespace marker. Legacy empty/invalid markers still count
228
+ * as deletion evidence, but deliberately expose no predecessor authority.
229
+ */
230
+ export function readSessionTombstoneMarker(dir, sessionId) {
231
+ const filePath = sessionTombstoneMarkerPath(dir, sessionId);
232
+ if (!existsSync(filePath)) return null;
233
+ try {
234
+ const value = JSON.parse(readFileSync(filePath, "utf8"));
235
+ if (
236
+ value?.schema !== SESSION_TOMBSTONE_MARKER_SCHEMA ||
237
+ value?.id !== sessionId
238
+ ) {
239
+ return { id: sessionId, legacy: true };
240
+ }
241
+ const generation = normalizeSessionGenerationAuthority(value.generation);
242
+ return {
243
+ schema: SESSION_TOMBSTONE_MARKER_SCHEMA,
244
+ id: sessionId,
245
+ generation: generation?.sessionId === sessionId ? generation : null,
246
+ last_hash:
247
+ typeof value.last_hash === "string" &&
248
+ /^[0-9a-f]{64}$/.test(value.last_hash)
249
+ ? value.last_hash
250
+ : null,
251
+ event_count: Math.max(0, Number(value.event_count) || 0),
252
+ deleted_at_ms: Math.max(0, Number(value.deleted_at_ms) || 0),
253
+ };
254
+ } catch {
255
+ return { id: sessionId, legacy: true };
256
+ }
257
+ }
258
+
140
259
  function appendActivity(dir, meta) {
141
260
  const filePath = sessionIndexPath(dir);
142
261
  // One compact line is emitted through one O_APPEND write. The journal is a
@@ -159,7 +278,7 @@ export function recordSessionEvent(
159
278
  sessionId,
160
279
  event,
161
280
  lastHash,
162
- { resetGeneration = false } = {},
281
+ { resetGeneration = false, transcriptState = null } = {},
163
282
  ) {
164
283
  const existing = readSessionMeta(dir, sessionId);
165
284
  // Only the transcript writer may authorize a new generation after checking
@@ -170,6 +289,30 @@ export function recordSessionEvent(
170
289
  : existing || emptySessionMeta(sessionId);
171
290
  current.id = sessionId;
172
291
  const next = applyEventToSessionMeta(current, event, lastHash);
292
+ next.transcript = transcriptState
293
+ ? {
294
+ dev: String(transcriptState.dev),
295
+ ino: String(transcriptState.ino),
296
+ size: Number(transcriptState.size),
297
+ mtimeMs: Number(transcriptState.mtimeMs),
298
+ ctimeMs: Number(transcriptState.ctimeMs),
299
+ ...(transcriptState.devExact != null
300
+ ? { devExact: String(transcriptState.devExact) }
301
+ : {}),
302
+ ...(transcriptState.inoExact != null
303
+ ? { inoExact: String(transcriptState.inoExact) }
304
+ : {}),
305
+ ...(transcriptState.sizeExact != null
306
+ ? { sizeExact: String(transcriptState.sizeExact) }
307
+ : {}),
308
+ ...(transcriptState.mtimeNs != null
309
+ ? { mtimeNs: String(transcriptState.mtimeNs) }
310
+ : {}),
311
+ ...(transcriptState.ctimeNs != null
312
+ ? { ctimeNs: String(transcriptState.ctimeNs) }
313
+ : {}),
314
+ }
315
+ : null;
173
316
  writeMetaSnapshot(dir, next);
174
317
  runSessionScaleFaultHook("afterMetaSnapshot", {
175
318
  dir,
@@ -201,7 +344,9 @@ export function recordSessionDeleted(dir, sessionId, timestamp = Date.now()) {
201
344
  const tombstone = {
202
345
  ...current,
203
346
  updated_at_ms: timestamp,
347
+ deleted_at_ms: timestamp,
204
348
  deleted: true,
349
+ transcript: null,
205
350
  };
206
351
  writeMetaSnapshot(dir, tombstone);
207
352
  appendActivity(dir, tombstone);
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { createHash } from "node:crypto";
11
11
  import {
12
- appendEvent as storeAppendEvent,
12
+ appendAuthorityEvent as storeAppendAuthorityEvent,
13
13
  readEvents as storeReadEvents,
14
14
  findLatestEvent as storeFindLatestEvent,
15
15
  } from "../harness/jsonl-session-store.js";
@@ -26,7 +26,7 @@ export const MAX_BACKGROUND_INTERACTION_RECORDS = 256;
26
26
  const TERMINAL_STATUSES = new Set(["resolved", "rejected", "cancelled"]);
27
27
 
28
28
  export const _deps = {
29
- appendEvent: storeAppendEvent,
29
+ appendEvent: storeAppendAuthorityEvent,
30
30
  readEvents: storeReadEvents,
31
31
  findLatestEvent: storeFindLatestEvent,
32
32
  };