chainlesschain 0.163.2 → 0.163.4

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 (222) hide show
  1. package/package.json +3 -2
  2. package/scripts/command-lifecycle-report.mjs +330 -38
  3. package/src/assets/web-panel/assets/{AIOps-DnGsmsqJ.js → AIOps-DB5X7qqV.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CrO6fcQ7.js → ActionButton-DxHRtKLk.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-DsBdOaP2.js → Analytics-DIH5QrxT.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-DmQslKUB.js → AppLayout-uu0oxVz7.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-BvyrT_QQ.js → Artifacts-BNSMiW9Y.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-prndoLiC.js → Audit-DcAzB4_x.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-DOTFyA55.js → BackgroundAgents-ClSsvjIc.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-9zOnPp_8.js → Backup-BMciY0js.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-C4PC6sAG.js → BaseInput-Hn3b57Sh.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-BBAF-W9v.js → Chat-CoSlC53V.js} +6 -6
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CWhvvloO.js → ChatBubbleRenderer-CFevJ3So.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-BI9iculd.js → Checkbox-B4L4Eu4w.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-3DP9BCKb.js → Codegen-C77FgRxF.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-df-2TnJX.js → Col-BrLtJLH3.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-CHs8gG_A.js → Community-Be7pXXhA.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-CDfF6q7V.js → Compact-DuGPecjo.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-CthrDnO7.js → Compliance-CzS66mjP.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-HjIqsWJw.js → Cowork-CEhjCoyK.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-BKc196fb.js → Cron-D7ir8Vja.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-CJnjdc8W.js → Crosschain-BcXmuLxf.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-BHUy-8Q2.js → DID-Cto1dtBy.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-QDB7sKeY.js → Dashboard-B7KjgwOX.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-DStcVK11.js → Dropdown-COMqxijg.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-BwSUskMJ.js → EmailListRenderer-BZrya-nf.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DgF_kurT.js → FamilyGuardDashboard-AmVeMq0J.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-k8wvv-wN.js → Federation-kZU8c-27.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-C11qoq2r.js → FormItemContext-sOV22v2-.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-BIIpr9kg.js → GenericCardRenderer-BUuLtGCz.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-BlA1exTe.js → Git-K-ZxsLsH.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-CYa1ZYM4.js → Governance-D3OEnawI.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-6_kKVIt6.js → Inference-Bll0gRmP.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-CB4AwxYy.js → KnowledgeGraph-DBXwjr53.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-xf7nHFAe.js → Logs-CEzPwEfP.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-Bf3DEqP6.js → MarkdownRenderer-CLmCbHx6.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-aPg8e4Jt.js → Marketplace-BYyRyOPz.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-C-TNlVUf.js → McpTools-DVu8w_rM.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-DMTPIpGa.js → Memory-tenuZ_hO.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-BxyvveRq.js → MobileBridge-Bxgy4ozS.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-DyPCrAyQ.js → MobileProjects-Dgx1D6sc.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-BdhqNXp6.js → Mtc-CRfJ8r8j.js} +5 -5
  43. package/src/assets/web-panel/assets/{MtcAudit-Cz-HFxzW.js → MtcAudit-BBJq4Aiz.js} +5 -5
  44. package/src/assets/web-panel/assets/{Multisig-CIUaFNsx.js → Multisig-B3ii9lai.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-CWe6-J17.js → NLProgramming-FIi-Cubv.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-vYAKeviU.js → Notes-DIq8MPf1.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-DQL9-2d7.js → NotificationSettings-BFOD9eGd.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-DnXj1jBn.js → OrderTableRenderer--41u7vre.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-B3spU8AN.js → Organization-B_0AWztW.js} +2 -2
  50. package/src/assets/web-panel/assets/{Overflow-DgEwo7vm.js → Overflow-B6I7TuXv.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-hujMRH8X.js → P2P-Cdf6qens.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-C_qhdg9h.js → PdhVaultBrowser-B_0FcQJY.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-vp7LMcSf.js → Permissions-6nFBjsQp.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-Dxr5Hgnq.js → PersonalDataHub-nQYV7xpn.js} +3 -3
  55. package/src/assets/web-panel/assets/{Pipeline-DEPZqqH4.js → Pipeline-CBVod5jm.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-DTpDiKPe.js → Privacy-D52jW1Nt.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-jDJsRWmF.js → ProjectInit-Bdx3BYhf.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-Dhor5RWH.js → ProjectSettings-b7xr4DUa.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-DhfifCKx.js +1 -0
  60. package/src/assets/web-panel/assets/Providers-Dy_PgDMr.js +1 -0
  61. package/src/assets/web-panel/assets/{QrScannerModal-CjIw-wIb.js → QrScannerModal-FQKSmc3e.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-DX6jcqoi.js → QuickAsk-CSTrhzcF.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-DopXkhar.js → Recommend-CxMABOUh.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-BLvqJE9c.js → RemoteSession-Cv2T8yRa.js} +2 -2
  65. package/src/assets/web-panel/assets/{Reputation-DhRj2Me7.js → Reputation-CE1k4Vvu.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-DQ53vuPq.js → Row-BNgNcAV_.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-BslvwiBD.js → RssFeed-5ZiBZ3ph.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-DJKBDNKZ.js → Search-mDOIF1UV.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-COhpxHER.js → Security-CtuCTC-e.js} +3 -3
  70. package/src/assets/web-panel/assets/{Services-dbulD6cI.js → Services-DxFO2Zg7.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-ciIVNfhC.js → Skeleton-CKmKkH9y.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-AiRTkTCk.js → Skills-Bmzl9qkk.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-DDMcWYBc.js → Sla-9RqaWHOC.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-BPxWbpXO.js → SpeechSettings-CGdzFIYw.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-BoEOXCyg.js → SyncSettings-CvNuCeBT.js} +2 -2
  76. package/src/assets/web-panel/assets/Tasks-B_sLdcnw.js +1 -0
  77. package/src/assets/web-panel/assets/{Templates-UowY8Ixe.js → Templates-D9_YijdK.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-DauSLQXN.js → Tenant-Cuc7BUSP.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-DBj7Jneq.js → Terminal-6VYRnJgd.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-UMrPwoZC.js → TimelineRenderer-GtK8xd8Y.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-4ea96-bn.js → Tokens-BZ94Lt5W.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger--ISCqt4b.js → Trigger-DEcZgDaX.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-D4GVimRJ.js → Trust-CC3z9THe.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-Ci-nXRQc.js → UkeySign-Cvtw8cV3.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-Cjk7mKPw.js → VideoEditing-CL4e6Bn3.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-BgOLOO3Z.js → Wallet-ycEemP27.js} +2 -2
  87. package/src/assets/web-panel/assets/{WebAuthn-CCX0K29i.js → WebAuthn-DgZ4X_aw.js} +5 -5
  88. package/src/assets/web-panel/assets/{WorkflowEditor-Ch3zgIsE.js → WorkflowEditor-D0qMhSv7.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-DKOU_2Vb.js → chat-DsAg01Zn.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-6OVo4u3C.js → colors-B0oqAhrQ.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-BH78Hlsq.js → compact-item-CmX0Rabz.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-CFRpSbbC.js → createContext-Be4cn1Ub.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-CP2qzG6D.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-DNQhgcVi.js → hasIn-D5v12kVq.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BkN3iTTp.js → index-0eWLkQKT.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-CkNEMANR.js → index-301ogenv.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-D3RtTT4K.js → index-5LGY0JbG.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-dDkoL4Pe.js → index-7VKDn-t1.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BHa4WyTZ.js → index-8WvYGnON.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CaYqY35Z.js → index-B1YGjOWC.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-bKm3TUDp.js → index-B3mUHuVc.js} +1 -1
  102. package/src/assets/web-panel/assets/{index--rq90rL9.js → index-BA4oulaP.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DaDgdJYj.js → index-BBREnn1V.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-B_Z-YoxX.js → index-BBvyHguy.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CkqHgG-b.js → index-BKmsS2jj.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CrcLHN2F.js → index-BRIqLy1m.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BaVE6E8y.js → index-BXGSbelg.js} +3 -3
  108. package/src/assets/web-panel/assets/{index-BYrnm5Ob.js → index-BaE0Ui07.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BDSR7ecX.js → index-BoAIAZ5C.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CNuCHHQT.js → index-BqltWojQ.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Eag8e_mA.js → index-CGiIyTZw.js} +1 -1
  112. package/src/assets/web-panel/assets/index-CKB0vbJU.js +1 -0
  113. package/src/assets/web-panel/assets/{index-BepBTpa8.js → index-CZ2wUEgr.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-HNGGVF6o.js → index-CZpfzcuy.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-AuBhLqOm.js → index-Ckrk3pIV.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-7TC3S8SN.js → index-CqoCZ5vR.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CFPJ8yzF.js → index-CyWBir7N.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Bb6kDrUx.js → index-CyyGTMKd.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DKN2noIF.js → index-D0BSkxYQ.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Du0rnksC.js → index-D5YVopyr.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BxRy5LPR.js → index-DKUBj36_.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-sm7W8AXy.js → index-DM724NgU.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BujsOZfc.js → index-DQRsQen0.js} +1 -1
  124. package/src/assets/web-panel/assets/index-DgoXmwqB.js +1 -0
  125. package/src/assets/web-panel/assets/{index-Y9MJv28e.js → index-DikJ0Qqe.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-caye7AOE.js → index-Dn2dSdXx.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-cdf7fd7d.js → index-DyUaFWEk.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BnnXQot_.js → index-Hfe_dEGx.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DvHGtNnF.js → index-_JjRLSD0.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-nbfHl1oV.js → index-frSojpHj.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Cu3L4r5l.js → index-jK3ax6Z6.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D84id2Y4.js → index-qMuZ-NRR.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-hPY0fFrd.js → index-q_fQ94SE.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-BZ9w6jPL.js → initDefaultProps-D4VdhJ9_.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BnwUiOho.js → motion-CZJA0MQW.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-ByUKJnNm.js → move-BqEs7Sb1.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-V7yK1KEl.js → mtc-parser-BpHEtsu1.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-BEXBBt4j.js → omit-BW94tY9W.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-qDm_46Gi.js → pickAttrs-BnBjPWP9.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-BIbhEo_0.js → placementArrow-uUkjQ_hu.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-NbPbDgA_.js → responsiveObserve-B-klUqXK.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-BnUWglZ0.js → slide-CvY1cNAs.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-BX8_wZI5.js → statusUtils-Ix5sEDT2.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-BV4OycQX.js → styleChecker-C8qcXOne.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-Od_H5llY.js → useFlexGapSupport-KNF6Kj8f.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-BWI-PyiX.js → useFs-DGJr345n.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-BqMuhG3g.js → usePersonalDataHub-BboN99rI.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-DNd23z6f.js → vnode-Bgt8Vgte.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-Cjaxnm7l.js → zoom-BhJtErgt.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/command-help-index.json +2 -2
  152. package/src/commands/agenda.js +6 -5
  153. package/src/commands/agent.js +237 -75
  154. package/src/commands/agents.js +6 -0
  155. package/src/commands/artifacts.js +98 -0
  156. package/src/commands/background-session.js +11 -1
  157. package/src/commands/mcp.js +218 -31
  158. package/src/commands/review.js +221 -22
  159. package/src/commands/session-mcp-recovery.js +5 -5
  160. package/src/data/changelog.json +27 -1
  161. package/src/gateways/ws/ws-agent-handler.js +492 -14
  162. package/src/harness/jsonl-session-store.js +39 -1
  163. package/src/harness/mcp-client.js +414 -71
  164. package/src/harness/prompt-compressor.js +24 -0
  165. package/src/harness/provider-backed-compaction.js +205 -0
  166. package/src/harness/worktree-isolator.js +26 -3
  167. package/src/lib/agent-worktree.js +41 -2
  168. package/src/lib/app-preview.js +3 -0
  169. package/src/lib/background-agent-supervisor.js +790 -186
  170. package/src/lib/background-command-argv.js +318 -0
  171. package/src/lib/background-launch-profile.js +1 -0
  172. package/src/lib/background-phase-reporter.js +22 -2
  173. package/src/lib/background-worktree-policy.js +109 -0
  174. package/src/lib/command-lifecycle-report.js +1340 -145
  175. package/src/lib/cowork-mcp-tools.js +51 -6
  176. package/src/lib/cowork-task-runner.js +1 -0
  177. package/src/lib/delivery-coordinator.js +30 -5
  178. package/src/lib/delivery-production-adapter.js +1777 -0
  179. package/src/lib/delivery-production-runner.js +240 -0
  180. package/src/lib/durable-security-store.js +29 -17
  181. package/src/lib/execution-trace/trace-context.cjs +179 -0
  182. package/src/lib/execution-trace/trace-context.js +8 -175
  183. package/src/lib/mcp-call-ledger-store.js +58 -6
  184. package/src/lib/mcp-headers-helper.js +76 -8
  185. package/src/lib/mcp-host-recovery-runtime.js +2 -0
  186. package/src/lib/mcp-ledger-recovery-admission.js +39 -3
  187. package/src/lib/mcp-recovery-adjudication.js +256 -19
  188. package/src/lib/mcp-sandbox-policy.js +184 -0
  189. package/src/lib/mcp-stdio-capsule-builder-worker.cjs +495 -0
  190. package/src/lib/mcp-stdio-executable-identity.js +33 -2
  191. package/src/lib/mcp-stdio-execution-authority.js +163 -0
  192. package/src/lib/mcp-stdio-immutable-vfs-resolver.cjs +830 -0
  193. package/src/lib/mcp-stdio-package-materialization.js +721 -333
  194. package/src/lib/mcp-stdio-workspace-authority.js +252 -0
  195. package/src/lib/observability/index.js +2 -0
  196. package/src/lib/observability/otlp-exporter.js +2 -2
  197. package/src/lib/packer/pack-update-applier.js +8 -1
  198. package/src/lib/packer/pkg-config-generator.js +34 -0
  199. package/src/lib/plugin-runtime/sandbox-policy.js +42 -2
  200. package/src/lib/process-execution-broker/index.js +213 -109
  201. package/src/lib/process-execution-broker/platform-sandbox.js +1024 -169
  202. package/src/lib/process-tree-termination.js +17 -1
  203. package/src/lib/scheduler-kernel/contract.js +315 -0
  204. package/src/lib/scheduler-kernel/store.js +1345 -0
  205. package/src/lib/session-host-lease.js +403 -30
  206. package/src/lib/session-persistence-failure.js +4 -1
  207. package/src/lib/skill-mcp.js +65 -4
  208. package/src/lib/sub-agent-context.js +8 -0
  209. package/src/lib/web-fetch.js +4 -4
  210. package/src/repl/agent-repl.js +285 -38
  211. package/src/runtime/agent-core.js +1044 -90
  212. package/src/runtime/agent-runtime.js +61 -8
  213. package/src/runtime/headless-runner.js +260 -166
  214. package/src/runtime/headless-stream.js +254 -25
  215. package/src/runtime/mcp-config.js +235 -28
  216. package/src/workers/background-agent-worker.js +492 -71
  217. package/src/assets/web-panel/assets/Projects-08xUDZGt.js +0 -1
  218. package/src/assets/web-panel/assets/Providers-BGs47s1a.js +0 -1
  219. package/src/assets/web-panel/assets/Tasks-CEYFJwmr.js +0 -1
  220. package/src/assets/web-panel/assets/devWarning-DEMblAIm.js +0 -1
  221. package/src/assets/web-panel/assets/index-BTvq-36D.js +0 -1
  222. package/src/assets/web-panel/assets/index-hUpvk6Jl.js +0 -1
@@ -1,10 +1,10 @@
1
- import { randomUUID as nodeRandomUUID } from "node:crypto";
2
1
  import { appendAuthorityEventIfHead as storeAppendAuthorityEventIfHead } from "../harness/jsonl-session-store.js";
3
2
  import {
4
3
  MCP_CALL_RECOVERY_ADJUDICATION_EVENT,
5
4
  MCP_CALL_RECOVERY_ADJUDICATION_SCHEMA_VERSION,
6
5
  MCP_CALL_RECOVERY_AUTHORITY,
7
6
  MCP_CALL_RECOVERY_CONFIRMATION,
7
+ MCP_CALL_RECOVERY_LEGACY_CONFIRMATION,
8
8
  McpCallRecoveryDecision,
9
9
  deriveMcpExactReplayDenies,
10
10
  loadMcpLedgerRecovery,
@@ -15,6 +15,7 @@ import {
15
15
  sha256PayloadDigest,
16
16
  snapshotMcpJsonRpcInput,
17
17
  } from "./mcp-call-ledger.js";
18
+ import { revokeSessionHostAuthority as storeRevokeSessionHostAuthority } from "./session-host-lease.js";
18
19
 
19
20
  const PAYLOAD_DIGEST = /^sha256:[0-9a-f]{64}$/;
20
21
  const RAW_AUTHORITY_HASH = /^[0-9a-f]{64}$/;
@@ -32,6 +33,30 @@ const PUBLIC_REPLAY_DENY_FIELDS = new Set([
32
33
  "inputBytes",
33
34
  "replayDigest",
34
35
  ]);
36
+ const PUBLIC_ADJUDICATION_FIELDS_V1 = new Set([
37
+ "schemaVersion",
38
+ "requestId",
39
+ "sessionId",
40
+ "ledgerId",
41
+ "decision",
42
+ "expectedHeadHash",
43
+ "expectedRecoveryDigest",
44
+ "authority",
45
+ "confirmation",
46
+ "reasonDigest",
47
+ ]);
48
+ const PUBLIC_ADJUDICATION_FIELDS_V2 = new Set([
49
+ ...PUBLIC_ADJUDICATION_FIELDS_V1,
50
+ "hostRevocation",
51
+ ]);
52
+ const PUBLIC_HOST_REVOCATION_FIELDS = new Set([
53
+ "requestId",
54
+ "revocationEpoch",
55
+ "targetLeaseId",
56
+ "targetFencingToken",
57
+ "targetOwnerPid",
58
+ ]);
59
+ const HOST_LEASE_ID = /^lease-[0-9a-f-]{36}$/;
35
60
 
36
61
  export class McpRecoveryAdjudicationError extends Error {
37
62
  constructor(code, message, options = {}) {
@@ -40,6 +65,9 @@ export class McpRecoveryAdjudicationError extends Error {
40
65
  this.code = code;
41
66
  this.sessionId = options.sessionId || null;
42
67
  this.ledgerId = options.ledgerId || null;
68
+ this.hostRevocation = options.hostRevocation || null;
69
+ this.commitState = options.commitState || null;
70
+ this.outcomeUnknown = options.outcomeUnknown === true;
43
71
  }
44
72
  }
45
73
 
@@ -226,25 +254,70 @@ export function publicMcpRecoveryAuthority(sessionId, recovery) {
226
254
  });
227
255
  });
228
256
  const adjudications = snapshot.adjudications.map((entry) => {
257
+ const legacy = entry?.schemaVersion === 1;
258
+ const fields = Object.keys(entry || {});
259
+ const allowedFields = legacy
260
+ ? PUBLIC_ADJUDICATION_FIELDS_V1
261
+ : PUBLIC_ADJUDICATION_FIELDS_V2;
229
262
  const requestId = canonicalIdentifier(entry?.requestId);
230
263
  const ledgerId = canonicalLedgerId(entry?.ledgerId);
264
+ const confirmationIsValid =
265
+ (entry?.schemaVersion === 1 &&
266
+ entry?.confirmation === MCP_CALL_RECOVERY_LEGACY_CONFIRMATION) ||
267
+ (entry?.schemaVersion === MCP_CALL_RECOVERY_ADJUDICATION_SCHEMA_VERSION &&
268
+ entry?.confirmation === MCP_CALL_RECOVERY_CONFIRMATION);
269
+ const revocation = entry?.hostRevocation;
270
+ const revocationFields = Object.keys(revocation || {});
271
+ const targetIsNull = revocation?.targetLeaseId === null;
272
+ const revocationIsValid =
273
+ legacy ||
274
+ (revocationFields.length === PUBLIC_HOST_REVOCATION_FIELDS.size &&
275
+ revocationFields.every((field) =>
276
+ PUBLIC_HOST_REVOCATION_FIELDS.has(field),
277
+ ) &&
278
+ revocation?.requestId === requestId &&
279
+ Number.isSafeInteger(revocation?.revocationEpoch) &&
280
+ revocation.revocationEpoch >= 1 &&
281
+ (targetIsNull
282
+ ? revocation.targetFencingToken === null &&
283
+ revocation.targetOwnerPid === null
284
+ : HOST_LEASE_ID.test(String(revocation?.targetLeaseId || "")) &&
285
+ Number.isSafeInteger(revocation?.targetFencingToken) &&
286
+ revocation.targetFencingToken >= 1 &&
287
+ Number.isSafeInteger(revocation?.targetOwnerPid) &&
288
+ revocation.targetOwnerPid >= 1));
231
289
  if (
290
+ fields.length !== allowedFields.size ||
291
+ fields.some((field) => !allowedFields.has(field)) ||
232
292
  !requestId ||
233
293
  !ledgerId ||
234
294
  !Object.values(McpCallRecoveryDecision).includes(entry?.decision) ||
235
295
  entry?.authority !== MCP_CALL_RECOVERY_AUTHORITY ||
236
- entry?.confirmation !== MCP_CALL_RECOVERY_CONFIRMATION ||
296
+ !confirmationIsValid ||
297
+ !revocationIsValid ||
237
298
  !PAYLOAD_DIGEST.test(String(entry?.reasonDigest || ""))
238
299
  ) {
239
300
  return invalidProjection();
240
301
  }
241
302
  return Object.freeze({
303
+ schemaVersion: entry.schemaVersion,
242
304
  requestId,
243
305
  ledgerId,
244
306
  decision: entry.decision,
245
307
  authority: entry.authority,
246
308
  confirmation: entry.confirmation,
247
309
  reasonDigest: entry.reasonDigest,
310
+ ...(legacy
311
+ ? {}
312
+ : {
313
+ hostRevocation: Object.freeze({
314
+ requestId: revocation.requestId,
315
+ revocationEpoch: revocation.revocationEpoch,
316
+ targetLeaseId: revocation.targetLeaseId,
317
+ targetFencingToken: revocation.targetFencingToken,
318
+ targetOwnerPid: revocation.targetOwnerPid,
319
+ }),
320
+ }),
248
321
  });
249
322
  });
250
323
  return Object.freeze({
@@ -286,14 +359,106 @@ export function buildMcpRecoveryAdjudicationChallenge({
286
359
  );
287
360
  }
288
361
  return (
289
- `HOST STOPPED; ADJUDICATE ${canonicalSessionId} ${canonicalId} ` +
362
+ `HOST STOPPED AND MCP DISPATCH DRAINED; REVOKE HOST AUTHORITY; ADJUDICATE ${canonicalSessionId} ${canonicalId} ` +
290
363
  `${canonicalDecision} ${canonicalDigest}`
291
364
  );
292
365
  }
293
366
 
367
+ function deterministicAdjudicationRequestId({
368
+ sessionId,
369
+ ledgerId,
370
+ decision,
371
+ expectedHeadHash,
372
+ expectedRecoveryDigest,
373
+ reasonDigest,
374
+ }) {
375
+ const digest = sha256PayloadDigest({
376
+ schemaVersion: MCP_CALL_RECOVERY_ADJUDICATION_SCHEMA_VERSION,
377
+ sessionId,
378
+ ledgerId,
379
+ decision,
380
+ expectedHeadHash,
381
+ expectedRecoveryDigest,
382
+ reasonDigest,
383
+ });
384
+ return `mcp-recovery-${digest.slice("sha256:".length)}`;
385
+ }
386
+
387
+ function canonicalHostRevocation(value, requestId, context) {
388
+ let snapshot;
389
+ try {
390
+ snapshot = snapshotMcpJsonRpcInput(value);
391
+ } catch (cause) {
392
+ throw new McpRecoveryAdjudicationError(
393
+ "CC_MCP_RECOVERY_HOST_REVOCATION_FAILED",
394
+ "MCP recovery host revocation returned malformed authority",
395
+ { ...context, cause },
396
+ );
397
+ }
398
+ const targetIsNull = snapshot?.targetLeaseId === null;
399
+ if (
400
+ !snapshot ||
401
+ snapshot.requestId !== requestId ||
402
+ snapshot.reasonCode !== "mcp-recovery-adjudication" ||
403
+ !Number.isSafeInteger(snapshot.revocationEpoch) ||
404
+ snapshot.revocationEpoch < 1 ||
405
+ typeof snapshot.replayed !== "boolean" ||
406
+ (targetIsNull
407
+ ? snapshot.targetFencingToken !== null || snapshot.targetOwnerPid !== null
408
+ : !HOST_LEASE_ID.test(String(snapshot.targetLeaseId || "")) ||
409
+ !Number.isSafeInteger(snapshot.targetFencingToken) ||
410
+ snapshot.targetFencingToken < 1 ||
411
+ !Number.isSafeInteger(snapshot.targetOwnerPid) ||
412
+ snapshot.targetOwnerPid < 1)
413
+ ) {
414
+ throw new McpRecoveryAdjudicationError(
415
+ "CC_MCP_RECOVERY_HOST_REVOCATION_FAILED",
416
+ "MCP recovery host revocation returned malformed authority",
417
+ context,
418
+ );
419
+ }
420
+ return Object.freeze({
421
+ requestId: snapshot.requestId,
422
+ revocationEpoch: snapshot.revocationEpoch,
423
+ replayed: snapshot.replayed,
424
+ targetLeaseId: snapshot.targetLeaseId,
425
+ targetFencingToken: snapshot.targetFencingToken,
426
+ targetOwnerPid: snapshot.targetOwnerPid,
427
+ });
428
+ }
429
+
430
+ function persistedHostRevocation(hostRevocation) {
431
+ return Object.freeze({
432
+ requestId: hostRevocation.requestId,
433
+ revocationEpoch: hostRevocation.revocationEpoch,
434
+ targetLeaseId: hostRevocation.targetLeaseId,
435
+ targetFencingToken: hostRevocation.targetFencingToken,
436
+ targetOwnerPid: hostRevocation.targetOwnerPid,
437
+ });
438
+ }
439
+
440
+ function exactAdjudicationReadback(sessionId, data, dependencies) {
441
+ try {
442
+ const recovery = readMcpRecoveryAuthority(sessionId, dependencies);
443
+ const expected = sha256PayloadDigest(data);
444
+ const match = recovery.adjudications.find(
445
+ (entry) =>
446
+ entry?.requestId === data.requestId &&
447
+ sha256PayloadDigest(entry) === expected,
448
+ );
449
+ if (!match || !RAW_AUTHORITY_HASH.test(String(recovery.headHash || ""))) {
450
+ return null;
451
+ }
452
+ return Object.freeze({ hash: recovery.headHash, recovery });
453
+ } catch {
454
+ return null;
455
+ }
456
+ }
457
+
294
458
  /**
295
- * Append exactly one human adjudication authority event under a verified-head
296
- * CAS. A stale comparison is returned to the caller and is never retried.
459
+ * Durably revoke current host authority, then append exactly one human
460
+ * adjudication event under a verified-head CAS. A stale comparison is never
461
+ * retried; the capability-reducing revocation remains durable on append loss.
297
462
  */
298
463
  export async function adjudicateMcpRecovery(request, dependencies = {}) {
299
464
  let safeRequest;
@@ -364,9 +529,16 @@ export async function adjudicateMcpRecovery(request, dependencies = {}) {
364
529
  }
365
530
 
366
531
  const reasonDigest = sha256PayloadDigest(reason);
367
- const randomUUID = dependencies.randomUUID || nodeRandomUUID;
368
532
  const requestId = canonicalIdentifier(
369
- safeRequest.requestId || `mcp-recovery-${randomUUID()}`,
533
+ safeRequest.requestId ||
534
+ deterministicAdjudicationRequestId({
535
+ sessionId,
536
+ ledgerId,
537
+ decision,
538
+ expectedHeadHash: recovery.headHash,
539
+ expectedRecoveryDigest: recovery.recoveryDigest,
540
+ reasonDigest,
541
+ }),
370
542
  );
371
543
  if (!requestId) {
372
544
  throw new McpRecoveryAdjudicationError(
@@ -375,6 +547,39 @@ export async function adjudicateMcpRecovery(request, dependencies = {}) {
375
547
  context,
376
548
  );
377
549
  }
550
+ const revokeSessionHostAuthority =
551
+ dependencies.revokeSessionHostAuthority || storeRevokeSessionHostAuthority;
552
+ let hostRevocation;
553
+ try {
554
+ hostRevocation = canonicalHostRevocation(
555
+ await revokeSessionHostAuthority(sessionId, {
556
+ requestId,
557
+ reasonCode: "mcp-recovery-adjudication",
558
+ }),
559
+ requestId,
560
+ context,
561
+ );
562
+ } catch (cause) {
563
+ if (cause instanceof McpRecoveryAdjudicationError) throw cause;
564
+ const commitState = cause?.commitState || "unknown";
565
+ if (commitState !== "not-committed") {
566
+ throw new McpRecoveryAdjudicationError(
567
+ "CC_MCP_RECOVERY_HOST_REVOCATION_OUTCOME_UNKNOWN",
568
+ "MCP recovery host revocation outcome is unknown; do not retry or adjudicate until exact authority readback succeeds",
569
+ {
570
+ ...context,
571
+ cause,
572
+ commitState,
573
+ outcomeUnknown: true,
574
+ },
575
+ );
576
+ }
577
+ throw new McpRecoveryAdjudicationError(
578
+ "CC_MCP_RECOVERY_HOST_REVOCATION_FAILED",
579
+ "MCP recovery host authority could not be durably revoked; no adjudication was appended",
580
+ { ...context, cause, commitState },
581
+ );
582
+ }
378
583
  const data = Object.freeze({
379
584
  schemaVersion: MCP_CALL_RECOVERY_ADJUDICATION_SCHEMA_VERSION,
380
585
  requestId,
@@ -386,6 +591,7 @@ export async function adjudicateMcpRecovery(request, dependencies = {}) {
386
591
  authority: MCP_CALL_RECOVERY_AUTHORITY,
387
592
  confirmation: MCP_CALL_RECOVERY_CONFIRMATION,
388
593
  reasonDigest,
594
+ hostRevocation: persistedHostRevocation(hostRevocation),
389
595
  });
390
596
  const appendAuthorityEventIfHead =
391
597
  dependencies.appendAuthorityEventIfHead || storeAppendAuthorityEventIfHead;
@@ -403,22 +609,52 @@ export async function adjudicateMcpRecovery(request, dependencies = {}) {
403
609
  if (cause?.code === "SESSION_REVISION_STALE") {
404
610
  throw new McpRecoveryAdjudicationError(
405
611
  "CC_MCP_RECOVERY_ADJUDICATION_STALE",
406
- "MCP recovery authority changed; run show again before adjudicating",
407
- { ...context, cause },
612
+ "MCP recovery authority changed after host revocation; run show again before adjudicating",
613
+ { ...context, cause, hostRevocation },
614
+ );
615
+ }
616
+ const commitState = cause?.commitState || "unknown";
617
+ if (commitState !== "not-committed") {
618
+ const readback = exactAdjudicationReadback(sessionId, data, dependencies);
619
+ if (readback) {
620
+ appended = readback;
621
+ } else {
622
+ throw new McpRecoveryAdjudicationError(
623
+ "CC_MCP_RECOVERY_ADJUDICATION_OUTCOME_UNKNOWN",
624
+ "MCP recovery adjudication persistence outcome is unknown; host authority remains revoked and exact transcript reconciliation is required before retry",
625
+ {
626
+ ...context,
627
+ cause,
628
+ hostRevocation,
629
+ commitState,
630
+ outcomeUnknown: true,
631
+ },
632
+ );
633
+ }
634
+ } else {
635
+ throw new McpRecoveryAdjudicationError(
636
+ "CC_MCP_RECOVERY_ADJUDICATION_PERSIST_FAILED",
637
+ "MCP recovery adjudication was not persisted; host authority remains revoked",
638
+ { ...context, cause, hostRevocation, commitState },
408
639
  );
409
640
  }
410
- throw new McpRecoveryAdjudicationError(
411
- "CC_MCP_RECOVERY_ADJUDICATION_PERSIST_FAILED",
412
- "MCP recovery adjudication was not persisted",
413
- { ...context, cause },
414
- );
415
641
  }
416
642
  if (!appended || !RAW_AUTHORITY_HASH.test(String(appended.hash || ""))) {
417
- throw new McpRecoveryAdjudicationError(
418
- "CC_MCP_RECOVERY_ADJUDICATION_PERSIST_FAILED",
419
- "MCP recovery adjudication did not return a durable authority hash",
420
- context,
421
- );
643
+ const readback = exactAdjudicationReadback(sessionId, data, dependencies);
644
+ if (readback) {
645
+ appended = readback;
646
+ } else {
647
+ throw new McpRecoveryAdjudicationError(
648
+ "CC_MCP_RECOVERY_ADJUDICATION_OUTCOME_UNKNOWN",
649
+ "MCP recovery adjudication returned no durable authority hash; host authority remains revoked and exact transcript reconciliation is required",
650
+ {
651
+ ...context,
652
+ hostRevocation,
653
+ commitState: appended?.commitState || "unknown",
654
+ outcomeUnknown: true,
655
+ },
656
+ );
657
+ }
422
658
  }
423
659
 
424
660
  return Object.freeze({
@@ -437,6 +673,7 @@ export async function adjudicateMcpRecovery(request, dependencies = {}) {
437
673
  : [],
438
674
  ),
439
675
  replayDenied: decision === McpCallRecoveryDecision.CONFIRMED_APPLIED,
676
+ hostRevocation,
440
677
  runtimeReloadRequired: true,
441
678
  remediation: "restart_or_resume_before_mcp_calls",
442
679
  });
@@ -0,0 +1,184 @@
1
+ import { isProxy } from "node:util/types";
2
+
3
+ /**
4
+ * Declarative sandbox boundaries an external MCP source may require.
5
+ *
6
+ * Internal broker guarantees (for example process-tree and code-snapshot) are
7
+ * deliberately not part of this source-controlled contract. A trusted host
8
+ * may add its own non-removable requirements after this value is normalized.
9
+ */
10
+ export const MCP_SANDBOX_BOUNDARIES = Object.freeze(["filesystem", "network"]);
11
+
12
+ export const MCP_SANDBOX_POLICY_INVALID_CODE = "CC_MCP_SANDBOX_POLICY_INVALID";
13
+ export const MCP_STDIO_CWD_INVALID_CODE = "CC_MCP_STDIO_SANDBOX_CWD_INVALID";
14
+
15
+ const SUPPORTED_BOUNDARIES = new Set(MCP_SANDBOX_BOUNDARIES);
16
+ const MAX_BOUNDARY_DECLARATIONS = 32;
17
+
18
+ function invalidPolicy(message) {
19
+ const error = new TypeError(message);
20
+ error.code = MCP_SANDBOX_POLICY_INVALID_CODE;
21
+ return error;
22
+ }
23
+
24
+ function invalidCwd(message) {
25
+ const error = new TypeError(message);
26
+ error.code = MCP_STDIO_CWD_INVALID_CODE;
27
+ return error;
28
+ }
29
+
30
+ /**
31
+ * Read an optional stdio working directory without invoking accessors or Proxy
32
+ * traps. Absence means "retain/default" while null and the empty string are an
33
+ * explicit clear. Every other value must be a NUL-free string.
34
+ */
35
+ export function readMcpStdioCwd(owner, options = {}) {
36
+ const label =
37
+ typeof options.label === "string" && options.label.length > 0
38
+ ? options.label
39
+ : "MCP stdio config";
40
+ if (!owner || typeof owner !== "object" || isProxy(owner)) {
41
+ throw invalidCwd(`${label} must be a non-Proxy object`);
42
+ }
43
+ const descriptor = Object.getOwnPropertyDescriptor(owner, "cwd");
44
+ if (!descriptor) return { present: false, cwd: null };
45
+ if (!("value" in descriptor)) {
46
+ throw invalidCwd(`${label}.cwd must be an own data property`);
47
+ }
48
+ const value = descriptor.value;
49
+ if (value == null || value === "") return { present: true, cwd: null };
50
+ if (typeof value !== "string" || value.includes("\0")) {
51
+ throw invalidCwd(`${label}.cwd must be a NUL-free path string`);
52
+ }
53
+ return { present: true, cwd: value };
54
+ }
55
+
56
+ function ownDataDescriptor(value, key, label) {
57
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
58
+ if (!descriptor || !("value" in descriptor)) {
59
+ throw invalidPolicy(`${label} must be an own data property`);
60
+ }
61
+ return descriptor;
62
+ }
63
+
64
+ function normalizeRequiredBoundaries(value, label) {
65
+ if (!Array.isArray(value) || isProxy(value)) {
66
+ throw invalidPolicy(`${label} must be a non-Proxy array`);
67
+ }
68
+
69
+ const lengthDescriptor = ownDataDescriptor(
70
+ value,
71
+ "length",
72
+ `${label}.length`,
73
+ );
74
+ const length = lengthDescriptor.value;
75
+ if (length > MAX_BOUNDARY_DECLARATIONS) {
76
+ throw invalidPolicy(
77
+ `${label} exceeds ${MAX_BOUNDARY_DECLARATIONS} boundary declarations`,
78
+ );
79
+ }
80
+ const allowedKeys = new Set(["length"]);
81
+ const requiredBoundaries = new Set();
82
+
83
+ for (let index = 0; index < length; index += 1) {
84
+ const key = String(index);
85
+ allowedKeys.add(key);
86
+ const descriptor = ownDataDescriptor(value, key, `${label}[${index}]`);
87
+ const boundary = descriptor.value;
88
+ if (typeof boundary !== "string" || !SUPPORTED_BOUNDARIES.has(boundary)) {
89
+ throw invalidPolicy(`${label} contains an unsupported boundary`);
90
+ }
91
+ requiredBoundaries.add(boundary);
92
+ }
93
+
94
+ for (const key of Reflect.ownKeys(value)) {
95
+ if (typeof key !== "string" || !allowedKeys.has(key)) {
96
+ throw invalidPolicy(
97
+ `${label} contains unsupported property: ${String(key)}`,
98
+ );
99
+ }
100
+ }
101
+
102
+ return Object.freeze([...requiredBoundaries].sort());
103
+ }
104
+
105
+ /**
106
+ * Normalize an MCP source's small declarative sandbox contract.
107
+ *
108
+ * The input is treated as untrusted data: Proxy objects, inherited/accessor
109
+ * fields, non-plain objects, and unknown fields are rejected without invoking
110
+ * user-controlled code. `null` and an empty policy retain the legacy meaning
111
+ * of "no source-declared requirements".
112
+ *
113
+ * @param {unknown} value
114
+ * @param {{label?: string}} [options]
115
+ * @returns {{requiredBoundaries: readonly string[]}|null}
116
+ */
117
+ export function normalizeMcpSandboxPolicy(value, options = {}) {
118
+ const label =
119
+ typeof options.label === "string" && options.label.length > 0
120
+ ? options.label
121
+ : "sandboxPolicy";
122
+
123
+ if (value === undefined || value === null) return null;
124
+ if (typeof value !== "object" || Array.isArray(value) || isProxy(value)) {
125
+ throw invalidPolicy(`${label} must be a non-Proxy plain object`);
126
+ }
127
+
128
+ const prototype = Object.getPrototypeOf(value);
129
+ if (prototype !== Object.prototype && prototype !== null) {
130
+ throw invalidPolicy(`${label} must be a plain object`);
131
+ }
132
+
133
+ const keys = Reflect.ownKeys(value);
134
+ for (const key of keys) {
135
+ if (key !== "requiredBoundaries") {
136
+ throw invalidPolicy(
137
+ `${label} contains unsupported field: ${String(key)}`,
138
+ );
139
+ }
140
+ }
141
+
142
+ if (!keys.includes("requiredBoundaries")) return null;
143
+ const descriptor = ownDataDescriptor(
144
+ value,
145
+ "requiredBoundaries",
146
+ `${label}.requiredBoundaries`,
147
+ );
148
+ const requiredBoundaries = normalizeRequiredBoundaries(
149
+ descriptor.value,
150
+ `${label}.requiredBoundaries`,
151
+ );
152
+ if (requiredBoundaries.length === 0) return null;
153
+
154
+ return Object.freeze({ requiredBoundaries });
155
+ }
156
+
157
+ /**
158
+ * Add the host-owned isolation floor for an exact-package stdio capsule.
159
+ *
160
+ * Source configuration is normalized as untrusted data first and can only add
161
+ * requirements to this floor. The returned policy is a new deeply-frozen
162
+ * runtime value, so neither the source object nor later launch preparation can
163
+ * remove a host requirement. Callers must only attach this policy after the
164
+ * trusted executable-identity preparer has issued a capsule execution
165
+ * contract; legacy stdio sources intentionally retain their existing policy.
166
+ * There is deliberately no source-configured escape hatch: future workspace
167
+ * or egress access must be a separate host-issued, authority-bound capability.
168
+ *
169
+ * @param {unknown} value
170
+ * @param {{label?: string}} [options]
171
+ * @returns {{requiredBoundaries: readonly string[]}}
172
+ */
173
+ export function enforceMcpStdioCapsuleHostSandboxPolicy(value, options = {}) {
174
+ const sourcePolicy = normalizeMcpSandboxPolicy(value, options);
175
+ const requiredBoundaries = Object.freeze(
176
+ [
177
+ ...new Set([
178
+ ...MCP_SANDBOX_BOUNDARIES,
179
+ ...(sourcePolicy?.requiredBoundaries || []),
180
+ ]),
181
+ ].sort(),
182
+ );
183
+ return Object.freeze({ requiredBoundaries });
184
+ }