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
@@ -56,6 +56,16 @@ const HTTP_REQUEST_TIMEOUT_MS = 30000;
56
56
  * hard 30s regardless of its config — an inconsistency with HTTP servers.
57
57
  */
58
58
  const STDIO_REQUEST_TIMEOUT_MS = 30000;
59
+ const MCP_PROTOCOL_VERSION = "2025-11-25";
60
+ const URL_ELICITATION_REQUIRED = -32042;
61
+
62
+ function supportsUrlElicitationVersion(version) {
63
+ const normalized = String(version || "");
64
+ return (
65
+ /^\d{4}-\d{2}-\d{2}$/.test(normalized) &&
66
+ normalized >= MCP_PROTOCOL_VERSION
67
+ );
68
+ }
59
69
 
60
70
  /**
61
71
  * Infer the transport kind for a server config. Falls back to "stdio".
@@ -85,6 +95,75 @@ export function inferTransport(config) {
85
95
  return "stdio";
86
96
  }
87
97
 
98
+ function mcpRpcError(payload = {}) {
99
+ const error = new Error(payload.message || "Unknown MCP error");
100
+ if (payload.code !== undefined) error.code = payload.code;
101
+ if (payload.data !== undefined) error.data = payload.data;
102
+ return error;
103
+ }
104
+
105
+ export function normalizeMcpElicitationRequest(
106
+ serverName,
107
+ requestId,
108
+ params = {},
109
+ ) {
110
+ const mode = params.mode == null ? "form" : String(params.mode);
111
+ const message = String(params.message || "").trim();
112
+ if (!message) {
113
+ const error = new Error("MCP elicitation requires a non-empty message");
114
+ error.code = "CC_MCP_ELICITATION_INVALID";
115
+ throw error;
116
+ }
117
+ const base = {
118
+ ...params,
119
+ mode,
120
+ message,
121
+ server: String(serverName),
122
+ requestId,
123
+ };
124
+ if (mode === "form") return base;
125
+ if (mode !== "url") {
126
+ const error = new Error(`Unsupported MCP elicitation mode: ${mode}`);
127
+ error.code = "CC_MCP_ELICITATION_INVALID";
128
+ throw error;
129
+ }
130
+
131
+ const elicitationId = String(params.elicitationId || "").trim();
132
+ if (!elicitationId) {
133
+ const error = new Error(
134
+ "URL mode MCP elicitation requires elicitationId",
135
+ );
136
+ error.code = "CC_MCP_ELICITATION_INVALID";
137
+ throw error;
138
+ }
139
+ let target;
140
+ try {
141
+ target = new URL(String(params.url || ""));
142
+ } catch {
143
+ const error = new Error("URL mode MCP elicitation requires a valid URL");
144
+ error.code = "CC_MCP_ELICITATION_INVALID";
145
+ throw error;
146
+ }
147
+ if (
148
+ target.protocol !== "https:" ||
149
+ target.username ||
150
+ target.password ||
151
+ !target.hostname
152
+ ) {
153
+ const error = new Error(
154
+ "URL mode MCP elicitation requires credential-free HTTPS",
155
+ );
156
+ error.code = "CC_MCP_ELICITATION_INVALID";
157
+ throw error;
158
+ }
159
+ return {
160
+ ...base,
161
+ elicitationId,
162
+ url: target.href,
163
+ urlHost: target.host,
164
+ };
165
+ }
166
+
88
167
  /** True for transports that talk over HTTP(S) — i.e. use fetch. */
89
168
  export function isHttpTransport(transportKind) {
90
169
  return (
@@ -182,6 +261,14 @@ export class MCPClient extends EventEmitter {
182
261
  ? Number(options.elicitationTimeoutMs)
183
262
  : 180000;
184
263
  this._pendingElicitations = new Map();
264
+ this._urlElicitations = new Map();
265
+ this._activeElicitations = 0;
266
+ this._maxConcurrentElicitations =
267
+ Number(options.maxConcurrentElicitations) > 0
268
+ ? Math.min(128, Number(options.maxConcurrentElicitations))
269
+ : 32;
270
+ this._protocolVersion =
271
+ String(options.protocolVersion || MCP_PROTOCOL_VERSION);
185
272
  this._runtimeProducer = options.eventRuntimeStore
186
273
  ? new EventRuntimeProducer({ store: options.eventRuntimeStore, emitter: this })
187
274
  : null;
@@ -201,6 +288,11 @@ export class MCPClient extends EventEmitter {
201
288
  if (Number(options.timeoutMs) > 0) {
202
289
  this._elicitationTimeoutMs = Number(options.timeoutMs);
203
290
  }
291
+ if (typeof handler === "function") {
292
+ for (const name of this.servers.keys()) {
293
+ this._ensureHttpMessageStream(name);
294
+ }
295
+ }
204
296
  }
205
297
 
206
298
  /** Run an async agent turn with a session-scoped elicitation route. */
@@ -223,11 +315,15 @@ export class MCPClient extends EventEmitter {
223
315
  const key = this._elicitationKey(serverName, requestId);
224
316
  const pending = this._pendingElicitations.get(key);
225
317
  if (!pending) return false;
226
- pending.resolve(this._normalizeElicitationResponse(response));
318
+ const normalized = this._normalizeElicitationResponse(
319
+ response,
320
+ pending.request,
321
+ );
322
+ pending.resolve(normalized);
227
323
  try {
228
324
  this._runtimeProducer?.store.acknowledgeInbox(
229
325
  `mcp-elicitation:${this._elicitationKey(serverName, requestId)}`,
230
- { response: this._normalizeElicitationResponse(response) },
326
+ { response: normalized },
231
327
  );
232
328
  } catch {}
233
329
  return true;
@@ -244,27 +340,82 @@ export class MCPClient extends EventEmitter {
244
340
  return `${String(serverName)}:${String(requestId)}`;
245
341
  }
246
342
 
247
- _normalizeElicitationResponse(response) {
343
+ _normalizeElicitationResponse(response, request = null) {
248
344
  const action = String(response?.action || "decline").toLowerCase();
249
345
  const safeAction = new Set(["accept", "decline", "cancel"]).has(action)
250
346
  ? action
251
347
  : "decline";
252
348
  const normalized = { action: safeAction };
253
- if (safeAction === "accept" && response?.content !== undefined) {
349
+ if (
350
+ safeAction === "accept" &&
351
+ request?.mode !== "url" &&
352
+ response?.content !== undefined
353
+ ) {
254
354
  normalized.content = response.content;
255
355
  }
256
356
  return normalized;
257
357
  }
258
358
 
259
359
  async _resolveElicitation(serverName, requestId, params = {}) {
360
+ if (this._activeElicitations >= this._maxConcurrentElicitations) {
361
+ const request = normalizeMcpElicitationRequest(
362
+ serverName,
363
+ requestId,
364
+ params,
365
+ );
366
+ this.emit("elicitation-deferred", {
367
+ ...request,
368
+ reason: "capacity_exceeded",
369
+ wireAction: "decline",
370
+ });
371
+ return { action: "decline" };
372
+ }
373
+ this._activeElicitations += 1;
374
+ try {
375
+ return await this._resolveElicitationWithin(
376
+ serverName,
377
+ requestId,
378
+ params,
379
+ );
380
+ } finally {
381
+ this._activeElicitations -= 1;
382
+ }
383
+ }
384
+
385
+ async _resolveElicitationWithin(serverName, requestId, params = {}) {
260
386
  const key = this._elicitationKey(serverName, requestId);
387
+ const request = normalizeMcpElicitationRequest(
388
+ serverName,
389
+ requestId,
390
+ params,
391
+ );
392
+ const negotiatedVersion =
393
+ this.servers.get(String(serverName))?.protocolVersion;
394
+ if (
395
+ request.mode === "url" &&
396
+ negotiatedVersion &&
397
+ !supportsUrlElicitationVersion(negotiatedVersion)
398
+ ) {
399
+ const error = new Error(
400
+ `URL elicitation is unavailable under MCP ${negotiatedVersion}`,
401
+ );
402
+ error.code = "CC_MCP_ELICITATION_INVALID";
403
+ throw error;
404
+ }
405
+ if (request.mode === "url") this._rememberUrlElicitation(request);
261
406
  try {
262
407
  this._runtimeProducer?.publish(
263
- { type: "mcp_elicitation", server: serverName, requestId, params },
408
+ {
409
+ type: "mcp_elicitation",
410
+ server: serverName,
411
+ requestId,
412
+ params: request,
413
+ },
264
414
  { origin: "mcp", id: `mcp-elicitation:${key}` },
265
415
  );
266
416
  } catch (error) {
267
417
  this.emit("elicitation-error", { server: serverName, requestId, error });
418
+ this._settleUrlElicitation(request, { action: "cancel" });
268
419
  return { action: "cancel" };
269
420
  }
270
421
  const contextSessionId = this._elicitationContext.getStore();
@@ -274,12 +425,17 @@ export class MCPClient extends EventEmitter {
274
425
  if (handler) {
275
426
  try {
276
427
  const direct = await handler({
277
- server: serverName,
278
- requestId,
279
- ...params,
428
+ ...request,
280
429
  });
281
- if (direct !== undefined) {
282
- const response = this._normalizeElicitationResponse(direct);
430
+ if (
431
+ direct !== undefined &&
432
+ String(direct?.action || "").toLowerCase() !== "defer"
433
+ ) {
434
+ const response = this._normalizeElicitationResponse(
435
+ direct,
436
+ request,
437
+ );
438
+ this._settleUrlElicitation(request, response);
283
439
  try {
284
440
  this._runtimeProducer?.store.acknowledgeInbox(
285
441
  `mcp-elicitation:${key}`,
@@ -294,6 +450,7 @@ export class MCPClient extends EventEmitter {
294
450
  requestId,
295
451
  error,
296
452
  });
453
+ this._settleUrlElicitation(request, { action: "cancel" });
297
454
  return { action: "cancel" };
298
455
  }
299
456
  }
@@ -308,12 +465,19 @@ export class MCPClient extends EventEmitter {
308
465
  { response: { action: "decline" } },
309
466
  );
310
467
  } catch {}
468
+ this._settleUrlElicitation(request, { action: "decline" });
469
+ this.emit("elicitation-deferred", {
470
+ ...request,
471
+ reason: "no_interactive_host",
472
+ wireAction: "decline",
473
+ });
311
474
  return { action: "decline" };
312
475
  }
313
476
  return new Promise((resolve) => {
314
477
  const timeout = setTimeout(() => {
315
478
  this._pendingElicitations.delete(key);
316
479
  this.emit("elicitation-timeout", { server: serverName, requestId });
480
+ this._settleUrlElicitation(request, { action: "cancel" });
317
481
  try {
318
482
  this._runtimeProducer?.store.fail(
319
483
  "inbox",
@@ -326,22 +490,128 @@ export class MCPClient extends EventEmitter {
326
490
  }, this._elicitationTimeoutMs);
327
491
  timeout.unref?.();
328
492
  this._pendingElicitations.set(key, {
493
+ request,
329
494
  resolve: (response) => {
330
495
  clearTimeout(timeout);
331
496
  this._pendingElicitations.delete(key);
332
- resolve(this._normalizeElicitationResponse(response));
497
+ const normalized = this._normalizeElicitationResponse(
498
+ response,
499
+ request,
500
+ );
501
+ this._settleUrlElicitation(request, normalized);
502
+ resolve(normalized);
333
503
  },
334
504
  });
335
505
  this.emit("elicitation-request", {
336
- server: serverName,
337
- requestId,
338
- ...params,
506
+ ...request,
339
507
  respond: (response) => this.respondElicitation(serverName, requestId, response),
340
508
  cancel: () => this.cancelElicitation(serverName, requestId),
341
509
  });
342
510
  });
343
511
  }
344
512
 
513
+ _rememberUrlElicitation(request) {
514
+ const id = request?.elicitationId;
515
+ if (!id) return;
516
+ const existing = this._urlElicitations.get(id);
517
+ if (existing && existing.server !== request.server) {
518
+ throw new Error(
519
+ `MCP URL elicitation id collision across servers: ${id}`,
520
+ );
521
+ }
522
+ if (existing && existing.request?.url !== request.url) {
523
+ throw new Error(
524
+ `MCP URL elicitation id reused with a different URL: ${id}`,
525
+ );
526
+ }
527
+ if (!existing) {
528
+ this._urlElicitations.set(id, {
529
+ id,
530
+ server: request.server,
531
+ request,
532
+ status: "pending",
533
+ completionNotified: false,
534
+ waiters: new Set(),
535
+ });
536
+ while (this._urlElicitations.size > 1000) {
537
+ this._urlElicitations.delete(this._urlElicitations.keys().next().value);
538
+ }
539
+ }
540
+ }
541
+
542
+ _settleUrlElicitation(request, response) {
543
+ if (request?.mode !== "url" || !request.elicitationId) return;
544
+ const entry = this._urlElicitations.get(request.elicitationId);
545
+ if (!entry || entry.status === "completed") return;
546
+ entry.status =
547
+ response?.action === "accept" ? "accepted" : response?.action || "decline";
548
+ if (entry.status === "accepted" && entry.completionNotified) {
549
+ this._completeUrlElicitation(entry);
550
+ }
551
+ if (entry.status !== "accepted") {
552
+ for (const waiter of entry.waiters) waiter(false);
553
+ entry.waiters.clear();
554
+ }
555
+ this.emit("elicitation-url-response", {
556
+ server: request.server,
557
+ elicitationId: request.elicitationId,
558
+ action: response?.action || "decline",
559
+ url: request.url,
560
+ urlHost: request.urlHost,
561
+ });
562
+ }
563
+
564
+ _handleElicitationComplete(serverName, params = {}) {
565
+ const elicitationId = String(params.elicitationId || "");
566
+ const entry = this._urlElicitations.get(elicitationId);
567
+ if (!entry || entry.server !== String(serverName)) {
568
+ return false;
569
+ }
570
+ if (entry.status === "completed") return false;
571
+ if (entry.status === "pending") {
572
+ // A fast out-of-band flow can finish while the host is still returning
573
+ // its explicit consent result. Remember the notification, but do not
574
+ // mark it complete until that consent has resolved to `accept`.
575
+ entry.completionNotified = true;
576
+ return true;
577
+ }
578
+ if (entry.status !== "accepted") return false;
579
+ this._completeUrlElicitation(entry);
580
+ return true;
581
+ }
582
+
583
+ _completeUrlElicitation(entry) {
584
+ if (!entry || entry.status === "completed") return;
585
+ entry.status = "completed";
586
+ for (const waiter of entry.waiters) waiter(true);
587
+ entry.waiters.clear();
588
+ this.emit("elicitation-complete", {
589
+ server: entry.server,
590
+ elicitationId: entry.id,
591
+ });
592
+ }
593
+
594
+ waitForElicitationCompletion(elicitationId, timeoutMs) {
595
+ const entry = this._urlElicitations.get(String(elicitationId));
596
+ if (!entry) return Promise.resolve(false);
597
+ if (entry.status === "completed") return Promise.resolve(true);
598
+ if (entry.status !== "accepted") return Promise.resolve(false);
599
+ const waitMs =
600
+ Number(timeoutMs) > 0 ? Number(timeoutMs) : this._elicitationTimeoutMs;
601
+ return new Promise((resolve) => {
602
+ let settled = false;
603
+ const finish = (value) => {
604
+ if (settled) return;
605
+ settled = true;
606
+ clearTimeout(timer);
607
+ entry.waiters.delete(finish);
608
+ resolve(value);
609
+ };
610
+ const timer = setTimeout(() => finish(false), waitMs);
611
+ entry.waiters.add(finish);
612
+ });
613
+ }
614
+
345
615
  /**
346
616
  * Set (or clear) the agent session id advertised to stdio MCP servers. Only
347
617
  * servers connected *after* this call see the new value; already-spawned
@@ -457,6 +727,8 @@ export class MCPClient extends EventEmitter {
457
727
  httpUrl: null,
458
728
  httpHeaders: {},
459
729
  httpSessionId: null,
730
+ protocolVersion: null,
731
+ _httpMessageStream: null,
460
732
  tools: [],
461
733
  resources: [],
462
734
  prompts: [],
@@ -501,6 +773,9 @@ export class MCPClient extends EventEmitter {
501
773
  pluginId: config.pluginId,
502
774
  pluginVersion: config.pluginVersion,
503
775
  pluginSource: config.pluginSource,
776
+ ...(config.sandboxPolicy
777
+ ? { sandboxPolicy: config.sandboxPolicy }
778
+ : {}),
504
779
  });
505
780
 
506
781
  entry.process = proc;
@@ -574,11 +849,14 @@ export class MCPClient extends EventEmitter {
574
849
 
575
850
  // Initialize MCP protocol (retried on transient network errors).
576
851
  const initResult = await this._requestWithRetry(name, "initialize", {
577
- protocolVersion: "2024-11-05",
852
+ protocolVersion: this._protocolVersion,
578
853
  capabilities: {
579
854
  tools: {},
580
855
  resources: {},
581
856
  prompts: {},
857
+ elicitation: supportsUrlElicitationVersion(this._protocolVersion)
858
+ ? { form: {}, url: {} }
859
+ : { form: {} },
582
860
  // Client-side roots capability: servers may request roots/list and
583
861
  // subscribe to list_changed notifications (Claude-Code 2.1.203).
584
862
  roots: { listChanged: true },
@@ -586,6 +864,9 @@ export class MCPClient extends EventEmitter {
586
864
  clientInfo: { name: "chainlesschain-cli", version: "0.37.9" },
587
865
  });
588
866
 
867
+ entry.protocolVersion = String(
868
+ initResult?.protocolVersion || this._protocolVersion,
869
+ );
589
870
  // Send initialized notification
590
871
  this._sendNotification(name, "notifications/initialized", {});
591
872
 
@@ -649,6 +930,12 @@ export class MCPClient extends EventEmitter {
649
930
  tools: entry.tools.length,
650
931
  toolsError: entry.toolsError,
651
932
  });
933
+ if (
934
+ entry.httpUrl &&
935
+ (this._elicitationHandler || this._elicitationHandlers.size > 0)
936
+ ) {
937
+ this._ensureHttpMessageStream(name);
938
+ }
652
939
  return {
653
940
  name,
654
941
  state: entry.state,
@@ -700,12 +987,23 @@ export class MCPClient extends EventEmitter {
700
987
  if (entry.process) {
701
988
  entry.process.kill();
702
989
  }
990
+ if (entry._httpMessageStream) {
991
+ entry._httpMessageStream.stopped = true;
992
+ entry._httpMessageStream.controller?.abort();
993
+ entry._httpMessageStream.wake?.();
994
+ entry._httpMessageStream = null;
995
+ }
703
996
  // HTTP sessions: best-effort DELETE to free server-side state.
704
997
  if (entry.httpUrl && entry.httpSessionId) {
705
998
  try {
706
999
  await _deps.fetch(entry.httpUrl, {
707
1000
  method: "DELETE",
708
- headers: { "Mcp-Session-Id": entry.httpSessionId },
1001
+ headers: {
1002
+ ...(entry.httpHeaders || {}),
1003
+ "Mcp-Session-Id": entry.httpSessionId,
1004
+ "MCP-Protocol-Version":
1005
+ entry.protocolVersion || this._protocolVersion,
1006
+ },
709
1007
  });
710
1008
  } catch (_e) {
711
1009
  // ignore — disconnect is best-effort
@@ -778,6 +1076,13 @@ export class MCPClient extends EventEmitter {
778
1076
  try {
779
1077
  return await this._callToolOnce(serverName, toolName, args);
780
1078
  } catch (err) {
1079
+ if (
1080
+ err?.code === URL_ELICITATION_REQUIRED &&
1081
+ (await this._resolveRequiredUrlElicitations(serverName, err))
1082
+ ) {
1083
+ // Retry exactly once after every out-of-band flow reports completion.
1084
+ return this._callToolOnce(serverName, toolName, args);
1085
+ }
781
1086
  if (
782
1087
  !this._reconnectors.has(serverName) ||
783
1088
  !isLikelyConnectionError(err)
@@ -790,6 +1095,49 @@ export class MCPClient extends EventEmitter {
790
1095
  }
791
1096
  }
792
1097
 
1098
+ async _resolveRequiredUrlElicitations(serverName, error) {
1099
+ const requested = Array.isArray(error?.data?.elicitations)
1100
+ ? error.data.elicitations
1101
+ : [];
1102
+ if (requested.length === 0 || requested.length > 16) return false;
1103
+ const normalized = [];
1104
+ const ids = new Set();
1105
+ for (const params of requested) {
1106
+ let request;
1107
+ try {
1108
+ request = normalizeMcpElicitationRequest(
1109
+ serverName,
1110
+ `url-required:${params?.elicitationId || normalized.length}`,
1111
+ params,
1112
+ );
1113
+ } catch {
1114
+ return false;
1115
+ }
1116
+ if (request.mode !== "url" || ids.has(request.elicitationId)) return false;
1117
+ ids.add(request.elicitationId);
1118
+ normalized.push(request);
1119
+ }
1120
+ const accepted = [];
1121
+ for (const request of normalized) {
1122
+ const response = await this._resolveElicitation(
1123
+ serverName,
1124
+ request.requestId,
1125
+ request,
1126
+ );
1127
+ if (response.action !== "accept") return false;
1128
+ accepted.push(request);
1129
+ }
1130
+ const completed = await Promise.all(
1131
+ accepted.map((request) =>
1132
+ this.waitForElicitationCompletion(
1133
+ request.elicitationId,
1134
+ this._elicitationTimeoutMs,
1135
+ ),
1136
+ ),
1137
+ );
1138
+ return completed.every(Boolean);
1139
+ }
1140
+
793
1141
  async _callToolOnce(serverName, toolName, args) {
794
1142
  const entry = this.servers.get(serverName);
795
1143
  if (!entry) throw new Error(`Server "${serverName}" not found`);
@@ -1019,6 +1367,113 @@ export class MCPClient extends EventEmitter {
1019
1367
  }
1020
1368
  }
1021
1369
 
1370
+ /**
1371
+ * Open the optional Streamable HTTP GET/SSE channel used for asynchronous
1372
+ * server requests and notifications. Interactive hosts enable it when they
1373
+ * install an elicitation handler; stdio already has a bidirectional stream.
1374
+ */
1375
+ _ensureHttpMessageStream(serverName) {
1376
+ const entry = this.servers.get(serverName);
1377
+ if (
1378
+ !entry?.httpUrl ||
1379
+ entry.state !== ServerState.CONNECTED ||
1380
+ entry._httpMessageStream
1381
+ ) {
1382
+ return false;
1383
+ }
1384
+ const stream = {
1385
+ stopped: false,
1386
+ controller: null,
1387
+ lastEventId: null,
1388
+ retryMs: 1000,
1389
+ wake: null,
1390
+ promise: null,
1391
+ };
1392
+ entry._httpMessageStream = stream;
1393
+ stream.promise = (async () => {
1394
+ try {
1395
+ while (
1396
+ !stream.stopped &&
1397
+ this.servers.get(serverName) === entry
1398
+ ) {
1399
+ stream.controller =
1400
+ typeof AbortController === "function"
1401
+ ? new AbortController()
1402
+ : null;
1403
+ const headers = {
1404
+ Accept: "text/event-stream",
1405
+ ...(entry.httpHeaders || {}),
1406
+ ...(entry.httpSessionId
1407
+ ? { "Mcp-Session-Id": entry.httpSessionId }
1408
+ : {}),
1409
+ "MCP-Protocol-Version":
1410
+ entry.protocolVersion || this._protocolVersion,
1411
+ ...(stream.lastEventId
1412
+ ? { "Last-Event-ID": stream.lastEventId }
1413
+ : {}),
1414
+ };
1415
+ try {
1416
+ const response = await _deps.fetch(entry.httpUrl, {
1417
+ method: "GET",
1418
+ headers,
1419
+ ...(stream.controller
1420
+ ? { signal: stream.controller.signal }
1421
+ : {}),
1422
+ });
1423
+ if (response.status === 405) return;
1424
+ if (!response.ok) {
1425
+ throw new Error(
1426
+ `MCP HTTP message stream returned ${response.status}`,
1427
+ );
1428
+ }
1429
+ const contentType = response.headers?.get
1430
+ ? String(
1431
+ response.headers.get("content-type") || "",
1432
+ ).toLowerCase()
1433
+ : "";
1434
+ if (!contentType.includes("text/event-stream")) return;
1435
+ const cap = Number.isFinite(entry.config?.maxBufferChars)
1436
+ ? entry.config.maxBufferChars
1437
+ : MCP_MAX_BUFFER_CHARS;
1438
+ await _consumeSseMessageStream(response, {
1439
+ cap,
1440
+ stream,
1441
+ onMessage: (message) =>
1442
+ this._handleMessage(serverName, message),
1443
+ });
1444
+ } catch (error) {
1445
+ if (stream.stopped || stream.controller?.signal.aborted) return;
1446
+ this.emit("server-stream-error", {
1447
+ name: serverName,
1448
+ error: error?.message || String(error),
1449
+ });
1450
+ } finally {
1451
+ stream.controller = null;
1452
+ }
1453
+ if (stream.stopped) return;
1454
+ await new Promise((resolve) => {
1455
+ const delay = Math.max(
1456
+ 50,
1457
+ Math.min(30000, Number(stream.retryMs) || 1000),
1458
+ );
1459
+ const timer = setTimeout(resolve, delay);
1460
+ stream.wake = () => {
1461
+ clearTimeout(timer);
1462
+ resolve();
1463
+ };
1464
+ });
1465
+ stream.wake = null;
1466
+ }
1467
+ } finally {
1468
+ if (entry._httpMessageStream === stream) {
1469
+ entry._httpMessageStream = null;
1470
+ }
1471
+ }
1472
+ })();
1473
+ stream.promise.catch(() => {});
1474
+ return true;
1475
+ }
1476
+
1022
1477
  /**
1023
1478
  * Send a JSON-RPC request over HTTP (Streamable HTTP per MCP spec).
1024
1479
  * Accepts responses as either `application/json` or `text/event-stream`.
@@ -1040,6 +1495,10 @@ export class MCPClient extends EventEmitter {
1040
1495
  if (entry.httpSessionId) {
1041
1496
  headers["Mcp-Session-Id"] = entry.httpSessionId;
1042
1497
  }
1498
+ if (method !== "initialize") {
1499
+ headers["MCP-Protocol-Version"] =
1500
+ entry.protocolVersion || this._protocolVersion;
1501
+ }
1043
1502
 
1044
1503
  // Per-call timeout (parity with the 30s stdio timeout) so a hung or dead
1045
1504
  // HTTP MCP server can't block the request forever. Servers flagged
@@ -1105,7 +1564,12 @@ export class MCPClient extends EventEmitter {
1105
1564
 
1106
1565
  let envelope;
1107
1566
  if (contentType.includes("text/event-stream")) {
1108
- envelope = await _extractSseResponse(response, id, cap);
1567
+ envelope = await _extractSseResponse(
1568
+ response,
1569
+ id,
1570
+ cap,
1571
+ (message) => this._handleMessage(serverName, message),
1572
+ );
1109
1573
  } else {
1110
1574
  const text = await _readBodyCapped(response, cap);
1111
1575
  envelope = text ? JSON.parse(text) : null;
@@ -1115,7 +1579,7 @@ export class MCPClient extends EventEmitter {
1115
1579
  throw new Error("Empty or invalid JSON-RPC response");
1116
1580
  }
1117
1581
  if (envelope.error) {
1118
- throw new Error(envelope.error.message || "Unknown error");
1582
+ throw mcpRpcError(envelope.error);
1119
1583
  }
1120
1584
  return envelope.result;
1121
1585
  } catch (err) {
@@ -1143,6 +1607,8 @@ export class MCPClient extends EventEmitter {
1143
1607
  if (entry.httpSessionId) {
1144
1608
  headers["Mcp-Session-Id"] = entry.httpSessionId;
1145
1609
  }
1610
+ headers["MCP-Protocol-Version"] =
1611
+ entry.protocolVersion || this._protocolVersion;
1146
1612
  try {
1147
1613
  const p = _deps.fetch(entry.httpUrl, {
1148
1614
  method: "POST",
@@ -1220,7 +1686,7 @@ export class MCPClient extends EventEmitter {
1220
1686
  entry._pending.delete(msg.id);
1221
1687
 
1222
1688
  if (msg.error) {
1223
- reject(new Error(msg.error.message || "Unknown error"));
1689
+ reject(mcpRpcError(msg.error));
1224
1690
  } else {
1225
1691
  resolve(msg.result);
1226
1692
  }
@@ -1248,6 +1714,8 @@ export class MCPClient extends EventEmitter {
1248
1714
  this._refreshServerList(serverName, "tools");
1249
1715
  } else if (msg.method === "notifications/resources/list_changed") {
1250
1716
  this._refreshServerList(serverName, "resources");
1717
+ } else if (msg.method === "notifications/elicitation/complete") {
1718
+ this._handleElicitationComplete(serverName, msg.params || {});
1251
1719
  }
1252
1720
  this.emit("notification", {
1253
1721
  server: serverName,
@@ -1315,7 +1783,12 @@ export class MCPClient extends EventEmitter {
1315
1783
  if (method === "elicitation/create") {
1316
1784
  this._resolveElicitation(serverName, id, msg.params || {})
1317
1785
  .then((response) => this._sendResponse(serverName, id, response))
1318
- .catch(() => this._sendResponse(serverName, id, { action: "cancel" }));
1786
+ .catch((error) =>
1787
+ this._sendResponse(serverName, id, undefined, {
1788
+ code: -32602,
1789
+ message: error?.message || "invalid elicitation request",
1790
+ }),
1791
+ );
1319
1792
  return;
1320
1793
  }
1321
1794
  this._sendResponse(serverName, id, undefined, {
@@ -1324,19 +1797,47 @@ export class MCPClient extends EventEmitter {
1324
1797
  });
1325
1798
  }
1326
1799
 
1327
- /**
1328
- * Write a JSON-RPC response back to a stdio server. HTTP transports cannot
1329
- * deliver server-initiated requests to this client (no persistent SSE GET
1330
- * stream is held), so there is never a response to send there.
1331
- */
1800
+ /** Write a JSON-RPC response back over stdio or Streamable HTTP POST. */
1332
1801
  _sendResponse(serverName, id, result, error) {
1333
1802
  const entry = this.servers.get(serverName);
1334
- if (!entry || !entry.process) return;
1335
- const message = JSON.stringify(
1803
+ if (!entry) return;
1804
+ const envelope =
1336
1805
  error !== undefined
1337
1806
  ? { jsonrpc: "2.0", id, error }
1338
- : { jsonrpc: "2.0", id, result },
1339
- );
1807
+ : { jsonrpc: "2.0", id, result };
1808
+ if (entry.httpUrl) {
1809
+ const headers = {
1810
+ "Content-Type": "application/json",
1811
+ Accept: "application/json, text/event-stream",
1812
+ ...(entry.httpHeaders || {}),
1813
+ ...(entry.httpSessionId
1814
+ ? { "Mcp-Session-Id": entry.httpSessionId }
1815
+ : {}),
1816
+ "MCP-Protocol-Version":
1817
+ entry.protocolVersion || this._protocolVersion,
1818
+ };
1819
+ try {
1820
+ const pending = _deps.fetch(entry.httpUrl, {
1821
+ method: "POST",
1822
+ headers,
1823
+ body: JSON.stringify(envelope),
1824
+ });
1825
+ pending?.catch?.((cause) =>
1826
+ this.emit("server-stream-error", {
1827
+ name: serverName,
1828
+ error: cause?.message || String(cause),
1829
+ }),
1830
+ );
1831
+ } catch (cause) {
1832
+ this.emit("server-stream-error", {
1833
+ name: serverName,
1834
+ error: cause?.message || String(cause),
1835
+ });
1836
+ }
1837
+ return;
1838
+ }
1839
+ if (!entry.process) return;
1840
+ const message = JSON.stringify(envelope);
1340
1841
  try {
1341
1842
  entry.process.stdin.write(message + "\n");
1342
1843
  } catch {
@@ -1408,30 +1909,104 @@ async function _readBodyCapped(response, cap) {
1408
1909
  * `data:` chunks, comments, and non-JSON-RPC events. `cap` bounds the body
1409
1910
  * size (see _readBodyCapped).
1410
1911
  */
1411
- async function _extractSseResponse(response, requestId, cap = 0) {
1912
+ async function _extractSseResponse(
1913
+ response,
1914
+ requestId,
1915
+ cap = 0,
1916
+ onMessage = null,
1917
+ ) {
1412
1918
  const text = await _readBodyCapped(response, cap);
1413
1919
 
1414
1920
  // Split into events on blank line, parse each event's concatenated `data:` lines.
1415
1921
  const events = text.split(/\r?\n\r?\n/);
1416
1922
  for (const event of events) {
1417
- const dataLines = [];
1418
- for (const line of event.split(/\r?\n/)) {
1419
- if (line.startsWith(":")) continue; // comment
1420
- if (line.startsWith("data:")) {
1421
- dataLines.push(line.slice(5).replace(/^ /, ""));
1422
- }
1923
+ const parsed = _parseSseEvent(event);
1924
+ if (!parsed?.message) continue;
1925
+ const payload = parsed.message;
1926
+ if (payload.jsonrpc === "2.0" && payload.id === requestId) {
1927
+ return payload;
1928
+ }
1929
+ onMessage?.(payload);
1930
+ }
1931
+ throw new Error(`SSE stream ended without a response for id ${requestId}`);
1932
+ }
1933
+
1934
+ function _parseSseEvent(event) {
1935
+ const dataLines = [];
1936
+ let id = null;
1937
+ let retry = null;
1938
+ for (const line of String(event || "").split(/\r?\n/)) {
1939
+ if (line.startsWith(":")) continue;
1940
+ if (line.startsWith("data:")) {
1941
+ dataLines.push(line.slice(5).replace(/^ /, ""));
1942
+ } else if (line.startsWith("id:")) {
1943
+ id = line.slice(3).replace(/^ /, "");
1944
+ } else if (line.startsWith("retry:")) {
1945
+ const value = Number(line.slice(6).trim());
1946
+ if (Number.isFinite(value) && value >= 0) retry = value;
1423
1947
  }
1424
- if (dataLines.length === 0) continue;
1948
+ }
1949
+ let message = null;
1950
+ if (dataLines.some((line) => line.length > 0)) {
1425
1951
  try {
1426
- const payload = JSON.parse(dataLines.join("\n"));
1427
- if (payload && payload.jsonrpc === "2.0" && payload.id === requestId) {
1428
- return payload;
1952
+ const candidate = JSON.parse(dataLines.join("\n"));
1953
+ if (candidate && typeof candidate === "object") message = candidate;
1954
+ } catch {
1955
+ // Non-JSON SSE events are transport metadata, not MCP messages.
1956
+ }
1957
+ }
1958
+ return { id, retry, message };
1959
+ }
1960
+
1961
+ async function _consumeSseMessageStream(
1962
+ response,
1963
+ { cap = 0, stream, onMessage },
1964
+ ) {
1965
+ const dispatch = (rawEvent) => {
1966
+ const parsed = _parseSseEvent(rawEvent);
1967
+ if (parsed.id != null && parsed.id !== "") {
1968
+ stream.lastEventId = parsed.id;
1969
+ }
1970
+ if (parsed.retry != null) stream.retryMs = parsed.retry;
1971
+ if (parsed.message) onMessage(parsed.message);
1972
+ };
1973
+
1974
+ if (!response.body || typeof response.body.getReader !== "function") {
1975
+ const text = await _readBodyCapped(response, cap);
1976
+ for (const event of text.split(/\r?\n\r?\n/)) dispatch(event);
1977
+ return;
1978
+ }
1979
+
1980
+ const reader = response.body.getReader();
1981
+ const decoder = new TextDecoder("utf-8");
1982
+ let buffer = "";
1983
+ try {
1984
+ for (;;) {
1985
+ const { value, done } = await reader.read();
1986
+ if (done) break;
1987
+ buffer += decoder.decode(value, { stream: true });
1988
+ if (cap > 0 && buffer.length > cap) {
1989
+ throw new Error(
1990
+ `MCP HTTP SSE event exceeded the ${cap}-char cap`,
1991
+ );
1992
+ }
1993
+ let boundary;
1994
+ while ((boundary = buffer.search(/\r?\n\r?\n/)) >= 0) {
1995
+ const separator = buffer.match(/\r?\n\r?\n/)[0];
1996
+ const event = buffer.slice(0, boundary);
1997
+ buffer = buffer.slice(boundary + separator.length);
1998
+ dispatch(event);
1429
1999
  }
1430
- } catch (_e) {
1431
- // skip non-JSON data events
2000
+ }
2001
+ buffer += decoder.decode();
2002
+ if (buffer.trim()) dispatch(buffer);
2003
+ } finally {
2004
+ try {
2005
+ reader.releaseLock?.();
2006
+ } catch {
2007
+ // Best-effort cleanup; abort/disconnect owns cancellation.
1432
2008
  }
1433
2009
  }
1434
- throw new Error(`SSE stream ended without a response for id ${requestId}`);
1435
2010
  }
1436
2011
 
1437
2012
  /**