chainlesschain 0.162.179 → 0.162.181

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 (251) hide show
  1. package/package.json +6 -3
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-BF13YdB-.js → AIOps-cq0dwbnf.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-B9y67AjF.js → ActionButton-CvcgGl3w.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-FcdDHoSC.js → Analytics-hM2-jFqg.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-CRm_zwSp.js → AppLayout-B9_Gsd_g.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-Cbo7-usf.js → Artifacts-B7bu52Og.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-vMaLpkHC.js → Audit-DThfDgqB.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-FiUY692t.js → BackgroundAgents-DjlFiD4v.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-BK80j_GQ.js → Backup-CK9xJKnG.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-ChNMuYR1.js → BaseInput-DEiSU8K8.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-928UREpm.js → Chat-CpT96czj.js} +5 -5
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-BKPPNmZI.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-dFW-zDbe.js → Checkbox-C1GfDnO0.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-BCcNJUj2.js → Codegen-3DAKgiLx.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-DcEkLv70.js → Col-74cOwZU1.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-DihBRRqg.js → Community-tn9Kkz9j.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-DGYxwWET.js → Compact-BcoXH7m4.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-OnYe1vS4.js → Compliance-DIPGUBgi.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-CmWB54c2.js → Cowork-doD5_91c.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-BrANb2uw.js → Cron-C-IDvubz.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-2HgWzSxg.js → Crosschain-CdcCoBdj.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-DdDwNI6K.js → DID-DdH5aMMA.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-D6PnE78-.js → Dashboard-DHLA4mm0.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-ClzvSN4O.js → Dropdown-dEeCt7Md.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-BUk9B727.js → EmailListRenderer-BMaecFv9.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-C8hi3v7i.js → FamilyGuardDashboard-DUaUukTN.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-B5SP8xkg.js → Federation-CMBE0_rp.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-DWzJ8AU5.js → FormItemContext-PG-JDbXq.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-3E3Q3rjG.js → GenericCardRenderer-Bcb0p88m.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-z8IdCMId.js → Git-Bgv15myB.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-CgqCF9lX.js → Governance-DB8YTArI.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-zgS-AuH9.js → Inference-BQMwCWaS.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-BdbgmESJ.js → KnowledgeGraph-B1_ZziiB.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-BHpknnjy.js → Logs-DovEEnt_.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-D201OL4T.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-Di9sAR7j.js → Marketplace-BlCXSpyB.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-DtnR9Z_A.js → McpTools-CsCR09Wj.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-BaX9uuXD.js → Memory-CBVRLKno.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-xelyKWTY.js → MobileBridge-C9OIafgA.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-BiFTOGBN.js → MobileProjects-D_zoJ8Xs.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-bV3OzTiO.js → Mtc-vE-HdvLj.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-BkwvFTdZ.js → MtcAudit-CPLaekCd.js} +2 -2
  44. package/src/assets/web-panel/assets/{Multisig-_6HQQ-oC.js → Multisig-C_UP9C2o.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-BBYhmWQZ.js → NLProgramming-2nODJcU1.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-Cq-6dQnU.js → Notes-BhE-SJGu.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-ILZ9zkX6.js → NotificationSettings-D21q7BNU.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-DgmTBEvk.js → OrderTableRenderer-0b62GYOD.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-CkLnWwCk.js → Organization-CEqmw_sb.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-CWVHZbhf.js → Overflow-MW-gMDO_.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-BXbqETkr.js → P2P-CY0hjI_G.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser--0JR-0ex.js → PdhVaultBrowser-BbWh7Man.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-Cz9_tfSy.js → Permissions-ChqEA_4Q.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-Dq7OWYtx.js → PersonalDataHub-B3YrbYfD.js} +5 -5
  55. package/src/assets/web-panel/assets/{Pipeline-DHPUNcc-.js → Pipeline-B8WBhhlW.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-CEAbrDkS.js → Privacy-Cmb0PXNx.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-CJYfclXE.js → ProjectInit-hF6zW3Nz.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-oCTgPCgp.js → ProjectSettings-BFSVfpW0.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-DAWkVFkc.js +1 -0
  60. package/src/assets/web-panel/assets/{Providers-BLTZtzTG.js → Providers-B8yux8Dx.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-C0b0TQB3.js → QrScannerModal-N76cQluO.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-tOl6N_gM.js → QuickAsk-ClvZ0KYR.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-DPzKr8yr.js → Recommend-B-GfgBpT.js} +1 -1
  64. package/src/assets/web-panel/assets/RemoteSession-mlglCdQi.js +5 -0
  65. package/src/assets/web-panel/assets/{Reputation-Cji1Vl79.js → Reputation-DJIZzQeG.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-D-NERWf2.js → Row-COzxu_bb.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-DzlgmAlB.js → RssFeed-CoYsJQuE.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-Cs0SWSa4.js → Search-DC77Mq9S.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-DL7EzcUO.js → Security-Loy2EdMO.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-CT-PzgTd.js → Services-GUD07Eu0.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-tByJWdJg.js → Skeleton-DWzkptYU.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-Dnr_6TTl.js → Skills-CEDn1r-Z.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-4O-yq0LY.js → Sla-ub_k4pXh.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-BYBVg1oR.js → SpeechSettings-D7HLX9CA.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-CpOYPbE5.js → SyncSettings-DbwOvl6m.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-CGVhOVh6.js → Tasks-CBQzoAu5.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-BuHFxR4X.js → Templates-BNVeIhud.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-DxDxHzgf.js → Tenant-PS9AzhXU.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-B9g_nISg.js → Terminal-Cgb4eLB_.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-DlrBC_4A.js → TimelineRenderer-CrmXMOkg.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-DvBlYZ6i.js → Tokens-DD-VDHw1.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-Dg8G9bhF.js → Trigger-BsoN_n-n.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-COICx4E-.js → Trust-n8LmN4ZV.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-B4pOBv7T.js → UkeySign-C9_7MImA.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-Qt4NMA8Q.js → VideoEditing-DyBteNgn.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-X1EkQc2Z.js → Wallet-BS5ixeXI.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-CyeEFBE5.js → WebAuthn-spc4UImU.js} +3 -3
  88. package/src/assets/web-panel/assets/{WorkflowEditor-nwzbMiVQ.js → WorkflowEditor-D7iVvaBO.js} +1 -1
  89. package/src/assets/web-panel/assets/chat-6CmBkHrL.js +1 -0
  90. package/src/assets/web-panel/assets/{colors-5Isz5lhJ.js → colors-BGoCLkxI.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-DsFQS3Oy.js → compact-item-fYZBetMO.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-OcEXp2uz.js → createContext-BeM-1UVj.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-BzPwHnw8.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-CZvC4p09.js → hasIn-CE7ZuEnV.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BF1sab0Q.js → index--lap6cf7.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-C7yeL3rf.js → index-ATcSr_2O.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-VkFXA9N-.js → index-B2U-ObMq.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DSmGGg5h.js → index-B3CDgvNW.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-jrNIrpq4.js → index-B4wiTEOM.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-B8ibl7bc.js → index-B8BsdNV_.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DOLozRk8.js → index-BEVm0lCS.js} +10 -10
  102. package/src/assets/web-panel/assets/{index-BPgc_bdR.js → index-BNZDILcO.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BTZZzlMO.js → index-BU_2qiDk.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Vubi6Tf5.js → index-BV551878.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-nXrnztXp.js → index-BfPL-m46.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CN8lPVpQ.js → index-BowH1eLQ.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BgE2BZl2.js → index-BsMfoaeo.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Cd5b2JHB.js → index-BunaQCa0.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CQlGw0nQ.js → index-C0v6YKKO.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Do6FJK32.js → index-C4SJVjs4.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Bqvo1f9T.js → index-C9Y3k0HI.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-LUdgPZg9.js → index-CIpVrf5P.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BpD2O7_p.js → index-CRLjEP1H.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-r_9NG6P7.js → index-CRnUE8Cb.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-FIgMAfBh.js → index-Cip8emOQ.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-RsQ1lFDV.js → index-CpIGIB85.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DGJupV0S.js → index-D1r9tT3J.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BpglwPWl.js → index-DT3zPSVX.js} +1 -1
  119. package/src/assets/web-panel/assets/index-DacrAdc-.js +1 -0
  120. package/src/assets/web-panel/assets/{index-CG3B2wCF.js → index-De0quFDw.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CxA2PDK1.js → index-DoXk5KJ8.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DaGKOVvQ.js → index-DsvfrESp.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-C7CtJYXq.js → index-Dw1PyYPm.js} +1 -1
  124. package/src/assets/web-panel/assets/index-EHzNJozo.js +1 -0
  125. package/src/assets/web-panel/assets/{index-Bu9NXvIa.js → index-MtOuq2i6.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BsZkTaa3.js → index-Puq6Luf1.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CPE4zHXF.js → index-QIpnpZgz.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Bsb-iylv.js → index-RMZ8a7Yt.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DMtGRQqw.js → index-WUrJ6S1j.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-C3lWvhk4.js → index-YjcumOZ4.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CmVbCGx_.js → index-lJBjB1QX.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-A5SHQW_M.js → index-ukg99D1V.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-CFJgt6qM.js → index-zb7rVOhV.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-Cdgep9YT.js → initDefaultProps-CYHMs1ag.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-7yn1ACEm.js → motion-DDB2Ffk5.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-D8o133Xc.js → move-Bg3cD-dX.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-CClHIG9V.js → mtc-parser-B5nedjTS.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-CLnrPE2d.js → omit-BHyuUILu.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-1CTWoZWl.js → pickAttrs-C9YQnEN9.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-xNNtS4Sp.js → placementArrow-DBUFYUe7.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-ypzAofs7.js → responsiveObserve-nBs2Obnk.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-QsrY9UwD.js → slide-DkCEaXNU.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-DSdThzOB.js → statusUtils-aqE1Wi6U.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-B_kKM8Ob.js → styleChecker-CN5bhfHB.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-CcdTBNV9.js → useFlexGapSupport-B_oX_kvJ.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-BuAH2XFU.js → useFs-rCuXHeme.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-B3zWiG4A.js → usePersonalDataHub-DZR9Abyd.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-B45Rc-CQ.js → vnode-ConCYQlX.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-DaYZDU5f.js → zoom-CUdDxG5M.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/commands/agent.js +4 -1
  152. package/src/commands/background-session.js +2 -1
  153. package/src/commands/context.js +69 -2
  154. package/src/commands/hub.js +30 -24
  155. package/src/data/changelog.json +27 -1
  156. package/src/gateways/ws/background-agent-protocol.js +38 -0
  157. package/src/gateways/ws/message-dispatcher.js +1 -0
  158. package/src/gateways/ws/remote-session-protocol.js +65 -6
  159. package/src/gateways/ws/ws-server.js +8 -1
  160. package/src/harness/feature-flags.js +15 -8
  161. package/src/harness/mcp-client.js +618 -43
  162. package/src/lazy-dispatch.js +30 -1
  163. package/src/lib/agent-authority.js +22 -0
  164. package/src/lib/agent-core.js +2 -0
  165. package/src/lib/agent-sandbox.js +161 -0
  166. package/src/lib/agent-team/team-runner.js +22 -0
  167. package/src/lib/artifact-store.js +35 -0
  168. package/src/lib/async-hook-supervisor.cjs +13 -2
  169. package/src/lib/audit-mtc.js +3 -2
  170. package/src/lib/background-agent-supervisor.js +104 -3
  171. package/src/lib/background-interaction-journal.js +407 -0
  172. package/src/lib/background-interaction-resolver.js +23 -34
  173. package/src/lib/background-session-transport.js +12 -2
  174. package/src/lib/capability-manifest.js +41 -3
  175. package/src/lib/capability-negotiation.js +1 -1
  176. package/src/lib/channels/channel-manager.js +33 -0
  177. package/src/lib/channels/telegram-channel.js +23 -5
  178. package/src/lib/channels/webhook-channel.js +38 -15
  179. package/src/lib/chrome-connector.js +169 -23
  180. package/src/lib/config-manager.js +23 -9
  181. package/src/lib/context-breakdown.js +31 -0
  182. package/src/lib/cowork-cron.js +274 -32
  183. package/src/lib/cross-chain-mtc.js +3 -2
  184. package/src/lib/durable-security-store.js +124 -0
  185. package/src/lib/event-runtime-host.js +67 -6
  186. package/src/lib/event-runtime-store.js +163 -0
  187. package/src/lib/goal-store.js +32 -12
  188. package/src/lib/headless-manifest.js +2 -1
  189. package/src/lib/hook-environment.cjs +58 -0
  190. package/src/lib/hook-manager.js +12 -5
  191. package/src/lib/hook-runner.cjs +122 -28
  192. package/src/lib/hook-runner.js +1 -0
  193. package/src/lib/hooks-v2-producers.js +36 -0
  194. package/src/lib/hooks-v2-runtime.js +329 -52
  195. package/src/lib/interaction-adapter.js +60 -19
  196. package/src/lib/interaction-binding.js +64 -0
  197. package/src/lib/json-schema-output.js +439 -14
  198. package/src/lib/json-schema-validate.js +514 -883
  199. package/src/lib/lan-pairing-tokens.js +115 -57
  200. package/src/lib/lsp/__tests__/lsp-client.test.js +32 -0
  201. package/src/lib/lsp/__tests__/lsp-manager.test.js +25 -0
  202. package/src/lib/lsp/lsp-client.js +4 -0
  203. package/src/lib/lsp/lsp-manager.js +3 -0
  204. package/src/lib/lsp/lsp-server-registry.js +18 -0
  205. package/src/lib/mcp-client.js +1 -0
  206. package/src/lib/mcp-oauth.js +35 -21
  207. package/src/lib/packer/pkg-config-generator.js +1 -0
  208. package/src/lib/permission-decision.js +99 -0
  209. package/src/lib/plugin-monitor-supervisor.js +3 -0
  210. package/src/lib/plugin-runtime/capabilities.js +50 -0
  211. package/src/lib/plugin-runtime/capability-consent.js +42 -35
  212. package/src/lib/plugin-runtime/hooks.js +36 -9
  213. package/src/lib/plugin-runtime/install.js +23 -7
  214. package/src/lib/plugin-runtime/lsp.js +4 -0
  215. package/src/lib/plugin-runtime/manifest.js +50 -2
  216. package/src/lib/plugin-runtime/mcp.js +30 -5
  217. package/src/lib/plugin-runtime/monitors.js +11 -0
  218. package/src/lib/plugin-runtime/plugin-options.js +94 -38
  219. package/src/lib/plugin-runtime/policy.js +29 -2
  220. package/src/lib/plugin-runtime/sandbox-policy.js +84 -0
  221. package/src/lib/plugin-runtime/scopes.js +7 -3
  222. package/src/lib/plugin-runtime/trust.js +36 -31
  223. package/src/lib/process-execution-broker/credential-agent.js +114 -16
  224. package/src/lib/process-execution-broker/credential-transport-worker.js +312 -0
  225. package/src/lib/process-execution-broker/credential-transport.js +378 -0
  226. package/src/lib/process-execution-broker/index.js +408 -19
  227. package/src/lib/process-execution-broker/platform-sandbox.js +561 -21
  228. package/src/lib/process-execution-broker/windows-sandbox.ps1 +999 -0
  229. package/src/lib/project-mcp-trust.js +21 -26
  230. package/src/lib/protocol-replay.js +19 -12
  231. package/src/lib/settings-hooks.cjs +13 -0
  232. package/src/lib/skill-loader.js +83 -10
  233. package/src/lib/sync-credentials.js +5 -4
  234. package/src/lib/turn-binding.js +8 -6
  235. package/src/repl/agent-repl.js +113 -28
  236. package/src/repl/repl-turn-binding.js +5 -2
  237. package/src/runtime/agent-core.js +331 -26
  238. package/src/runtime/coding-agent-contract-shared.cjs +3 -3
  239. package/src/runtime/headless-runner.js +101 -4
  240. package/src/runtime/headless-stream.js +209 -23
  241. package/src/runtime/mcp-config.js +29 -17
  242. package/src/runtime/policies/agent-policy.js +2 -0
  243. package/src/workers/background-agent-worker.js +128 -13
  244. package/src/assets/web-panel/assets/ChatBubbleRenderer-DvySUzxJ.js +0 -1
  245. package/src/assets/web-panel/assets/MarkdownRenderer-DkxCweb1.js +0 -1
  246. package/src/assets/web-panel/assets/Projects-ClomCrN0.js +0 -1
  247. package/src/assets/web-panel/assets/RemoteSession-pRgaWsUK.js +0 -4
  248. package/src/assets/web-panel/assets/chat-Bvl-ojg2.js +0 -1
  249. package/src/assets/web-panel/assets/devWarning-CSVgo71Z.js +0 -1
  250. package/src/assets/web-panel/assets/index-DMIWh9fu.js +0 -1
  251. package/src/assets/web-panel/assets/index-ssTvV1l6.js +0 -1
@@ -1,5 +1,6 @@
1
1
  /**
2
- * Hooks v2 System — M3-1: 完整18事件schema + 5executor类型
2
+ * Hooks v2 System — 40-event schema + 5 public executor types
3
+ * (plus trusted programmatic `js` compatibility handlers).
3
4
  * 对应文档 §2.3
4
5
  *
5
6
  * 支持的18种生命周期事件:
@@ -24,9 +25,14 @@ import crypto from "node:crypto";
24
25
  import fs from "node:fs/promises";
25
26
  import path from "node:path";
26
27
  import broker from "./process-execution-broker/index.js";
28
+ import hookEnvironment from "./hook-environment.cjs";
29
+ import permissionRules from "./permission-rules.cjs";
27
30
  import { EventRuntimeStore } from "./event-runtime-store.js";
28
31
  import { getDefaultEventRuntimeHost } from "./event-runtime-host.js";
29
32
 
33
+ const { globToRegExp } = permissionRules;
34
+ const { buildManagedHookEnvironment } = hookEnvironment;
35
+
30
36
  const VALID_HOOK_EVENTS = new Set([
31
37
  "Setup",
32
38
  // Session
@@ -106,20 +112,6 @@ export const HOOK_EVENT_CONTRACTS = Object.freeze(
106
112
  ),
107
113
  );
108
114
 
109
- const SAFE_ENV_KEYS = Object.freeze([
110
- "PATH",
111
- "PATHEXT",
112
- "SystemRoot",
113
- "WINDIR",
114
- "COMSPEC",
115
- "TMP",
116
- "TEMP",
117
- "TMPDIR",
118
- "LANG",
119
- "LC_ALL",
120
- "HOME",
121
- "USERPROFILE",
122
- ]);
123
115
  const DECISION_RANK = Object.freeze({
124
116
  continue: 0,
125
117
  allow: 1,
@@ -154,26 +146,209 @@ function hostnameMatches(hostname, pattern) {
154
146
  return host === rule;
155
147
  }
156
148
 
157
- function buildHookEnvironment(hook, policy) {
158
- const env = {};
159
- for (const key of SAFE_ENV_KEYS) {
160
- if (process.env[key] != null) env[key] = process.env[key];
149
+ function managedListAllows(value, configured) {
150
+ if (!Array.isArray(configured)) return true;
151
+ const candidate = String(value || "");
152
+ return configured.some((entry) => {
153
+ const pattern = String(entry || "").trim();
154
+ if (!pattern) return false;
155
+ if (pattern === "*") return true;
156
+ const expression = globToRegExp(
157
+ process.platform === "win32" ? pattern.toLowerCase() : pattern,
158
+ );
159
+ return expression.test(
160
+ process.platform === "win32" ? candidate.toLowerCase() : candidate,
161
+ );
162
+ });
163
+ }
164
+
165
+ function isInsideManagedRoot(candidate, roots) {
166
+ if (!Array.isArray(roots)) return true;
167
+ const resolved = path.resolve(candidate);
168
+ return roots.some((root) => {
169
+ const managedRoot = path.resolve(String(root));
170
+ const relative = path.relative(managedRoot, resolved);
171
+ return (
172
+ relative === "" ||
173
+ (!relative.startsWith("..") && !path.isAbsolute(relative))
174
+ );
175
+ });
176
+ }
177
+
178
+ function managedPolicyError(message) {
179
+ const error = new Error(message);
180
+ error.code = "CC_HOOK_MANAGED_POLICY_DENIED";
181
+ return error;
182
+ }
183
+
184
+ /**
185
+ * Merge the administrator policy with a hook's own requested sandbox. Managed
186
+ * settings may strengthen a hook but a hook cannot remove managed boundaries.
187
+ * Boundary identifiers are intentionally left for ProcessExecutionBroker to
188
+ * validate so every external-process caller gets the same stable contract.
189
+ */
190
+ export function resolveHookSandboxPolicy(hook = {}, managedPolicy = {}) {
191
+ const hookPolicy = hook.sandboxPolicy;
192
+ const administratorPolicy = managedPolicy.sandboxPolicy;
193
+ for (const [label, value] of [
194
+ ["hook sandboxPolicy", hookPolicy],
195
+ ["managed hook sandboxPolicy", administratorPolicy],
196
+ ]) {
197
+ if (
198
+ value !== undefined &&
199
+ (value === null || typeof value !== "object" || Array.isArray(value))
200
+ ) {
201
+ throw managedPolicyError(`${label} must be an object`);
202
+ }
161
203
  }
162
- const managed = new Set(
163
- (policy.environmentAllowlist || []).map((key) => String(key)),
164
- );
165
- const requested = new Set(
166
- (hook.environmentAllowlist || hook.envAllowlist || []).map((key) =>
167
- String(key),
168
- ),
169
- );
170
- for (const key of requested) {
171
- if (!managed.has(key) || process.env[key] == null) continue;
172
- env[key] = process.env[key];
204
+
205
+ const requiredBoundaries = [];
206
+ for (const [label, value] of [
207
+ ["managed requiredBoundaries", managedPolicy.requiredBoundaries],
208
+ [
209
+ "managed sandboxPolicy.requiredBoundaries",
210
+ administratorPolicy?.requiredBoundaries,
211
+ ],
212
+ ["hook requiredBoundaries", hook.requiredBoundaries],
213
+ ["hook sandboxPolicy.requiredBoundaries", hookPolicy?.requiredBoundaries],
214
+ ]) {
215
+ if (value === undefined) continue;
216
+ if (!Array.isArray(value)) {
217
+ throw managedPolicyError(`${label} must be an array`);
218
+ }
219
+ for (const boundary of value) {
220
+ if (!requiredBoundaries.includes(boundary)) {
221
+ requiredBoundaries.push(boundary);
222
+ }
223
+ }
224
+ }
225
+
226
+ const configured =
227
+ hookPolicy !== undefined ||
228
+ administratorPolicy !== undefined ||
229
+ hook.requiredBoundaries !== undefined ||
230
+ managedPolicy.requiredBoundaries !== undefined;
231
+ if (!configured) return null;
232
+ const resolved = {
233
+ ...(hookPolicy || {}),
234
+ ...(administratorPolicy || {}),
235
+ };
236
+ delete resolved.requiredBoundaries;
237
+ if (requiredBoundaries.length > 0) {
238
+ resolved.requiredBoundaries = requiredBoundaries;
239
+ }
240
+ return resolved;
241
+ }
242
+
243
+ export function assertManagedHookPolicy(
244
+ hook,
245
+ context = {},
246
+ policy = {},
247
+ configDir = null,
248
+ ) {
249
+ if (!managedListAllows(hook.type, policy.allowedExecutors)) {
250
+ throw managedPolicyError(
251
+ `Hook executor is outside the managed allowlist: ${hook.type}`,
252
+ );
253
+ }
254
+
255
+ if (hook.type === "command") {
256
+ if (hook.shell === true && policy.allowShell !== true) {
257
+ throw managedPolicyError(
258
+ "Shell-mode command hooks are disabled by managed policy",
259
+ );
260
+ }
261
+ const executable = String(hook.command || "");
262
+ const commandCandidates = new Set([
263
+ executable,
264
+ path.basename(executable),
265
+ ]);
266
+ if (
267
+ Array.isArray(policy.commandAllowlist) &&
268
+ ![...commandCandidates].some((value) =>
269
+ managedListAllows(value, policy.commandAllowlist),
270
+ )
271
+ ) {
272
+ throw managedPolicyError(
273
+ `Hook command is outside the managed allowlist: ${executable}`,
274
+ );
275
+ }
276
+ const cwd = hook.cwd || context.cwd || configDir || process.cwd();
277
+ if (!isInsideManagedRoot(cwd, policy.workspaceRoots)) {
278
+ throw managedPolicyError(
279
+ `Hook working directory is outside managed workspace roots: ${cwd}`,
280
+ );
281
+ }
282
+ }
283
+
284
+ if (hook.type === "mcp_tool") {
285
+ const target = `${hook.server || ""}/${hook.tool || ""}`;
286
+ if (!managedListAllows(target, policy.mcpToolAllowlist)) {
287
+ throw managedPolicyError(
288
+ `MCP hook target is outside the managed allowlist: ${target}`,
289
+ );
290
+ }
291
+ }
292
+
293
+ if (
294
+ hook.type === "agent" &&
295
+ hook.agentName &&
296
+ !managedListAllows(hook.agentName, policy.agentAllowlist)
297
+ ) {
298
+ throw managedPolicyError(
299
+ `Hook agent is outside the managed allowlist: ${hook.agentName}`,
300
+ );
301
+ }
302
+ if (
303
+ hook.type === "agent" &&
304
+ hook.skillName &&
305
+ !managedListAllows(hook.skillName, policy.skillAllowlist)
306
+ ) {
307
+ throw managedPolicyError(
308
+ `Hook skill is outside the managed allowlist: ${hook.skillName}`,
309
+ );
310
+ }
311
+ }
312
+
313
+ export function fileChangedHookMatches(hook, context = {}) {
314
+ const configured =
315
+ hook?.globs ?? hook?.paths ?? hook?.glob ?? hook?.if ?? null;
316
+ if (configured == null) return true;
317
+ const patterns = (Array.isArray(configured) ? configured : [configured])
318
+ .map((value) => String(value || "").trim().replace(/\\/g, "/"))
319
+ .filter(Boolean);
320
+ if (patterns.length === 0) return true;
321
+
322
+ const rawPath = String(context.path || "").replace(/\\/g, "/");
323
+ if (!rawPath) return false;
324
+ const candidates = new Set([rawPath.replace(/^\.\//, "")]);
325
+ if (path.isAbsolute(rawPath)) {
326
+ const relative = path
327
+ .relative(context.cwd || process.cwd(), rawPath)
328
+ .replace(/\\/g, "/");
329
+ if (relative && !relative.startsWith("../")) candidates.add(relative);
173
330
  }
174
- env.CC_HOOK_EVENT = hook.event;
175
- env.CC_HOOK_SCHEMA_VERSION = String(HOOK_EVENT_SCHEMA_VERSION);
176
- return env;
331
+ const caseInsensitive = process.platform === "win32";
332
+ return patterns.some((pattern) => {
333
+ const normalizedPattern = pattern.replace(/^\.\//, "");
334
+ const expression = globToRegExp(
335
+ caseInsensitive ? normalizedPattern.toLowerCase() : normalizedPattern,
336
+ );
337
+ return [...candidates].some((candidate) =>
338
+ expression.test(caseInsensitive ? candidate.toLowerCase() : candidate),
339
+ );
340
+ });
341
+ }
342
+
343
+ function buildHookEnvironment(hook, policy) {
344
+ return buildManagedHookEnvironment({
345
+ managedAllowlist: policy.environmentAllowlist,
346
+ requestedAllowlist: hook.environmentAllowlist || hook.envAllowlist,
347
+ values: {
348
+ CC_HOOK_EVENT: hook.event,
349
+ CC_HOOK_SCHEMA_VERSION: HOOK_EVENT_SCHEMA_VERSION,
350
+ },
351
+ });
177
352
  }
178
353
 
179
354
  function hookBudget(hook) {
@@ -190,6 +365,29 @@ function hookBudget(hook) {
190
365
  });
191
366
  }
192
367
 
368
+ async function executeWithHookTimeout(label, budget, executor) {
369
+ const controller = new AbortController();
370
+ let timer;
371
+ const timeout = new Promise((_, reject) => {
372
+ timer = setTimeout(() => {
373
+ controller.abort();
374
+ const error = new Error(
375
+ `${label} hook exceeded its ${budget.timeoutMs}ms budget`,
376
+ );
377
+ error.code = "CC_HOOK_BUDGET_EXCEEDED";
378
+ reject(error);
379
+ }, budget.timeoutMs);
380
+ });
381
+ try {
382
+ return await Promise.race([
383
+ Promise.resolve().then(() => executor(controller.signal)),
384
+ timeout,
385
+ ]);
386
+ } finally {
387
+ clearTimeout(timer);
388
+ }
389
+ }
390
+
193
391
  class HooksV2Runtime extends EventEmitter {
194
392
  constructor(configDir, options = {}) {
195
393
  super();
@@ -210,9 +408,15 @@ class HooksV2Runtime extends EventEmitter {
210
408
  ...(options.promptExecutor ? { prompt: options.promptExecutor } : {}),
211
409
  ...(options.agentExecutor ? { agent: options.agentExecutor } : {}),
212
410
  };
411
+ this.mcpAuthorizer =
412
+ typeof options.mcpAuthorizer === "function"
413
+ ? options.mcpAuthorizer
414
+ : null;
213
415
  this.managedPolicy = {
214
416
  httpAllowlist: [],
215
417
  environmentAllowlist: [],
418
+ allowShell: false,
419
+ requireMcpAuthorization: true,
216
420
  ...(options.managedPolicy || {}),
217
421
  };
218
422
  this.hooks = new Map(); // eventName -> HookDefinition[]
@@ -243,6 +447,8 @@ class HooksV2Runtime extends EventEmitter {
243
447
  * @property {boolean} [blocking] - default false
244
448
  * @property {string[]} [if] - conditional matchers
245
449
  * @property {string} [description]
450
+ * @property {{profile?:string, requiredBoundaries?:string[]}} [sandboxPolicy]
451
+ * @property {string[]} [requiredBoundaries]
246
452
  */
247
453
 
248
454
  async loadHooks(hooksPath) {
@@ -315,7 +521,10 @@ class HooksV2Runtime extends EventEmitter {
315
521
  throw new Error(`Invalid hook event: ${eventName}`);
316
522
  }
317
523
 
318
- const hooks = this.hooks.get(eventName) || [];
524
+ const hooks = (this.hooks.get(eventName) || []).filter(
525
+ (hook) =>
526
+ eventName !== "FileChanged" || fileChangedHookMatches(hook, context),
527
+ );
319
528
  // Reserve the durable record for the inline producer before executing any
320
529
  // hook. A process-level EventRuntimeHost may observe the same store, but it
321
530
  // cannot reclaim this record until the longest declared hook timeout plus
@@ -371,6 +580,12 @@ class HooksV2Runtime extends EventEmitter {
371
580
  const record = { execId, hookId: hook.id, event: eventName, type: hook.type, startedAt: new Date() };
372
581
 
373
582
  try {
583
+ assertManagedHookPolicy(
584
+ hook,
585
+ context,
586
+ this.managedPolicy,
587
+ this.configDir,
588
+ );
374
589
  let result;
375
590
  switch (hook.type) {
376
591
  case "command":
@@ -474,6 +689,10 @@ class HooksV2Runtime extends EventEmitter {
474
689
  throw new Error("command hook requires a command");
475
690
  }
476
691
  const budget = hookBudget(hook);
692
+ const sandboxPolicy = resolveHookSandboxPolicy(
693
+ hook,
694
+ this.managedPolicy,
695
+ );
477
696
  const child = await this.executionBroker.spawn(
478
697
  hook.command,
479
698
  hook.args || [],
@@ -487,6 +706,7 @@ class HooksV2Runtime extends EventEmitter {
487
706
  scope: "hook",
488
707
  policy: "allow",
489
708
  hookName: hook.id,
709
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
490
710
  },
491
711
  );
492
712
  const payload = JSON.stringify({
@@ -561,12 +781,22 @@ class HooksV2Runtime extends EventEmitter {
561
781
  if (typeof executor !== "function") {
562
782
  throw new Error("prompt hook executor is not configured");
563
783
  }
564
- return executor({
784
+ const budget = hookBudget(hook);
785
+ const sandboxPolicy = resolveHookSandboxPolicy(
565
786
  hook,
566
- prompt: expanded,
567
- context,
568
- budget: hookBudget(hook),
569
- });
787
+ this.managedPolicy,
788
+ );
789
+ return executeWithHookTimeout("prompt", budget, (signal) =>
790
+ executor({
791
+ hook,
792
+ prompt: expanded,
793
+ context,
794
+ budget,
795
+ signal,
796
+ managedPolicy: this.managedPolicy,
797
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
798
+ }),
799
+ );
570
800
  }
571
801
 
572
802
  async _execAgent(hook, context) {
@@ -574,13 +804,23 @@ class HooksV2Runtime extends EventEmitter {
574
804
  if (typeof executor !== "function") {
575
805
  throw new Error("agent hook executor is not configured");
576
806
  }
577
- return executor({
807
+ const budget = hookBudget(hook);
808
+ const sandboxPolicy = resolveHookSandboxPolicy(
578
809
  hook,
579
- agentName: hook.agentName || null,
580
- skillName: hook.skillName || null,
581
- context,
582
- budget: hookBudget(hook),
583
- });
810
+ this.managedPolicy,
811
+ );
812
+ return executeWithHookTimeout("agent", budget, (signal) =>
813
+ executor({
814
+ hook,
815
+ agentName: hook.agentName || null,
816
+ skillName: hook.skillName || null,
817
+ context,
818
+ budget,
819
+ signal,
820
+ managedPolicy: this.managedPolicy,
821
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
822
+ }),
823
+ );
584
824
  }
585
825
 
586
826
  async _execMcpTool(hook, context) {
@@ -591,14 +831,51 @@ class HooksV2Runtime extends EventEmitter {
591
831
  if (!hook.server || !hook.tool) {
592
832
  throw new Error("mcp_tool hook requires server and tool");
593
833
  }
594
- return executor({
595
- server: hook.server,
596
- tool: hook.tool,
597
- arguments: hook.arguments || context,
598
- context,
834
+ let permission = null;
835
+ if (this.managedPolicy.requireMcpAuthorization !== false) {
836
+ if (!this.mcpAuthorizer) {
837
+ throw managedPolicyError(
838
+ "MCP hook requires the shared MCP permission authorizer",
839
+ );
840
+ }
841
+ permission = await this.mcpAuthorizer({
842
+ server: hook.server,
843
+ tool: hook.tool,
844
+ arguments: hook.arguments || context,
845
+ context,
846
+ hook,
847
+ });
848
+ const decision = String(permission?.decision || "").toLowerCase();
849
+ if (
850
+ permission !== true &&
851
+ permission?.allowed !== true &&
852
+ decision !== "allow" &&
853
+ decision !== "approve"
854
+ ) {
855
+ throw managedPolicyError(
856
+ `MCP hook permission denied: ${hook.server}/${hook.tool}`,
857
+ );
858
+ }
859
+ }
860
+ const budget = hookBudget(hook);
861
+ const sandboxPolicy = resolveHookSandboxPolicy(
599
862
  hook,
600
- budget: hookBudget(hook),
601
- });
863
+ this.managedPolicy,
864
+ );
865
+ return executeWithHookTimeout("mcp_tool", budget, (signal) =>
866
+ executor({
867
+ server: hook.server,
868
+ tool: hook.tool,
869
+ arguments: hook.arguments || context,
870
+ context,
871
+ hook,
872
+ budget,
873
+ signal,
874
+ permission,
875
+ managedPolicy: this.managedPolicy,
876
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
877
+ }),
878
+ );
602
879
  }
603
880
 
604
881
  async _execJs(hook, context) {
@@ -16,6 +16,10 @@ import {
16
16
  import { createAbortError } from "./abort-utils.js";
17
17
  import { emitHooksV2Event } from "./hooks-v2-producers.js";
18
18
  import { verifyApprovalBinding } from "./agent-authority.js";
19
+ import {
20
+ normalizeInteractionBinding,
21
+ sameInteractionBinding,
22
+ } from "./interaction-binding.js";
19
23
  import { createEnvelope } from "@chainlesschain/session-core";
20
24
 
21
25
  // Phase 5: parallel service-envelope emission. Map WS agent-handler event
@@ -128,6 +132,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
128
132
  // this WS session instead of leaking across sessions via the process-
129
133
  // global default tracker.
130
134
  this._sequenceTracker = new CodingAgentSequenceTracker();
135
+ this._questionSequence = 0;
131
136
  // Phase 5: parallel service-envelope emission. Opt-in (default off) so
132
137
  // legacy callers that count ws.send invocations stay green.
133
138
  this.enablePhase5Envelopes = options.enablePhase5Envelopes === true;
@@ -175,6 +180,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
175
180
  // routed / argument-tampered verdict and is rejected in _resolvePending.
176
181
  // null (the default for plain questions) → no binding check, unchanged.
177
182
  binding: options.binding || null,
183
+ bindingType: options.bindingType || null,
178
184
  });
179
185
 
180
186
  this._sendWs({
@@ -274,6 +280,12 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
274
280
  }
275
281
  : {}),
276
282
  };
283
+ const binding = normalizeInteractionBinding({
284
+ sessionId: this.sessionId,
285
+ turnId: normalizedTurnId,
286
+ toolUseId: normalizedToolUseId,
287
+ sequence: ++this._questionSequence,
288
+ });
277
289
 
278
290
  return this._request(
279
291
  {
@@ -295,10 +307,13 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
295
307
  tool_use_id: normalizedToolUseId,
296
308
  }
297
309
  : {}),
310
+ binding,
298
311
  metadata: questionMetadata,
299
312
  },
300
313
  {
301
314
  kind: "question",
315
+ binding,
316
+ bindingType: "interaction",
302
317
  ...(Number(timeoutMs) > 0 ? { timeoutMs: Number(timeoutMs) } : {}),
303
318
  },
304
319
  );
@@ -324,30 +339,48 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
324
339
  requestedSchema = null,
325
340
  timeoutMs,
326
341
  } = {}) {
327
- emitHooksV2Event("MCPElicitation", {
342
+ const hookContext = {
343
+ schema_version: 1,
328
344
  server: server || null,
329
345
  request_id: mcpRequestId ?? null,
330
346
  message: String(message),
331
347
  requested_schema: requestedSchema || null,
332
- });
333
- return this._request(
334
- {
335
- type: "question",
336
- questionType: "elicitation",
337
- question: String(message),
338
- ...(requestedSchema ? { requestedSchema } : {}),
339
- metadata: {
340
- kind: "mcp_elicitation",
341
- server: server || null,
342
- requestId: mcpRequestId ?? null,
343
- requestedSchema: requestedSchema || null,
348
+ session_id: this.sessionId || null,
349
+ };
350
+ emitHooksV2Event("MCPElicitation", hookContext);
351
+ emitHooksV2Event("Elicitation", hookContext);
352
+ try {
353
+ const answer = await this._request(
354
+ {
355
+ type: "question",
356
+ questionType: "elicitation",
357
+ question: String(message),
358
+ ...(requestedSchema ? { requestedSchema } : {}),
359
+ metadata: {
360
+ kind: "mcp_elicitation",
361
+ server: server || null,
362
+ requestId: mcpRequestId ?? null,
363
+ requestedSchema: requestedSchema || null,
364
+ },
344
365
  },
345
- },
346
- {
347
- kind: "question",
348
- ...(Number(timeoutMs) > 0 ? { timeoutMs: Number(timeoutMs) } : {}),
349
- },
350
- );
366
+ {
367
+ kind: "question",
368
+ ...(Number(timeoutMs) > 0 ? { timeoutMs: Number(timeoutMs) } : {}),
369
+ },
370
+ );
371
+ emitHooksV2Event("ElicitationResult", {
372
+ ...hookContext,
373
+ action: answer == null ? "cancel" : "accept",
374
+ });
375
+ return answer;
376
+ } catch (error) {
377
+ emitHooksV2Event("ElicitationResult", {
378
+ ...hookContext,
379
+ action: "cancel",
380
+ reason: error?.code || error?.message || "interaction_failed",
381
+ });
382
+ throw error;
383
+ }
351
384
  }
352
385
 
353
386
  async requestHostTool(toolName, args = {}, extra = {}) {
@@ -484,8 +517,16 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
484
517
  // (fail closed) instead of the approve it claims to be, mirroring the local
485
518
  // headless approval gate. Backward-compatible: no request binding, or an
486
519
  // answer with no echoed binding, resolves exactly as before.
520
+ if (
521
+ pending.bindingType === "interaction" &&
522
+ !sameInteractionBinding(pending.binding, incomingBinding)
523
+ ) {
524
+ return;
525
+ }
526
+
487
527
  let effective = payload;
488
528
  if (
529
+ pending.bindingType !== "interaction" &&
489
530
  pending.binding &&
490
531
  incomingBinding &&
491
532
  !verifyApprovalBinding(pending.binding, incomingBinding)
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Transport-neutral binding for a human interaction response.
3
+ *
4
+ * The binding is intentionally plain JSON so CLI attach, WebSocket, Desktop,
5
+ * VS Code, JetBrains, SDK and Remote Control can echo the same value without
6
+ * reinterpreting it. The runtime that created the request remains authoritative
7
+ * and compares every field before accepting a response.
8
+ */
9
+
10
+ function asNullableString(value) {
11
+ if (value === undefined || value === null || value === "") return null;
12
+ return String(value);
13
+ }
14
+
15
+ export function normalizeInteractionBinding(binding = {}) {
16
+ const source =
17
+ binding && typeof binding === "object" && !Array.isArray(binding)
18
+ ? binding
19
+ : {};
20
+ return {
21
+ backgroundAgentId: asNullableString(
22
+ source.backgroundAgentId ?? source.background_agent_id,
23
+ ),
24
+ sessionId: asNullableString(source.sessionId ?? source.session_id),
25
+ turnId: asNullableString(source.turnId ?? source.turn_id),
26
+ toolUseId: asNullableString(
27
+ source.toolUseId ??
28
+ source.tool_use_id ??
29
+ source.toolCallId ??
30
+ source.tool_call_id,
31
+ ),
32
+ sequence:
33
+ Number.isSafeInteger(source.sequence) && source.sequence > 0
34
+ ? source.sequence
35
+ : null,
36
+ };
37
+ }
38
+
39
+ export function sameInteractionBinding(left, right) {
40
+ const a = normalizeInteractionBinding(left);
41
+ const b = normalizeInteractionBinding(right);
42
+ return (
43
+ a.backgroundAgentId === b.backgroundAgentId &&
44
+ a.sessionId === b.sessionId &&
45
+ a.turnId === b.turnId &&
46
+ a.toolUseId === b.toolUseId &&
47
+ a.sequence === b.sequence
48
+ );
49
+ }
50
+
51
+ export function hasCompleteInteractionBinding(binding) {
52
+ if (!binding || typeof binding !== "object" || Array.isArray(binding)) {
53
+ return false;
54
+ }
55
+ const hasAny = (...keys) =>
56
+ keys.some((key) => Object.prototype.hasOwnProperty.call(binding, key));
57
+ return (
58
+ hasAny("backgroundAgentId", "background_agent_id") &&
59
+ hasAny("sessionId", "session_id") &&
60
+ hasAny("turnId", "turn_id") &&
61
+ hasAny("toolUseId", "tool_use_id", "toolCallId", "tool_call_id") &&
62
+ normalizeInteractionBinding(binding).sequence !== null
63
+ );
64
+ }