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
@@ -1813,6 +1813,11 @@ export async function executeTool(name, args, context = {}) {
1813
1813
  typeof context.externalToolDescriptors === "object"
1814
1814
  ? context.externalToolDescriptors[name] || null
1815
1815
  : null;
1816
+ const localToolExecutor =
1817
+ context.externalToolExecutors &&
1818
+ typeof context.externalToolExecutors === "object"
1819
+ ? context.externalToolExecutors[name] || null
1820
+ : null;
1816
1821
  const runtimeDescriptor =
1817
1822
  getRuntimeToolDescriptor(name) || localToolDescriptor;
1818
1823
  const admission = context.toolAdmission;
@@ -2086,6 +2091,69 @@ export async function executeTool(name, args, context = {}) {
2086
2091
  ruleAllowed = true;
2087
2092
  }
2088
2093
 
2094
+ // MCP annotations are peer-provided hints, never execution authority. A
2095
+ // server that claims readOnlyHint=true therefore still needs a request-level
2096
+ // approval unless the host independently authorized this exact tool as a
2097
+ // trusted read. An explicit settings allow can suppress the default prompt,
2098
+ // but it cannot suppress a host-owned `ask`/requiresConfirmation decision.
2099
+ // Plan mode has already applied its stricter hard ceiling above, so this gate
2100
+ // covers normal interactive/Auto execution without creating a Plan escape.
2101
+ if (localToolExecutor?.kind === "mcp") {
2102
+ const mcpEffectContract = mcpLedgerEffectContract(
2103
+ localToolDescriptor,
2104
+ hostToolPolicy,
2105
+ );
2106
+ const trustedHostRead =
2107
+ mcpEffectContract.effect === McpEffect.READ &&
2108
+ mcpEffectContract.trusted === true;
2109
+ const settingsAskWasConfirmed =
2110
+ settingsVerdict.decision === "ask" && ruleAllowed;
2111
+ const hostRequiresConfirmation =
2112
+ !settingsAskWasConfirmed &&
2113
+ (hostToolPolicy?.requiresConfirmation === true ||
2114
+ hostToolPolicy?.decision === "ask");
2115
+ const defaultRequiresConfirmation = !trustedHostRead && !ruleAllowed;
2116
+
2117
+ if (hostRequiresConfirmation || defaultRequiresConfirmation) {
2118
+ const approved = await requestInteractivePermission(
2119
+ name,
2120
+ args,
2121
+ context,
2122
+ cwd,
2123
+ {
2124
+ tool: name,
2125
+ args,
2126
+ rule: null,
2127
+ reason: hostRequiresConfirmation
2128
+ ? "host policy requires confirmation for this MCP tool"
2129
+ : `MCP effect is ${mcpEffectContract.effect} and lacks a trusted host read authorization`,
2130
+ source: hostRequiresConfirmation
2131
+ ? "host-managed MCP policy"
2132
+ : "MCP effect contract",
2133
+ mcpEffect: mcpEffectContract.effect,
2134
+ mcpTrusted: mcpEffectContract.trusted === true,
2135
+ },
2136
+ );
2137
+ if (!approved) {
2138
+ return {
2139
+ error: `[MCP Permission] Tool "${name}" requires confirmation because its effect is ${mcpEffectContract.effect} and it does not have an applicable trusted host read authorization — denied.`,
2140
+ policy: {
2141
+ decision: "ask",
2142
+ via: hostRequiresConfirmation
2143
+ ? "host-mcp-policy"
2144
+ : "mcp-effect-contract",
2145
+ code: "CC_MCP_EFFECT_CONFIRMATION_REQUIRED",
2146
+ effect: mcpEffectContract.effect,
2147
+ trusted: mcpEffectContract.trusted === true,
2148
+ },
2149
+ };
2150
+ }
2151
+ // The approval is scoped to this request and also satisfies the later
2152
+ // generic external-tool/ApprovalGate prompt for the same invocation.
2153
+ ruleAllowed = true;
2154
+ }
2155
+ }
2156
+
2089
2157
  // Sensitive-file write guard (Claude-Code 2.1.160 parity): shell startup
2090
2158
  // files / PowerShell profiles / git+husky hooks execute code on the user's
2091
2159
  // next shell or commit — even otherwise-permitted edit flows confirm first.
@@ -3319,11 +3387,18 @@ function mcpLedgerEffectContract(descriptor, hostPolicy) {
3319
3387
  )
3320
3388
  ? descriptorContract.declaredEffect
3321
3389
  : "unknown";
3390
+ // Host authority may raise an unknown/read declaration to a stricter effect,
3391
+ // but it may never downgrade the conservative peer risk floor. In
3392
+ // particular, an accidentally stale host `read` policy cannot turn a newly
3393
+ // declared write/destructive tool into a trusted read.
3322
3394
  const effect =
3323
- authorizedEffect ||
3324
- (declaredEffect === "destructive" || declaredEffect === "write"
3325
- ? declaredEffect
3326
- : "unknown");
3395
+ declaredEffect === "destructive" || authorizedEffect === "destructive"
3396
+ ? "destructive"
3397
+ : declaredEffect === "write" || authorizedEffect === "write"
3398
+ ? "write"
3399
+ : declaredEffect === "unknown"
3400
+ ? "unknown"
3401
+ : authorizedEffect || "unknown";
3327
3402
  const annotations = descriptorContract.annotations || {};
3328
3403
 
3329
3404
  return {
@@ -3341,7 +3416,15 @@ function mcpLedgerEffectContract(descriptor, hostPolicy) {
3341
3416
  : null,
3342
3417
  trusted:
3343
3418
  authorizedEffect != null &&
3344
- (hostContract.trusted === true || hostPolicy?.sourceTrusted === true),
3419
+ (hostContract.trusted === true || hostPolicy?.sourceTrusted === true) &&
3420
+ // Trust is valid only when the host authorization is at least as strict
3421
+ // as the merged effect. A stale host `read` classification cannot lend
3422
+ // trust to a server that now declares write/destructive behavior.
3423
+ authorizedEffect === effect &&
3424
+ // Trusted-read execution/parallelism requires the intersection promised
3425
+ // by the roadmap: a server read declaration plus host authorization.
3426
+ // An unmarked tool stays untrusted even when a host policy predicts read.
3427
+ (effect !== "read" || declaredEffect === "read"),
3345
3428
  source:
3346
3429
  hostContract.provenance ||
3347
3430
  descriptorContract.provenance ||
@@ -0,0 +1,143 @@
1
+ import { performance } from "node:perf_hooks";
2
+
3
+ const HOST_CLEANUP_DEADLINE_MS = 10_000;
4
+ const SAFE_ERROR_CODE = /^[A-Z][A-Z0-9_]{0,63}$/;
5
+
6
+ function projectedErrorCode(error) {
7
+ if (!error) return null;
8
+ return typeof error.code === "string" && SAFE_ERROR_CODE.test(error.code)
9
+ ? error.code
10
+ : "CC_CLEANUP_STEP_FAILED";
11
+ }
12
+
13
+ export function normalizeCleanupDeadlineMs(value) {
14
+ return Number.isFinite(value) &&
15
+ value > 0 &&
16
+ value <= HOST_CLEANUP_DEADLINE_MS
17
+ ? Math.max(1, Math.floor(value))
18
+ : HOST_CLEANUP_DEADLINE_MS;
19
+ }
20
+
21
+ export function cleanupDeadlineError(report) {
22
+ const error = new Error(
23
+ `CLI cleanup exceeded the host deadline of ${report.timeoutMs} ms`,
24
+ );
25
+ error.code = "CC_CLEANUP_DEADLINE_EXCEEDED";
26
+ error.isCleanupDeadlineFailure = true;
27
+ error.timeoutMs = report.timeoutMs;
28
+ error.timedOutSteps = report.steps
29
+ .filter((step) => step.status === "timeout")
30
+ .map((step) => step.name);
31
+ error.cleanupReport = report;
32
+ return error;
33
+ }
34
+
35
+ /**
36
+ * One host-owned absolute deadline shared by a cleanup sequence. Operations
37
+ * are invoked in order. If an operation consumes the remaining budget, later
38
+ * disposers are still invoked (and observed) but are not awaited, so one
39
+ * uncooperative adapter cannot prevent exhaustive teardown from starting.
40
+ */
41
+ export function createCleanupDeadline(
42
+ { timeoutMs, label = "cli-cleanup" } = {},
43
+ deps = {},
44
+ ) {
45
+ // A wall-clock adjustment must never extend teardown past the host ceiling.
46
+ const now = deps.now || (() => performance.now());
47
+ const setTimer = deps.setTimeout || setTimeout;
48
+ const clearTimer = deps.clearTimeout || clearTimeout;
49
+ const normalizedTimeoutMs = normalizeCleanupDeadlineMs(timeoutMs);
50
+ let startedAt = null;
51
+ let deadlineAt = null;
52
+ let exhausted = false;
53
+ const steps = [];
54
+
55
+ const ensureStarted = () => {
56
+ if (startedAt !== null) return;
57
+ startedAt = now();
58
+ deadlineAt = startedAt + normalizedTimeoutMs;
59
+ };
60
+
61
+ const record = (name, status, stepStartedAt, error = null) => {
62
+ steps.push(
63
+ Object.freeze({
64
+ name,
65
+ status,
66
+ durationMs: Math.max(0, now() - stepStartedAt),
67
+ errorCode: projectedErrorCode(error),
68
+ }),
69
+ );
70
+ };
71
+
72
+ return {
73
+ async run(name, operation) {
74
+ if (typeof name !== "string" || name.length === 0) {
75
+ throw new TypeError("cleanup step name is required");
76
+ }
77
+ if (typeof operation !== "function") {
78
+ record(name, "skipped", now());
79
+ return { status: "skipped" };
80
+ }
81
+ ensureStarted();
82
+ const stepStartedAt = now();
83
+ let promise;
84
+ try {
85
+ promise = Promise.resolve(operation());
86
+ } catch (error) {
87
+ record(name, "error", stepStartedAt, error);
88
+ return { status: "error", error };
89
+ }
90
+ // Always observe a late rejection after a timeout.
91
+ promise.catch(() => {});
92
+ const remainingMs = Math.max(0, deadlineAt - now());
93
+ if (exhausted || remainingMs === 0) {
94
+ exhausted = true;
95
+ record(name, "timeout", stepStartedAt);
96
+ return { status: "timeout" };
97
+ }
98
+
99
+ let timer = null;
100
+ const timeout = new Promise((resolve) => {
101
+ timer = setTimer(() => resolve({ timeout: true }), remainingMs);
102
+ });
103
+ const settled = await Promise.race([
104
+ promise.then(
105
+ (value) => ({ value }),
106
+ (error) => ({ error }),
107
+ ),
108
+ timeout,
109
+ ]);
110
+ if (timer !== null) clearTimer(timer);
111
+ if (settled?.timeout) {
112
+ // A platform timer can fire fractionally before performance.now()
113
+ // reaches deadlineAt. Latch exhaustion so later disposers are still
114
+ // invoked but never regain a sliver of cleanup budget.
115
+ exhausted = true;
116
+ record(name, "timeout", stepStartedAt);
117
+ return { status: "timeout" };
118
+ }
119
+ if (settled?.error) {
120
+ record(name, "error", stepStartedAt, settled.error);
121
+ return { status: "error", error: settled.error };
122
+ }
123
+ record(name, "completed", stepStartedAt);
124
+ return { status: "completed", value: settled.value };
125
+ },
126
+ report() {
127
+ const finishedAt = now();
128
+ const timedOut = steps.some((step) => step.status === "timeout");
129
+ return Object.freeze({
130
+ label,
131
+ timeoutMs: normalizedTimeoutMs,
132
+ startedAt,
133
+ finishedAt,
134
+ elapsedMs: startedAt === null ? 0 : Math.max(0, finishedAt - startedAt),
135
+ timedOut,
136
+ completed: !timedOut,
137
+ steps: Object.freeze([...steps]),
138
+ });
139
+ },
140
+ };
141
+ }
142
+
143
+ export const MAX_CLI_CLEANUP_DEADLINE_MS = HOST_CLEANUP_DEADLINE_MS;