shadow-claw 1.32.0 → 1.33.0

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 (220) hide show
  1. package/.well-known/mcp/server-card.json +1 -1
  2. package/.well-known/mcp.json +1 -1
  3. package/dist/electron/main.cjs +1 -1
  4. package/dist/lib/components/index.js +26 -26
  5. package/dist/lib/components/settings/shadow-claw-accounts.js +1 -1
  6. package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
  7. package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
  8. package/dist/lib/components/settings/shadow-claw-git.js +1 -1
  9. package/dist/lib/components/settings/shadow-claw-integrations.js +1 -1
  10. package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
  11. package/dist/lib/components/settings/shadow-claw-mcp-remote.js +1 -1
  12. package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
  13. package/dist/lib/components/settings/shadow-claw-notifications.js +1 -1
  14. package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
  15. package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
  16. package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
  17. package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
  18. package/dist/lib/components/shadow-claw-a2ui.js +1 -1
  19. package/dist/lib/components/shadow-claw-accounts.js +1 -1
  20. package/dist/lib/components/shadow-claw-channel-config.js +1 -1
  21. package/dist/lib/components/shadow-claw-channels.js +1 -1
  22. package/dist/lib/components/shadow-claw-chat.js +1 -1
  23. package/dist/lib/components/shadow-claw-control-plane.js +1 -1
  24. package/dist/lib/components/shadow-claw-conversations.js +1 -1
  25. package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
  26. package/dist/lib/components/shadow-claw-files.js +1 -1
  27. package/dist/lib/components/shadow-claw-git.js +1 -1
  28. package/dist/lib/components/shadow-claw-integrations.js +1 -1
  29. package/dist/lib/components/shadow-claw-llm.js +1 -1
  30. package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
  31. package/dist/lib/components/shadow-claw-networking.js +1 -1
  32. package/dist/lib/components/shadow-claw-notifications.js +1 -1
  33. package/dist/lib/components/shadow-claw-page-header.js +1 -1
  34. package/dist/lib/components/shadow-claw-pages.js +1 -1
  35. package/dist/lib/components/shadow-claw-peerjs.js +1 -1
  36. package/dist/lib/components/shadow-claw-settings.js +1 -1
  37. package/dist/lib/components/shadow-claw-storage.js +1 -1
  38. package/dist/lib/components/shadow-claw-task-server.js +1 -1
  39. package/dist/lib/components/shadow-claw-tasks.js +1 -1
  40. package/dist/lib/components/shadow-claw-terminal.js +1 -1
  41. package/dist/lib/components/shadow-claw-tools.js +1 -1
  42. package/dist/lib/components/shadow-claw-webvm.js +1 -1
  43. package/dist/lib/components/shadow-claw.js +1 -1
  44. package/dist/lib/{config-DjZ9QWc4.js → config-BcFbkaQv.js} +21 -4
  45. package/dist/lib/config-BcFbkaQv.js.map +1 -0
  46. package/dist/lib/{configurePeerJs-DD3G3Pms.js → configurePeerJs-CBMPHbwa.js} +3 -3
  47. package/dist/lib/{configurePeerJs-DD3G3Pms.js.map → configurePeerJs-CBMPHbwa.js.map} +1 -1
  48. package/dist/lib/{connections-BURqMIUv.js → connections-PZrUDf49.js} +2 -2
  49. package/dist/lib/{connections-BURqMIUv.js.map → connections-PZrUDf49.js.map} +1 -1
  50. package/dist/lib/{downloadGroupFile-B8J4up2a.js → downloadGroupFile-DSRUa9Au.js} +2 -2
  51. package/dist/lib/{downloadGroupFile-B8J4up2a.js.map → downloadGroupFile-DSRUa9Au.js.map} +1 -1
  52. package/dist/lib/{file-viewer-DoHM75Jz.js → file-viewer-11VVOpJv.js} +5 -5
  53. package/dist/lib/{file-viewer-DoHM75Jz.js.map → file-viewer-11VVOpJv.js.map} +1 -1
  54. package/dist/lib/{getGroupDir-QrN2aTo8.js → getGroupDir-BxKMYPPm.js} +3 -3
  55. package/dist/lib/{getGroupDir-QrN2aTo8.js.map → getGroupDir-BxKMYPPm.js.map} +1 -1
  56. package/dist/lib/{git-Brr7JIbs.js → git-BppibnJW.js} +3 -3
  57. package/dist/lib/{git-Brr7JIbs.js.map → git-BppibnJW.js.map} +1 -1
  58. package/dist/lib/{iframe-sanitizer-Bujgq14T.js → iframe-sanitizer-Dp8EYffI.js} +2 -2
  59. package/dist/lib/{iframe-sanitizer-Bujgq14T.js.map → iframe-sanitizer-Dp8EYffI.js.map} +1 -1
  60. package/dist/lib/index.js +27 -27
  61. package/dist/lib/{initChatSplitResize-BjiWoqC_.js → initChatSplitResize-CE_kWaLf.js} +2 -2
  62. package/dist/lib/{initChatSplitResize-BjiWoqC_.js.map → initChatSplitResize-CE_kWaLf.js.map} +1 -1
  63. package/dist/lib/{initControlPlane-3TUdhRBM.js → initControlPlane-BRIIOzoH.js} +18 -17
  64. package/dist/lib/{initControlPlane-3TUdhRBM.js.map → initControlPlane-BRIIOzoH.js.map} +1 -1
  65. package/dist/lib/{markdown-BFUTPQoO.js → markdown-Cq4sVwUT.js} +4 -4
  66. package/dist/lib/{markdown-BFUTPQoO.js.map → markdown-Cq4sVwUT.js.map} +1 -1
  67. package/dist/lib/{mcp-reconnect-BxJ77WSb.js → mcp-reconnect-CoHDMjmY.js} +2 -2
  68. package/dist/lib/{mcp-reconnect-BxJ77WSb.js.map → mcp-reconnect-CoHDMjmY.js.map} +1 -1
  69. package/dist/lib/{memoryStorage-D3FBwO9T.js → memoryStorage-DcFWrn_y.js} +2 -2
  70. package/dist/lib/{memoryStorage-D3FBwO9T.js.map → memoryStorage-DcFWrn_y.js.map} +1 -1
  71. package/dist/lib/{orchestrator-DW5l2bbW.js → orchestrator-C3TgDZvq.js} +81 -18
  72. package/dist/lib/{orchestrator-DW5l2bbW.js.map → orchestrator-C3TgDZvq.js.map} +1 -1
  73. package/dist/lib/{orchestrator-DLnCmeTZ.js → orchestrator-Ce9_lmL2.js} +12 -12
  74. package/dist/lib/{orchestrator-DLnCmeTZ.js.map → orchestrator-Ce9_lmL2.js.map} +1 -1
  75. package/dist/lib/{peerjs-BXlMuIQn.js → peerjs-PTYQ7yEG.js} +6 -6
  76. package/dist/lib/{peerjs-BXlMuIQn.js.map → peerjs-PTYQ7yEG.js.map} +1 -1
  77. package/dist/lib/{push-client-B419nn-i.js → push-client-DDV5Rcg6.js} +3 -3
  78. package/dist/lib/{push-client-B419nn-i.js.map → push-client-DDV5Rcg6.js.map} +1 -1
  79. package/dist/lib/{readGroupFileBytes-CSA7u-nJ.js → readGroupFileBytes-7C8G-yps.js} +2 -2
  80. package/dist/lib/{readGroupFileBytes-CSA7u-nJ.js.map → readGroupFileBytes-7C8G-yps.js.map} +1 -1
  81. package/dist/lib/{shadow-claw-DmMO4vVG.js → shadow-claw-WrWoPqFx.js} +10 -10
  82. package/dist/lib/{shadow-claw-DmMO4vVG.js.map → shadow-claw-WrWoPqFx.js.map} +1 -1
  83. package/dist/lib/{shadow-claw-a2ui-2I5nffIn.js → shadow-claw-a2ui-CcmJNXQP.js} +2 -2
  84. package/dist/lib/{shadow-claw-a2ui-2I5nffIn.js.map → shadow-claw-a2ui-CcmJNXQP.js.map} +1 -1
  85. package/dist/lib/{shadow-claw-accounts-DMb0y4ca.js → shadow-claw-accounts-CcB2429E.js} +3 -3
  86. package/dist/lib/{shadow-claw-accounts-DMb0y4ca.js.map → shadow-claw-accounts-CcB2429E.js.map} +1 -1
  87. package/dist/lib/{shadow-claw-channel-config-BhxHf6wZ.js → shadow-claw-channel-config-C4v0h8oa.js} +3 -3
  88. package/dist/lib/{shadow-claw-channel-config-BhxHf6wZ.js.map → shadow-claw-channel-config-C4v0h8oa.js.map} +1 -1
  89. package/dist/lib/{shadow-claw-channels-B5vzE9Z2.js → shadow-claw-channels-CyV88k9T.js} +3 -3
  90. package/dist/lib/{shadow-claw-channels-B5vzE9Z2.js.map → shadow-claw-channels-CyV88k9T.js.map} +1 -1
  91. package/dist/lib/{shadow-claw-chat-BsYnJ4-G.js → shadow-claw-chat-DSYtuZod.js} +11 -11
  92. package/dist/lib/{shadow-claw-chat-BsYnJ4-G.js.map → shadow-claw-chat-DSYtuZod.js.map} +1 -1
  93. package/dist/lib/{shadow-claw-control-plane-DqcgQsun.js → shadow-claw-control-plane-DBSGuDT1.js} +7 -7
  94. package/dist/lib/{shadow-claw-control-plane-DqcgQsun.js.map → shadow-claw-control-plane-DBSGuDT1.js.map} +1 -1
  95. package/dist/lib/{shadow-claw-conversations-B9Pn58g3.js → shadow-claw-conversations-Cp8pK4PM.js} +5 -5
  96. package/dist/lib/{shadow-claw-conversations-B9Pn58g3.js.map → shadow-claw-conversations-Cp8pK4PM.js.map} +1 -1
  97. package/dist/lib/{shadow-claw-file-viewer-DL6c4oPK.js → shadow-claw-file-viewer-B8G8yo48.js} +8 -8
  98. package/dist/lib/{shadow-claw-file-viewer-DL6c4oPK.js.map → shadow-claw-file-viewer-B8G8yo48.js.map} +1 -1
  99. package/dist/lib/{shadow-claw-files-C_ksPb8W.js → shadow-claw-files-D1COKzuC.js} +9 -9
  100. package/dist/lib/{shadow-claw-files-C_ksPb8W.js.map → shadow-claw-files-D1COKzuC.js.map} +1 -1
  101. package/dist/lib/{shadow-claw-git-jwsY7L1N.js → shadow-claw-git-60tWU4Ee.js} +6 -6
  102. package/dist/lib/{shadow-claw-git-jwsY7L1N.js.map → shadow-claw-git-60tWU4Ee.js.map} +1 -1
  103. package/dist/lib/{shadow-claw-integrations-yT7j07TM.js → shadow-claw-integrations-Bw1cG1ze.js} +4 -4
  104. package/dist/lib/{shadow-claw-integrations-yT7j07TM.js.map → shadow-claw-integrations-Bw1cG1ze.js.map} +1 -1
  105. package/dist/lib/{shadow-claw-llm-CEPJh1Jh.js → shadow-claw-llm-By5CvsFJ.js} +6 -6
  106. package/dist/lib/{shadow-claw-llm-CEPJh1Jh.js.map → shadow-claw-llm-By5CvsFJ.js.map} +1 -1
  107. package/dist/lib/{shadow-claw-mcp-remote-DGDWjByQ.js → shadow-claw-mcp-remote-BaNODd1v.js} +4 -4
  108. package/dist/lib/{shadow-claw-mcp-remote-DGDWjByQ.js.map → shadow-claw-mcp-remote-BaNODd1v.js.map} +1 -1
  109. package/dist/lib/{shadow-claw-networking-Bi4yvc73.js → shadow-claw-networking-DtZ5bsTz.js} +2 -2
  110. package/dist/lib/{shadow-claw-networking-Bi4yvc73.js.map → shadow-claw-networking-DtZ5bsTz.js.map} +1 -1
  111. package/dist/lib/{shadow-claw-notifications-C-JgGqQx.js → shadow-claw-notifications-C3VEba_A.js} +3 -3
  112. package/dist/lib/{shadow-claw-notifications-C-JgGqQx.js.map → shadow-claw-notifications-C3VEba_A.js.map} +1 -1
  113. package/dist/lib/{shadow-claw-page-header-DrAcWCZ9.js → shadow-claw-page-header-BLowJopA.js} +2 -2
  114. package/dist/lib/{shadow-claw-page-header-DrAcWCZ9.js.map → shadow-claw-page-header-BLowJopA.js.map} +1 -1
  115. package/dist/lib/{shadow-claw-pages-OEOClgA8.js → shadow-claw-pages-CpeUV-hw.js} +9 -9
  116. package/dist/lib/{shadow-claw-pages-OEOClgA8.js.map → shadow-claw-pages-CpeUV-hw.js.map} +1 -1
  117. package/dist/lib/{shadow-claw-peerjs-DmC2CV-9.js → shadow-claw-peerjs-DYAzJbTy.js} +3 -3
  118. package/dist/lib/{shadow-claw-peerjs-DmC2CV-9.js.map → shadow-claw-peerjs-DYAzJbTy.js.map} +1 -1
  119. package/dist/lib/{shadow-claw-settings-xAtFog0T.js → shadow-claw-settings-ByxwW3WK.js} +9 -9
  120. package/dist/lib/{shadow-claw-settings-xAtFog0T.js.map → shadow-claw-settings-ByxwW3WK.js.map} +1 -1
  121. package/dist/lib/{shadow-claw-storage-B4UHl-po.js → shadow-claw-storage-CsSPYVDJ.js} +5 -5
  122. package/dist/lib/{shadow-claw-storage-B4UHl-po.js.map → shadow-claw-storage-CsSPYVDJ.js.map} +1 -1
  123. package/dist/lib/{shadow-claw-task-server-B0eWzg57.js → shadow-claw-task-server-De2WCEw4.js} +2 -2
  124. package/dist/lib/{shadow-claw-task-server-B0eWzg57.js.map → shadow-claw-task-server-De2WCEw4.js.map} +1 -1
  125. package/dist/lib/{shadow-claw-tasks-HHU_8Gyg.js → shadow-claw-tasks-zHWT4GaE.js} +7 -7
  126. package/dist/lib/{shadow-claw-tasks-HHU_8Gyg.js.map → shadow-claw-tasks-zHWT4GaE.js.map} +1 -1
  127. package/dist/lib/{shadow-claw-terminal-CdC2G6Zz.js → shadow-claw-terminal-Bpawfv4N.js} +2 -2
  128. package/dist/lib/{shadow-claw-terminal-CdC2G6Zz.js.map → shadow-claw-terminal-Bpawfv4N.js.map} +1 -1
  129. package/dist/lib/{shadow-claw-tools-2AICxVXA.js → shadow-claw-tools-BbKdWcps.js} +7 -7
  130. package/dist/lib/{shadow-claw-tools-2AICxVXA.js.map → shadow-claw-tools-BbKdWcps.js.map} +1 -1
  131. package/dist/lib/{shadow-claw-webvm-Cy-Ia2vs.js → shadow-claw-webvm-DLqK0AxW.js} +3 -3
  132. package/dist/lib/{shadow-claw-webvm-Cy-Ia2vs.js.map → shadow-claw-webvm-DLqK0AxW.js.map} +1 -1
  133. package/dist/lib/subsystems/mcp/webmcp.d.ts +37 -0
  134. package/dist/lib/subsystems/providers/model-registry.d.ts +4 -1
  135. package/dist/lib/subsystems/providers/providers.d.ts +10 -0
  136. package/dist/lib/{syncWebMcpRegistration-CaAPPg2V.js → syncWebMcpRegistration-mlbbvcdm.js} +5 -5
  137. package/dist/lib/{syncWebMcpRegistration-CaAPPg2V.js.map → syncWebMcpRegistration-mlbbvcdm.js.map} +1 -1
  138. package/dist/lib/{tools-f1WPNDSS.js → tools-Bb2ujM2E.js} +4 -4
  139. package/dist/lib/{tools-f1WPNDSS.js.map → tools-Bb2ujM2E.js.map} +1 -1
  140. package/dist/lib/utils/index.js +1 -1
  141. package/dist/lib/utils/utils.js +1 -1
  142. package/dist/lib/{utils-B99XP70b.js → utils-mpsYPfS7.js} +3 -3
  143. package/dist/lib/{utils-B99XP70b.js.map → utils-mpsYPfS7.js.map} +1 -1
  144. package/dist/lib/webmcp-BVR2lBVo.js +1544 -0
  145. package/dist/lib/webmcp-BVR2lBVo.js.map +1 -0
  146. package/dist/public/.well-known/mcp/server-card.json +1 -1
  147. package/dist/public/.well-known/mcp.json +1 -1
  148. package/dist/public/agent.worker.js +44 -44
  149. package/dist/public/config-BqecTktB.js +1 -0
  150. package/dist/public/{configurePeerJs--JGpJVti.js → configurePeerJs-BPKfWuEt.js} +1 -1
  151. package/dist/public/{connections-6575KDGE.js → connections-C_3tYsmX.js} +1 -1
  152. package/dist/public/{custom-element-security-Da_6HQ6X.js → custom-element-security-DXwU3Lae.js} +1 -1
  153. package/dist/public/docs/example/article/index.html +2 -2
  154. package/dist/public/docs/publishing/index.html +2 -2
  155. package/dist/public/docs/skill-creator/index.html +2 -2
  156. package/dist/public/docs/subsystems/tools.md +4 -3
  157. package/dist/public/docs/subsystems/webmcp.md +58 -13
  158. package/dist/public/{downloadGroupFile-Dj-AMNsd.js → downloadGroupFile-DTyf5DIC.js} +1 -1
  159. package/dist/public/{e2e-bridge-CbYqdMp-.js → e2e-bridge-DXwWCQKw.js} +1 -1
  160. package/dist/public/{file-viewer-vHJ5Zsgk.js → file-viewer-ConEyDDG.js} +1 -1
  161. package/dist/public/{getGroupDir-BwprrdrQ.js → getGroupDir-ZfZsiq6d.js} +1 -1
  162. package/dist/public/{git-8F7wvoUB.js → git-BtBaLC1-.js} +2 -2
  163. package/dist/public/{iframe-sanitizer-viROQkRn.js → iframe-sanitizer-Corkvo_d.js} +1 -1
  164. package/dist/public/index.html +2 -2
  165. package/dist/public/index.js +1 -1
  166. package/dist/public/{initChatSplitResize-BA18wLQQ.js → initChatSplitResize-CUc-TEmT.js} +1 -1
  167. package/dist/public/{initControlPlane-C5v0FtJE.js → initControlPlane-B_uYS8a4.js} +1 -1
  168. package/dist/public/main/index.html +2 -2
  169. package/dist/public/main/memory/index.html +2 -2
  170. package/dist/public/{markdown-eFKxxpVP.js → markdown-Cfa6GuJs.js} +1 -1
  171. package/dist/public/{mcp-reconnect-CBHuaYdF.js → mcp-reconnect-CUOkdPEz.js} +1 -1
  172. package/dist/public/{memoryStorage-C1llaYus.js → memoryStorage-Bh8fjmip.js} +1 -1
  173. package/dist/public/{orchestrator-DNr2HDI2.js → orchestrator-BcSzrg6E.js} +2 -2
  174. package/dist/public/{orchestrator-BeJfwtvz.js → orchestrator-Bi5OdVZD.js} +11 -11
  175. package/dist/public/{peerjs-mG30TAJ_.js → peerjs-CzCXG-NW.js} +1 -1
  176. package/dist/public/{push-client-C2zMT3Sf.js → push-client-Cr3Ruahp.js} +1 -1
  177. package/dist/public/service-worker.js +1 -1
  178. package/dist/public/{shadow-claw-Ble6l0Iw.js → shadow-claw-CzUYuuOa.js} +2 -2
  179. package/dist/public/{shadow-claw-accounts-D1y-zbMs.js → shadow-claw-accounts-BgIHB_aP.js} +1 -1
  180. package/dist/public/{shadow-claw-channels-D_xfBoWp.js → shadow-claw-channels-Ce_trJ5D.js} +1 -1
  181. package/dist/public/{shadow-claw-chat-D_Lbi5oH.js → shadow-claw-chat-CdECLLwL.js} +1 -1
  182. package/dist/public/{shadow-claw-control-plane-CrnA5lM0.js → shadow-claw-control-plane-DM62UmOz.js} +2 -2
  183. package/dist/public/{shadow-claw-conversations-BN-hFmN1.js → shadow-claw-conversations-AM5g3C00.js} +1 -1
  184. package/dist/public/{shadow-claw-file-viewer-BKEpzpbx.js → shadow-claw-file-viewer-BP7gWS5g.js} +1 -1
  185. package/dist/public/{shadow-claw-files-DDZMk5AA.js → shadow-claw-files-RPPGszcK.js} +1 -1
  186. package/dist/public/{shadow-claw-git-CqOO97Re.js → shadow-claw-git-BsHEvLrb.js} +2 -2
  187. package/dist/public/{shadow-claw-integrations-CRGL78Fy.js → shadow-claw-integrations-B0vbcOqg.js} +1 -1
  188. package/dist/public/{shadow-claw-llm-DoGxEHQL.js → shadow-claw-llm-FNNamrc_.js} +2 -2
  189. package/dist/public/{shadow-claw-mcp-remote-DyGnK4S_.js → shadow-claw-mcp-remote-7mDgniQu.js} +1 -1
  190. package/dist/public/{shadow-claw-networking-DJeCdb7e.js → shadow-claw-networking-CGsetaLp.js} +1 -1
  191. package/dist/public/{shadow-claw-notifications-hSKJeMXb.js → shadow-claw-notifications-pnwRcR-4.js} +1 -1
  192. package/dist/public/{shadow-claw-page-header-DA-FG08G.js → shadow-claw-page-header-BUy15Poz.js} +1 -1
  193. package/dist/public/{shadow-claw-pages-DTS98Zbi.js → shadow-claw-pages-ILAjGWNk.js} +1 -1
  194. package/dist/public/{shadow-claw-settings-5w0ce8SP.js → shadow-claw-settings-Bx5IgVqN.js} +3 -3
  195. package/dist/public/{shadow-claw-storage-DqlVt27X.js → shadow-claw-storage-PAtNykaF.js} +1 -1
  196. package/dist/public/{shadow-claw-task-server-ByZwKI6S.js → shadow-claw-task-server-Cbbi_2OO.js} +1 -1
  197. package/dist/public/{shadow-claw-tasks-Dc4G4zBu.js → shadow-claw-tasks-B-jKYWZJ.js} +1 -1
  198. package/dist/public/{shadow-claw-terminal-DvusP7wg.js → shadow-claw-terminal-BRejND-Z.js} +1 -1
  199. package/dist/public/{shadow-claw-tools-BEsid8q-.js → shadow-claw-tools-DNQe3oa-.js} +1 -1
  200. package/dist/public/{shadow-claw-webvm-BWlIeK78.js → shadow-claw-webvm-BFuwRifU.js} +1 -1
  201. package/dist/public/{syncWebMcpRegistration-CqVCB6m8.js → syncWebMcpRegistration-FxKAPwaz.js} +1 -1
  202. package/dist/public/theme-init.js +1 -1
  203. package/dist/public/{tools-Cp1gequ8.js → tools-BwQKGsro.js} +1 -1
  204. package/dist/public/transformers-js.worker.js +1 -1
  205. package/dist/public/webmcp-C28PAlfy.js +1 -0
  206. package/dist/server.js +1 -1
  207. package/package.json +3 -3
  208. package/src/core/utils/initControlPlane.test.ts +122 -1
  209. package/src/core/utils/initControlPlane.ts +12 -8
  210. package/src/subsystems/mcp/webmcp.test.ts +253 -1
  211. package/src/subsystems/mcp/webmcp.ts +147 -4
  212. package/src/subsystems/providers/model-registry.test.ts +139 -0
  213. package/src/subsystems/providers/model-registry.ts +54 -2
  214. package/src/subsystems/providers/providers.test.ts +329 -0
  215. package/src/subsystems/providers/providers.ts +135 -11
  216. package/dist/lib/config-DjZ9QWc4.js.map +0 -1
  217. package/dist/lib/webmcp-BC8_WafM.js +0 -1710
  218. package/dist/lib/webmcp-BC8_WafM.js.map +0 -1
  219. package/dist/public/config-Bnwx4EfS.js +0 -1
  220. package/dist/public/webmcp-DBONjQWd.js +0 -2
@@ -0,0 +1,1544 @@
1
+ import { n as __exportAll } from "./rolldown-runtime-DZ8SGSJo.js";
2
+ import { o as DEFAULT_GROUP_ID } from "./config-BcFbkaQv.js";
3
+ import { t as TOOL_DEFINITIONS } from "./tools-DKzPWc0q.js";
4
+ import "./tools-C3Kft940.js";
5
+
6
+ //#region node_modules/@mcp-b/webmcp-polyfill/dist/schema.js
7
+ const FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE = "Failed to parse input arguments";
8
+ const TOOL_INVOCATION_FAILED_MESSAGE = "Tool was executed but the invocation failed. For example, the script function threw an error";
9
+ const VALID_TOOL_NAME_RE = /^[A-Za-z0-9_.-]{1,128}$/u;
10
+ function isPlainObject(value) {
11
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12
+ }
13
+ function toDomString(value) {
14
+ if (typeof value === "symbol") throw new TypeError("Symbol values cannot be converted to a DOMString");
15
+ return String(value);
16
+ }
17
+ function coerceWebMcpToolDescriptor(tool) {
18
+ const name = Reflect.get(tool, "name");
19
+ const description = Reflect.get(tool, "description");
20
+ const title = Reflect.get(tool, "title");
21
+ if (name === void 0) throw new TypeError("Tool \"name\" is required");
22
+ if (description === void 0) throw new TypeError("Tool \"description\" is required");
23
+ const annotations = Reflect.get(tool, "annotations");
24
+ const annotationMembers = isPlainObject(annotations) ? annotations : {};
25
+ const inputSchema = Reflect.get(tool, "inputSchema");
26
+ const outputSchema = Reflect.get(tool, "outputSchema");
27
+ const execute = Reflect.get(tool, "execute");
28
+ return {
29
+ name: toDomString(name),
30
+ ...title === void 0 ? {} : { title: toDomString(title).toWellFormed() },
31
+ description: toDomString(description),
32
+ ...inputSchema === void 0 ? {} : { inputSchema },
33
+ ...outputSchema === void 0 ? {} : { outputSchema },
34
+ execute,
35
+ ...annotations === void 0 ? {} : { annotations: {
36
+ ...annotationMembers.title === void 0 ? {} : { title: toDomString(annotationMembers.title).toWellFormed() },
37
+ readOnlyHint: Boolean(annotationMembers.readOnlyHint),
38
+ ...annotationMembers.destructiveHint === void 0 ? {} : { destructiveHint: Boolean(annotationMembers.destructiveHint) },
39
+ ...annotationMembers.idempotentHint === void 0 ? {} : { idempotentHint: Boolean(annotationMembers.idempotentHint) },
40
+ ...annotationMembers.openWorldHint === void 0 ? {} : { openWorldHint: Boolean(annotationMembers.openWorldHint) },
41
+ untrustedContentHint: Boolean(annotationMembers.untrustedContentHint)
42
+ } }
43
+ };
44
+ }
45
+ function createUnknownError(message) {
46
+ return new DOMException(message, "UnknownError");
47
+ }
48
+ function createToolInvocationFailedError(error) {
49
+ return createUnknownError(error instanceof Error ? `${TOOL_INVOCATION_FAILED_MESSAGE}: ${error.message}` : TOOL_INVOCATION_FAILED_MESSAGE);
50
+ }
51
+ function createInvalidStateError(message) {
52
+ return new DOMException(message, "InvalidStateError");
53
+ }
54
+ function validateWebMcpToolDescriptor(tool) {
55
+ if (tool.name === "") throw createInvalidStateError("Tool \"name\" must be a non-empty string");
56
+ if (typeof tool.name !== "string" || !VALID_TOOL_NAME_RE.test(tool.name)) throw createInvalidStateError("Tool \"name\" must be 1–128 characters and contain only ASCII alphanumeric, underscore, hyphen, or period");
57
+ if (typeof tool.description !== "string" || tool.description.length === 0) throw createInvalidStateError("Tool \"description\" must be a non-empty string");
58
+ if (typeof tool.execute !== "function") throw new TypeError("Tool \"execute\" must be a function");
59
+ }
60
+ function toWebMcpAnnotations(annotations) {
61
+ return {
62
+ readOnlyHint: annotations.readOnlyHint ?? false,
63
+ untrustedContentHint: annotations.untrustedContentHint ?? false
64
+ };
65
+ }
66
+ function parseChromeToolInput(input) {
67
+ try {
68
+ const value = JSON.parse(input);
69
+ if (Array.isArray(value) || isPlainObject(value)) return value;
70
+ } catch {}
71
+ throw createUnknownError(FAILED_TO_PARSE_INPUT_ARGUMENTS_MESSAGE);
72
+ }
73
+ function serializeChromeToolResult(value) {
74
+ if (typeof value === "object" && value !== null || typeof value === "function") try {
75
+ const serialized = JSON.stringify(value);
76
+ if (serialized) return serialized;
77
+ } catch {}
78
+ return String(value) || "Operation succeeded";
79
+ }
80
+ function withAbortSignal(operation, signal, getAbortReason = () => signal?.reason) {
81
+ if (!signal) return operation;
82
+ if (signal.aborted) return Promise.reject(getAbortReason());
83
+ return new Promise((resolve, reject) => {
84
+ const onAbort = () => {
85
+ cleanup();
86
+ reject(getAbortReason());
87
+ };
88
+ const cleanup = () => signal.removeEventListener("abort", onAbort);
89
+ signal.addEventListener("abort", onAbort, { once: true });
90
+ operation.then((value) => {
91
+ cleanup();
92
+ resolve(value);
93
+ }, (error) => {
94
+ cleanup();
95
+ reject(error);
96
+ });
97
+ });
98
+ }
99
+ function isPotentiallyTrustworthyOrigin(url) {
100
+ const originUrl = url.origin === "null" ? url : new URL(url.origin);
101
+ const protocol = originUrl.protocol;
102
+ if ([
103
+ "https:",
104
+ "wss:",
105
+ "file:",
106
+ "chrome-extension:",
107
+ "moz-extension:"
108
+ ].includes(protocol)) return true;
109
+ const hostname = originUrl.hostname.toLowerCase();
110
+ const ipv4 = hostname.split(".");
111
+ const isLoopbackIpv4 = ipv4.length === 4 && ipv4.every((part) => /^\d{1,3}$/u.test(part) && Number(part) <= 255) && Number(ipv4[0]) === 127;
112
+ return hostname === "::1" || hostname === "[::1]" || hostname === "localhost" || hostname === "localhost." || hostname.endsWith(".localhost") || hostname.endsWith(".localhost.") || isLoopbackIpv4;
113
+ }
114
+ function validatePotentiallyTrustworthyOrigins(origins) {
115
+ for (const origin of origins ?? []) {
116
+ let parsed;
117
+ try {
118
+ parsed = new URL(origin);
119
+ } catch {
120
+ throw new DOMException(`Invalid or untrustworthy origin: ${String(origin)}`, "SecurityError");
121
+ }
122
+ if (!isPotentiallyTrustworthyOrigin(parsed)) throw new DOMException(`Invalid or untrustworthy origin: ${origin}`, "SecurityError");
123
+ }
124
+ }
125
+ function validateWebMcpAccess(ownerDocument) {
126
+ validateOriginAgentCluster();
127
+ if (!ownerDocument) return;
128
+ const DOMExceptionConstructor = ownerDocument.defaultView?.DOMException ?? DOMException;
129
+ let fullyActive = false;
130
+ try {
131
+ const ownerWindow = ownerDocument.defaultView;
132
+ fullyActive = Boolean(ownerWindow && ownerWindow.document === ownerDocument);
133
+ } catch {}
134
+ if (!fullyActive) throw new DOMExceptionConstructor("The associated document is not fully active", "InvalidStateError");
135
+ const policy = Reflect.get(ownerDocument, "permissionsPolicy") ?? Reflect.get(ownerDocument, "featurePolicy");
136
+ if (policy && typeof policy === "object") {
137
+ const features = Reflect.get(policy, "features");
138
+ const allowsFeature = Reflect.get(policy, "allowsFeature");
139
+ if (typeof features === "function" && typeof allowsFeature === "function") {
140
+ const supported = Reflect.apply(features, policy, []);
141
+ if (Array.isArray(supported) && supported.includes("tools")) {
142
+ if (Reflect.apply(allowsFeature, policy, ["tools"]) === true) return;
143
+ throw new DOMExceptionConstructor("WebMCP is disabled by Permissions Policy", "NotAllowedError");
144
+ }
145
+ }
146
+ }
147
+ const ownerWindow = ownerDocument.defaultView;
148
+ if (!ownerWindow || ownerWindow.parent === ownerWindow) return;
149
+ try {
150
+ ownerWindow.parent.document;
151
+ return;
152
+ } catch {}
153
+ throw new DOMExceptionConstructor("WebMCP in cross-origin frames requires native Permissions Policy support", "NotAllowedError");
154
+ }
155
+ function validateOriginAgentCluster() {
156
+ if (globalThis.originAgentCluster === false && globalThis.location?.protocol !== "file:") throw new DOMException("", "SecurityError");
157
+ }
158
+ function validateExecutableOrigin(origin) {
159
+ try {
160
+ if (new URL(String(origin)).origin !== "null") return;
161
+ } catch {}
162
+ throw new DOMException(`Unsupported tool origin: ${String(origin)}`, "NotSupportedError");
163
+ }
164
+ function serializeInputSchema(schema) {
165
+ if (schema === null || typeof schema !== "object" && typeof schema !== "function") throw new TypeError("inputSchema must be an object");
166
+ const serialized = JSON.stringify(schema);
167
+ if (serialized === void 0) throw new TypeError("inputSchema must be JSON-serializable");
168
+ return serialized;
169
+ }
170
+
171
+ //#endregion
172
+ //#region node_modules/@mcp-b/webmcp-polyfill/dist/index.js
173
+ const agentInvokedEvents = /* @__PURE__ */ new WeakSet();
174
+ const agentResponses = /* @__PURE__ */ new WeakMap();
175
+ const activeSubmissions = /* @__PURE__ */ new WeakMap();
176
+ function isAgentInvokedSubmitEvent(event) {
177
+ return event.isTrusted && (agentInvokedEvents.has(event) || event.eventPhase !== Event.NONE && event.target instanceof HTMLFormElement && activeSubmissions.has(event.target));
178
+ }
179
+ function respondWithAgentSubmitEvent(event, agentResponse) {
180
+ if (!isAgentInvokedSubmitEvent(event)) throw new DOMException("respondWith() is only available during an agent-invoked submit event", "InvalidStateError");
181
+ if (!event.defaultPrevented) throw new DOMException("respondWith() requires preventDefault() during an agent-invoked submit event", "InvalidStateError");
182
+ if (event.eventPhase === Event.NONE) throw new DOMException("respondWith() is only available while the submit event is being dispatched", "InvalidStateError");
183
+ agentInvokedEvents.add(event);
184
+ const response = Promise.resolve(agentResponse);
185
+ agentResponses.set(event, response);
186
+ if (event.target instanceof HTMLFormElement) activeSubmissions.get(event.target)?.respond(event);
187
+ }
188
+ const TEXT_INPUT_TYPES = /* @__PURE__ */ new Set([
189
+ "email",
190
+ "password",
191
+ "search",
192
+ "tel",
193
+ "text",
194
+ "url"
195
+ ]);
196
+ const READONLY_INPUT_TYPES = /* @__PURE__ */ new Set([
197
+ ...TEXT_INPUT_TYPES,
198
+ "date",
199
+ "datetime-local",
200
+ "month",
201
+ "number",
202
+ "time",
203
+ "week"
204
+ ]);
205
+ function isControl(element) {
206
+ return element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement;
207
+ }
208
+ function getFormControls(form) {
209
+ return Reflect.get(HTMLFormElement.prototype, "elements", form);
210
+ }
211
+ function getFormAttribute(form, name) {
212
+ return Reflect.apply(Element.prototype.getAttribute, form, [name]);
213
+ }
214
+ function formHasAttribute(form, name) {
215
+ return Reflect.apply(Element.prototype.hasAttribute, form, [name]);
216
+ }
217
+ function isFormConnected(form) {
218
+ return Reflect.get(Node.prototype, "isConnected", form);
219
+ }
220
+ function getOpenShadowRoot(element) {
221
+ return Reflect.get(Element.prototype, "shadowRoot", element);
222
+ }
223
+ function checkFormValidity(form) {
224
+ return Reflect.apply(HTMLFormElement.prototype.checkValidity, form, []);
225
+ }
226
+ function requestFormSubmit(form, submitter) {
227
+ Reflect.apply(HTMLFormElement.prototype.requestSubmit, form, submitter ? [submitter] : []);
228
+ }
229
+ function getControls(form) {
230
+ return [...getFormControls(form)].filter((element) => isControl(element) && !element.matches(":disabled") && !("readOnly" in element && element.readOnly && (element instanceof HTMLTextAreaElement || READONLY_INPUT_TYPES.has(element.type))));
231
+ }
232
+ function controlGroups(form) {
233
+ const groups = /* @__PURE__ */ new Map();
234
+ for (const control of getControls(form)) {
235
+ const name = control.name.trim();
236
+ const controls = groups.get(name);
237
+ if (controls) controls.push(control);
238
+ else groups.set(name, [control]);
239
+ }
240
+ return groups;
241
+ }
242
+ function labelText(control) {
243
+ return [...control.labels ?? []].map((label) => {
244
+ const copy = label.cloneNode(true);
245
+ if (!(copy instanceof HTMLElement)) return "";
246
+ copy.querySelectorAll("button, input, meter, output, progress, select, textarea").forEach((element) => element.remove());
247
+ return copy.textContent?.trim() ?? "";
248
+ }).filter(Boolean).join("; ");
249
+ }
250
+ function commonFieldset(form, controls) {
251
+ for (let element = controls[0]?.parentElement; element && element !== form; element = element.parentElement) if (element instanceof HTMLFieldSetElement && controls.every((control) => element.contains(control))) return element;
252
+ }
253
+ function parameterDescription(form, controls) {
254
+ if (controls.length === 1) {
255
+ const control = controls[0];
256
+ if (!control) return void 0;
257
+ return control.getAttribute("toolparamdescription") || labelText(control) || control.getAttribute("aria-description") || void 0;
258
+ }
259
+ return commonFieldset(form, controls)?.getAttribute("toolparamdescription") || void 0;
260
+ }
261
+ function withDescription(schema, form, controls, extra) {
262
+ const description = parameterDescription(form, controls);
263
+ const combined = description && extra ? `${description} (${extra})` : description || extra;
264
+ return combined ? {
265
+ ...schema,
266
+ description: combined
267
+ } : schema;
268
+ }
269
+ function validNumberAttribute(input, name) {
270
+ const raw = input.getAttribute(name);
271
+ if (raw === null || raw.trim() === "") return void 0;
272
+ const value = Number(raw);
273
+ return Number.isFinite(value) ? value : void 0;
274
+ }
275
+ function isStepBaseMultiple(stepBase, step) {
276
+ const quotient = stepBase / step;
277
+ return Math.abs(quotient - Math.round(quotient)) < Number.EPSILON * 16;
278
+ }
279
+ function validPattern(input) {
280
+ const pattern = input.getAttribute("pattern");
281
+ if (pattern === null) return void 0;
282
+ try {
283
+ new RegExp(pattern, "v");
284
+ return pattern;
285
+ } catch {
286
+ return;
287
+ }
288
+ }
289
+ function numberSchema(input, includePattern = true) {
290
+ const schema = { type: "number" };
291
+ const minimum = validNumberAttribute(input, "min");
292
+ const maximum = validNumberAttribute(input, "max");
293
+ if (minimum !== void 0) schema.minimum = minimum;
294
+ if (maximum !== void 0) schema.maximum = maximum;
295
+ const rawStep = input.getAttribute("step");
296
+ if (rawStep !== "any") {
297
+ const parsedStep = rawStep === null || rawStep === "" ? 1 : Number(rawStep);
298
+ const step = Number.isFinite(parsedStep) && parsedStep > 0 ? parsedStep : 1;
299
+ const rawValue = Number(input.getAttribute("value"));
300
+ if (isStepBaseMultiple(minimum ?? (Number.isFinite(rawValue) ? rawValue : 0), step)) schema.multipleOf = step;
301
+ }
302
+ const pattern = includePattern ? validPattern(input) : void 0;
303
+ if (pattern !== void 0) schema.pattern = pattern;
304
+ return schema;
305
+ }
306
+ function temporalFormat(input, datePrefix) {
307
+ const rawStep = input.getAttribute("step");
308
+ const parsedStep = rawStep === null || rawStep === "" ? 60 : Number(rawStep);
309
+ const step = Number.isFinite(parsedStep) && parsedStep > 0 ? parsedStep : 60;
310
+ if (step < 1) return `${datePrefix}(:[0-5][0-9](\\.[0-9]{1,3})?)?$`;
311
+ if (step < 60) return `${datePrefix}(:[0-5][0-9])?$`;
312
+ return `${datePrefix}$`;
313
+ }
314
+ function optionSchemas(options) {
315
+ return {
316
+ anyOf: options.map((option) => ({
317
+ type: "string",
318
+ const: option.value,
319
+ title: option.textContent ?? ""
320
+ })),
321
+ enum: options.map((option) => option.value)
322
+ };
323
+ }
324
+ function groupChoiceSchemas(controls) {
325
+ return {
326
+ anyOf: controls.map((control) => {
327
+ const title = labelText(control);
328
+ return {
329
+ type: "string",
330
+ const: control.value,
331
+ ...title ? { title } : {}
332
+ };
333
+ }),
334
+ enum: controls.map((control) => control.value)
335
+ };
336
+ }
337
+ function parameterSchema(form, controls) {
338
+ const first = controls[0];
339
+ if (!first) return void 0;
340
+ if (controls.length > 1) {
341
+ if (!controls.every((control) => control instanceof HTMLInputElement)) return void 0;
342
+ if (controls.every((control) => control.type === "checkbox")) return withDescription({
343
+ type: "array",
344
+ items: {
345
+ type: "string",
346
+ ...groupChoiceSchemas(controls)
347
+ },
348
+ uniqueItems: true
349
+ }, form, controls);
350
+ if (controls.every((control) => control.type === "radio")) return withDescription({
351
+ type: "string",
352
+ ...groupChoiceSchemas(controls)
353
+ }, form, controls);
354
+ return;
355
+ }
356
+ if (first instanceof HTMLTextAreaElement) return withDescription({ type: "string" }, form, controls);
357
+ if (first instanceof HTMLSelectElement) {
358
+ const choices = optionSchemas([...first.options]);
359
+ return withDescription(first.multiple ? {
360
+ type: "array",
361
+ items: {
362
+ type: "string",
363
+ ...choices
364
+ },
365
+ uniqueItems: true
366
+ } : {
367
+ type: "string",
368
+ ...choices
369
+ }, form, controls);
370
+ }
371
+ if (TEXT_INPUT_TYPES.has(first.type)) {
372
+ const schema = { type: "string" };
373
+ const pattern = validPattern(first);
374
+ if (pattern !== void 0) schema.pattern = pattern;
375
+ return withDescription(schema, form, controls);
376
+ }
377
+ if (first.type === "hidden") return first.getAttribute("toolparamdescription") ? withDescription({ type: "string" }, form, controls) : void 0;
378
+ if (first.type === "number") return withDescription(numberSchema(first), form, controls);
379
+ if (first.type === "range") {
380
+ const schema = numberSchema(first, false);
381
+ schema.minimum ??= 0;
382
+ schema.maximum ??= 100;
383
+ return withDescription(schema, form, controls);
384
+ }
385
+ if (first.type === "checkbox") return withDescription({ type: "boolean" }, form, controls);
386
+ if (first.type === "radio") return withDescription({
387
+ type: "string",
388
+ ...groupChoiceSchemas([first])
389
+ }, form, controls);
390
+ if (first.type === "date") return withDescription({
391
+ type: "string",
392
+ format: "date"
393
+ }, form, controls, "Dates MUST be provided in 'YYYY-MM-DD' format.");
394
+ if (first.type === "month") return withDescription({
395
+ type: "string",
396
+ format: "^[0-9]{4}-(0[1-9]|1[0-2])$"
397
+ }, form, controls);
398
+ if (first.type === "week") return withDescription({
399
+ type: "string",
400
+ format: "^[0-9]{4}-W(0[1-9]|[1-4][0-9]|5[0-3])$"
401
+ }, form, controls);
402
+ if (first.type === "time") return withDescription({
403
+ type: "string",
404
+ format: temporalFormat(first, "^([01][0-9]|2[0-3]):[0-5][0-9]")
405
+ }, form, controls);
406
+ if (first.type === "datetime-local") return withDescription({
407
+ type: "string",
408
+ format: temporalFormat(first, "^[0-9]{4}-(0[1-9]|1[0-2])-[0-9]{2}T([01][0-9]|2[0-3]):[0-5][0-9]")
409
+ }, form, controls);
410
+ if (first.type === "color") return withDescription({
411
+ type: "string",
412
+ format: "^#[0-9a-zA-Z]{6}$"
413
+ }, form, controls);
414
+ }
415
+ function synthesizeSchema(form) {
416
+ const properties = {};
417
+ const required = [];
418
+ for (const [name, controls] of controlGroups(form)) {
419
+ if (!name) continue;
420
+ const schema = parameterSchema(form, controls);
421
+ if (!schema) continue;
422
+ Object.defineProperty(properties, name, {
423
+ configurable: true,
424
+ enumerable: true,
425
+ value: schema,
426
+ writable: true
427
+ });
428
+ if (controls.some((control) => control.required)) required.push(name);
429
+ }
430
+ return {
431
+ type: "object",
432
+ properties,
433
+ required
434
+ };
435
+ }
436
+ function toolDefinition(form) {
437
+ return {
438
+ name: getFormAttribute(form, "toolname") ?? "",
439
+ title: getFormAttribute(form, "tooltitle") ?? "",
440
+ description: getFormAttribute(form, "tooldescription") ?? "",
441
+ inputSchema: synthesizeSchema(form),
442
+ autosubmit: formHasAttribute(form, "toolautosubmit")
443
+ };
444
+ }
445
+ function toFormString(value) {
446
+ if (typeof value === "string" || typeof value === "boolean") return String(value);
447
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
448
+ }
449
+ function toFormBoolean(value) {
450
+ if (typeof value === "boolean") return value;
451
+ if (typeof value === "number" && Number.isInteger(value)) return value !== 0;
452
+ if (typeof value !== "string") return void 0;
453
+ if (value === "1" || value.toLowerCase() === "true") return true;
454
+ if (value === "0" || value.toLowerCase() === "false") return false;
455
+ }
456
+ function hasUniqueAllowedValues(value, allowed) {
457
+ if (!Array.isArray(value)) return false;
458
+ const remaining = new Set(allowed);
459
+ for (const item of value) {
460
+ const string = toFormString(item);
461
+ if (string === void 0 || !remaining.delete(string)) return false;
462
+ }
463
+ return true;
464
+ }
465
+ function inputAcceptsValue(input, value) {
466
+ if (value === "") return input.type !== "number" && input.type !== "range";
467
+ const probe = input.ownerDocument.createElement("input");
468
+ probe.type = input.type;
469
+ probe.value = value;
470
+ return probe.value !== "";
471
+ }
472
+ function validatesParameter(form, controls, value) {
473
+ const first = controls[0];
474
+ if (!first || !parameterSchema(form, controls)) return false;
475
+ if (controls.length > 1) {
476
+ if (!controls.every((control) => control instanceof HTMLInputElement)) return false;
477
+ if (controls.every((control) => control.type === "checkbox")) return hasUniqueAllowedValues(value, new Set(controls.map((control) => control.value)));
478
+ if (controls.every((control) => control.type === "radio")) {
479
+ const string = toFormString(value);
480
+ return string !== void 0 && controls.some((control) => control.value === string);
481
+ }
482
+ return false;
483
+ }
484
+ if (first instanceof HTMLSelectElement) {
485
+ const allowed = new Set([...first.options].map((option) => option.value));
486
+ if (first.multiple) return hasUniqueAllowedValues(value, allowed);
487
+ const string = toFormString(value);
488
+ return string !== void 0 && allowed.has(string);
489
+ }
490
+ if (first instanceof HTMLTextAreaElement) return toFormString(value) !== void 0;
491
+ if (first.type === "checkbox") return toFormBoolean(value) !== void 0;
492
+ if (first.type === "radio") {
493
+ const string = toFormString(value);
494
+ return string !== void 0 && first.value === string;
495
+ }
496
+ const string = toFormString(value);
497
+ return string !== void 0 && inputAcceptsValue(first, string);
498
+ }
499
+ function dispatchInputAndChange(control) {
500
+ control.dispatchEvent(new Event("input", {
501
+ bubbles: true,
502
+ composed: true
503
+ }));
504
+ control.dispatchEvent(new Event("change", { bubbles: true }));
505
+ }
506
+ function setNativeValue(control, value) {
507
+ const prototype = control instanceof HTMLInputElement ? HTMLInputElement.prototype : HTMLTextAreaElement.prototype;
508
+ Object.getOwnPropertyDescriptor(prototype, "value")?.set?.call(control, value);
509
+ }
510
+ function setNativeChecked(control, checked) {
511
+ Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "checked")?.set?.call(control, checked);
512
+ }
513
+ function fillParameter(controls, value) {
514
+ const first = controls[0];
515
+ if (!first) return;
516
+ if (controls.length > 1 && controls.every((control) => control instanceof HTMLInputElement)) {
517
+ if (controls.every((control) => control.type === "checkbox") && Array.isArray(value)) {
518
+ const checked = new Set(value.map(toFormString));
519
+ for (const control of controls) {
520
+ const next = checked.has(control.value);
521
+ if (control.checked === next) continue;
522
+ setNativeChecked(control, next);
523
+ dispatchInputAndChange(control);
524
+ }
525
+ return;
526
+ }
527
+ const selected = toFormString(value);
528
+ const control = controls.find((candidate) => candidate.value === selected);
529
+ if (control && !control.checked) {
530
+ setNativeChecked(control, true);
531
+ dispatchInputAndChange(control);
532
+ }
533
+ return;
534
+ }
535
+ if (first instanceof HTMLSelectElement) {
536
+ if (first.multiple && Array.isArray(value)) {
537
+ const selected = new Set(value.map(toFormString));
538
+ let changed = false;
539
+ for (const option of first.options) {
540
+ const next = selected.has(option.value);
541
+ if (option.selected === next) continue;
542
+ option.selected = next;
543
+ changed = true;
544
+ }
545
+ if (changed) dispatchInputAndChange(first);
546
+ return;
547
+ }
548
+ const next = toFormString(value);
549
+ if (next !== void 0 && first.value !== next) {
550
+ first.value = next;
551
+ dispatchInputAndChange(first);
552
+ }
553
+ return;
554
+ }
555
+ if (first instanceof HTMLInputElement && first.type === "checkbox") {
556
+ const next = toFormBoolean(value);
557
+ if (next !== void 0 && first.checked !== next) {
558
+ setNativeChecked(first, next);
559
+ dispatchInputAndChange(first);
560
+ }
561
+ return;
562
+ }
563
+ if (first instanceof HTMLInputElement && first.type === "radio") {
564
+ if (toFormString(value) === first.value && !first.checked) {
565
+ setNativeChecked(first, true);
566
+ dispatchInputAndChange(first);
567
+ }
568
+ return;
569
+ }
570
+ const next = toFormString(value);
571
+ if (next !== void 0 && first.value !== next) {
572
+ setNativeValue(first, next);
573
+ dispatchInputAndChange(first);
574
+ }
575
+ }
576
+ function fillForm(form, input) {
577
+ if (Array.isArray(input)) throw new TypeError("Declarative tool input must be an object");
578
+ const groups = controlGroups(form);
579
+ for (const [name, value] of Object.entries(input)) {
580
+ const controls = groups.get(name);
581
+ if (!controls || !validatesParameter(form, controls, value)) throw new TypeError(`Invalid value for declarative form parameter "${name}"`);
582
+ }
583
+ for (const [name, value] of Object.entries(input)) fillParameter(groups.get(name) ?? [], value);
584
+ }
585
+ function findSubmitter(form) {
586
+ return [...getFormControls(form)].find((element) => !element.matches(":disabled") && (element instanceof HTMLButtonElement && element.type === "submit" || element instanceof HTMLInputElement && ["image", "submit"].includes(element.type)));
587
+ }
588
+ function validationError(form) {
589
+ const failures = [...getFormControls(form)].filter((element) => isControl(element) && element.willValidate && !element.validity.valid).map((control) => `${control.name.trim() || "{unknown}"}: ${control.validationMessage}`).join(". ");
590
+ return new DOMException(`Form validation failed: ${failures}`, "UnknownError");
591
+ }
592
+ function toolActivatedEvent(toolName) {
593
+ const event = new Event("toolactivated");
594
+ Object.defineProperty(event, "toolName", {
595
+ enumerable: true,
596
+ value: toolName
597
+ });
598
+ return event;
599
+ }
600
+ function waitForSubmission(registration, toolName, autosubmit, submitter) {
601
+ const { form } = registration;
602
+ registration.cancelPending?.(new DOMException("Tool execution cancelled", "UnknownError"));
603
+ return new Promise((resolve, reject) => {
604
+ let settled = false;
605
+ const cleanup = () => {
606
+ Reflect.apply(EventTarget.prototype.removeEventListener, form, [
607
+ "invalid",
608
+ onInvalid,
609
+ true
610
+ ]);
611
+ activeSubmissions.delete(form);
612
+ if (registration.cancelPending === cancel) delete registration.cancelPending;
613
+ };
614
+ const finish = (callback) => {
615
+ if (settled) return;
616
+ settled = true;
617
+ cleanup();
618
+ callback();
619
+ };
620
+ const cancel = (reason) => finish(() => reject(reason));
621
+ const settleResponse = (response) => {
622
+ response.then((value) => finish(() => resolve(value)), (error) => finish(() => reject(error)));
623
+ };
624
+ const onInvalid = (event) => {
625
+ if (!event.isTrusted) return;
626
+ queueMicrotask(() => {
627
+ if (!checkFormValidity(form)) cancel(validationError(form));
628
+ });
629
+ };
630
+ activeSubmissions.set(form, {
631
+ complete(event) {
632
+ queueMicrotask(() => {
633
+ const response = agentResponses.get(event);
634
+ if (response) settleResponse(response);
635
+ else if (event.defaultPrevented) cancel(new DOMException("preventDefault() requires respondWith()", "UnknownError"));
636
+ else finish(() => resolve(void 0));
637
+ });
638
+ },
639
+ direct() {
640
+ finish(() => resolve(void 0));
641
+ },
642
+ respond(event) {
643
+ queueMicrotask(() => {
644
+ const response = agentResponses.get(event);
645
+ if (response) settleResponse(response);
646
+ });
647
+ }
648
+ });
649
+ registration.cancelPending = cancel;
650
+ Reflect.apply(EventTarget.prototype.addEventListener, form, [
651
+ "invalid",
652
+ onInvalid,
653
+ true
654
+ ]);
655
+ if (!autosubmit) {
656
+ submitter?.focus();
657
+ window.dispatchEvent(toolActivatedEvent(toolName));
658
+ return;
659
+ }
660
+ try {
661
+ requestFormSubmit(form, submitter);
662
+ window.dispatchEvent(toolActivatedEvent(toolName));
663
+ } catch (error) {
664
+ cancel(error);
665
+ }
666
+ });
667
+ }
668
+ /** Installs the DOM-backed half of the draft Declarative WebMCP API. */
669
+ function installDeclarativeForms(document, context) {
670
+ let active = true;
671
+ const registrations = /* @__PURE__ */ new Map();
672
+ const blockedDefinitions = /* @__PURE__ */ new Map();
673
+ const observers = /* @__PURE__ */ new Map();
674
+ const onSubmit = (event) => {
675
+ if (!(event instanceof SubmitEvent) || !event.isTrusted || !(event.target instanceof HTMLFormElement)) return;
676
+ const submission = activeSubmissions.get(event.target);
677
+ if (!submission) return;
678
+ agentInvokedEvents.add(event);
679
+ submission.complete(event);
680
+ };
681
+ const onReset = (event) => {
682
+ if (!event.isTrusted || !(event.target instanceof HTMLFormElement)) return;
683
+ const form = event.target;
684
+ queueMicrotask(() => {
685
+ if (event.defaultPrevented) return;
686
+ registrations.get(form)?.cancelPending?.(new DOMException("Tool execution cancelled by form reset", "UnknownError"));
687
+ });
688
+ };
689
+ function stopObservingRoot(root) {
690
+ observers.get(root)?.disconnect();
691
+ observers.delete(root);
692
+ root.removeEventListener("reset", onReset, true);
693
+ root.removeEventListener("submit", onSubmit, true);
694
+ }
695
+ function observeRoot(root) {
696
+ if (observers.has(root)) return;
697
+ const observer = new MutationObserver(sync);
698
+ observers.set(root, observer);
699
+ observer.observe(root, {
700
+ attributes: true,
701
+ characterData: true,
702
+ childList: true,
703
+ subtree: true
704
+ });
705
+ root.addEventListener("reset", onReset, true);
706
+ root.addEventListener("submit", onSubmit, true);
707
+ }
708
+ function sync() {
709
+ observeRoot(document);
710
+ for (const root of observers.keys()) if (root instanceof ShadowRoot && !Reflect.get(Node.prototype, "isConnected", root.host)) stopObservingRoot(root);
711
+ const candidates = /* @__PURE__ */ new Set();
712
+ const selected = /* @__PURE__ */ new Map();
713
+ const selectedByName = /* @__PURE__ */ new Map();
714
+ for (const root of observers.keys()) for (const element of root.querySelectorAll("*")) {
715
+ const shadowRoot = getOpenShadowRoot(element);
716
+ if (shadowRoot) observeRoot(shadowRoot);
717
+ if (!(element instanceof HTMLFormElement) || !formHasAttribute(element, "toolname") || !formHasAttribute(element, "tooldescription") || !isFormConnected(element)) continue;
718
+ const form = element;
719
+ candidates.add(form);
720
+ const definition = toolDefinition(form);
721
+ const fingerprint = JSON.stringify(definition);
722
+ const blockedFingerprint = blockedDefinitions.get(form);
723
+ if (blockedFingerprint === fingerprint) continue;
724
+ const retryingChangedDefinition = blockedFingerprint !== void 0;
725
+ blockedDefinitions.delete(form);
726
+ const existingForm = selectedByName.get(definition.name);
727
+ if (existingForm && !retryingChangedDefinition) {
728
+ blockedDefinitions.set(form, fingerprint);
729
+ continue;
730
+ }
731
+ if (existingForm) {
732
+ const existingSelection = selected.get(existingForm);
733
+ if (existingSelection) {
734
+ blockedDefinitions.set(existingForm, existingSelection.fingerprint);
735
+ selected.delete(existingForm);
736
+ }
737
+ }
738
+ selectedByName.set(definition.name, form);
739
+ selected.set(form, {
740
+ definition,
741
+ fingerprint
742
+ });
743
+ }
744
+ for (const form of blockedDefinitions.keys()) if (!candidates.has(form)) blockedDefinitions.delete(form);
745
+ for (const [form, registration] of registrations) if (selected.get(form)?.fingerprint !== registration.fingerprint) {
746
+ registration.cancelPending?.(new DOMException("Tool execution cancelled because its form changed", "UnknownError"));
747
+ registration.controller.abort();
748
+ registrations.delete(form);
749
+ }
750
+ for (const [form, { definition, fingerprint }] of selected) {
751
+ if (registrations.has(form)) continue;
752
+ const controller = new AbortController();
753
+ const registration = {
754
+ controller,
755
+ fingerprint,
756
+ form
757
+ };
758
+ registrations.set(form, registration);
759
+ context.registerTool({
760
+ name: definition.name,
761
+ title: definition.title,
762
+ description: definition.description,
763
+ inputSchema: definition.inputSchema,
764
+ execute(input) {
765
+ const submitter = findSubmitter(form);
766
+ if (!definition.autosubmit && !submitter) throw new DOMException("A declarative form without toolautosubmit requires a submit button", "UnknownError");
767
+ fillForm(form, input);
768
+ return waitForSubmission(registration, definition.name, definition.autosubmit, submitter);
769
+ }
770
+ }, { signal: controller.signal }).catch((error) => {
771
+ controller.abort();
772
+ if (error?.name === "AbortError") return;
773
+ console.error(`[webmcp] declarative form tool "${definition.name}" was not registered:`, error);
774
+ });
775
+ }
776
+ }
777
+ let restoreAttachShadow = () => {};
778
+ const elementPrototype = document.defaultView?.Element.prototype;
779
+ const attachShadowDescriptor = elementPrototype ? Object.getOwnPropertyDescriptor(elementPrototype, "attachShadow") : void 0;
780
+ if (elementPrototype && attachShadowDescriptor?.configurable) {
781
+ const nativeAttachShadow = elementPrototype.attachShadow;
782
+ const attachShadow = function(init) {
783
+ const root = nativeAttachShadow.call(this, init);
784
+ if (active && root.mode === "open" && Reflect.get(Node.prototype, "ownerDocument", this) === document && Reflect.get(Node.prototype, "isConnected", this)) observeRoot(root);
785
+ return root;
786
+ };
787
+ Object.defineProperty(elementPrototype, "attachShadow", {
788
+ ...attachShadowDescriptor,
789
+ value: attachShadow
790
+ });
791
+ restoreAttachShadow = () => {
792
+ if (elementPrototype.attachShadow === attachShadow) Object.defineProperty(elementPrototype, "attachShadow", attachShadowDescriptor);
793
+ };
794
+ }
795
+ let restoreFormSubmit = () => {};
796
+ const formPrototype = document.defaultView?.HTMLFormElement.prototype;
797
+ const submitDescriptor = formPrototype ? Object.getOwnPropertyDescriptor(formPrototype, "submit") : void 0;
798
+ if (formPrototype && submitDescriptor?.configurable) {
799
+ const nativeSubmit = formPrototype.submit;
800
+ const submit = function() {
801
+ nativeSubmit.call(this);
802
+ if (active) activeSubmissions.get(this)?.direct();
803
+ };
804
+ Object.defineProperty(formPrototype, "submit", {
805
+ ...submitDescriptor,
806
+ value: submit
807
+ });
808
+ restoreFormSubmit = () => {
809
+ if (formPrototype.submit === submit) Object.defineProperty(formPrototype, "submit", submitDescriptor);
810
+ };
811
+ }
812
+ sync();
813
+ return () => {
814
+ active = false;
815
+ restoreFormSubmit();
816
+ restoreAttachShadow();
817
+ for (const root of observers.keys()) stopObservingRoot(root);
818
+ blockedDefinitions.clear();
819
+ for (const registration of registrations.values()) {
820
+ registration.cancelPending?.(new DOMException("Tool execution cancelled", "UnknownError"));
821
+ registration.controller.abort();
822
+ }
823
+ registrations.clear();
824
+ };
825
+ }
826
+ const POLYFILL_MARKER_PROPERTY = "__isWebMCPPolyfill";
827
+ const REGISTERED_INPUT_SCHEMA_SYMBOL = Symbol("registeredInputSchema");
828
+ const REGISTRATION_SIGNAL_SYMBOL = Symbol("registrationSignal");
829
+ const REGISTRATION_ABORT_SYMBOL = Symbol("registrationAbort");
830
+ const installedProperties = [];
831
+ let installedContext = null;
832
+ let cleanupDeclarativeForms = null;
833
+ function currentOrigin() {
834
+ return typeof globalThis.origin === "string" ? globalThis.origin : globalThis.location?.origin ?? "";
835
+ }
836
+ function installProperty(target, key, descriptor) {
837
+ const previous = Object.getOwnPropertyDescriptor(target, key);
838
+ try {
839
+ Object.defineProperty(target, key, descriptor);
840
+ } catch (error) {
841
+ cleanupWebMCPPolyfill();
842
+ throw error;
843
+ }
844
+ installedProperties.push({
845
+ target,
846
+ key,
847
+ previous
848
+ });
849
+ }
850
+ var StrictWebMCPContext = class extends EventTarget {
851
+ #tools = /* @__PURE__ */ new Map();
852
+ #testingShim = null;
853
+ #ontoolchangeHandler = null;
854
+ #ontoolchangeListener = (event) => {
855
+ this.#ontoolchangeHandler?.call(this, event);
856
+ };
857
+ #domException;
858
+ #ownerDocument;
859
+ constructor(ownerDocument) {
860
+ super();
861
+ this.#ownerDocument = ownerDocument;
862
+ this.#domException = ownerDocument?.defaultView?.DOMException ?? DOMException;
863
+ Object.defineProperty(this, POLYFILL_MARKER_PROPERTY, {
864
+ value: true,
865
+ enumerable: false,
866
+ writable: false,
867
+ configurable: false
868
+ });
869
+ }
870
+ get ontoolchange() {
871
+ return this.#ontoolchangeHandler;
872
+ }
873
+ set ontoolchange(handler) {
874
+ const listener = typeof handler === "function" ? handler : null;
875
+ if (listener === null) {
876
+ this.#ontoolchangeHandler = null;
877
+ super.removeEventListener("toolchange", this.#ontoolchangeListener);
878
+ return;
879
+ }
880
+ if (this.#ontoolchangeHandler === null) super.addEventListener("toolchange", this.#ontoolchangeListener);
881
+ this.#ontoolchangeHandler = listener;
882
+ }
883
+ async registerTool(tool, options = {}) {
884
+ validateWebMcpAccess(this.#ownerDocument);
885
+ const signal = options?.signal;
886
+ const normalized = normalizeToolDescriptor(tool, this.#tools);
887
+ signal?.throwIfAborted();
888
+ validatePotentiallyTrustworthyOrigins(options?.exposedTo);
889
+ signal?.throwIfAborted();
890
+ if (options?.exposedTo?.length) throw new this.#domException("Cross-document tool exposure requires native WebMCP", "NotSupportedError");
891
+ this.#tools.set(normalized.name, normalized);
892
+ if (signal) {
893
+ const abort = () => {
894
+ if (this.#removeTool(normalized.name, normalized)) this.#notifyToolsChanged();
895
+ };
896
+ normalized[REGISTRATION_SIGNAL_SYMBOL] = signal;
897
+ normalized[REGISTRATION_ABORT_SYMBOL] = abort;
898
+ signal.addEventListener("abort", abort, { once: true });
899
+ }
900
+ await this.#notifyToolsChanged();
901
+ if (signal?.aborted) throw signal.reason;
902
+ }
903
+ async getTools(options = {}) {
904
+ validateWebMcpAccess(this.#ownerDocument);
905
+ validatePotentiallyTrustworthyOrigins(options?.fromOrigins);
906
+ if (options?.fromOrigins?.length) throw new this.#domException("Cross-document tool discovery requires native WebMCP", "NotSupportedError");
907
+ const tools = [...this.#tools.values()].map((tool) => {
908
+ const serialized = tool[REGISTERED_INPUT_SCHEMA_SYMBOL];
909
+ const parsed = serialized === void 0 ? void 0 : JSON.parse(serialized);
910
+ return {
911
+ name: tool.name,
912
+ title: tool.title ?? "",
913
+ description: tool.description,
914
+ ...isPlainObject(parsed) ? { inputSchema: parsed } : {},
915
+ origin: currentOrigin(),
916
+ window: globalThis.window,
917
+ ...tool.annotations ? { annotations: toWebMcpAnnotations(tool.annotations) } : {}
918
+ };
919
+ }).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
920
+ await new Promise((resolve) => setTimeout(resolve, 0));
921
+ return tools;
922
+ }
923
+ async executeTool(tool, inputArgsJson, options = {}) {
924
+ validateWebMcpAccess(this.#ownerDocument);
925
+ if (tool === null || typeof tool !== "object") throw new TypeError("RegisteredTool must be an object");
926
+ for (const required of [
927
+ "name",
928
+ "description",
929
+ "window",
930
+ "origin"
931
+ ]) if (!(required in tool)) throw new TypeError(`RegisteredTool.${required} is required`);
932
+ validateExecutableOrigin(tool.origin);
933
+ if (tool.window !== globalThis.window || tool.origin !== currentOrigin()) throw createUnknownError(`Tool not found: ${tool.name}`);
934
+ return this.#invokeToolByName(tool.name, inputArgsJson, options);
935
+ }
936
+ /** @internal Used by initializeWebMCPPolyfill */
937
+ static getTestingShim(context) {
938
+ context.#testingShim ??= new PolyfillTestingShim(context);
939
+ return context.#testingShim;
940
+ }
941
+ /** @internal Used by PolyfillTestingShim */
942
+ static getToolInfos(context) {
943
+ return [...context.#tools.values()].map((tool) => ({
944
+ name: tool.name,
945
+ description: tool.description,
946
+ ...tool[REGISTERED_INPUT_SCHEMA_SYMBOL] === void 0 ? {} : { inputSchema: tool[REGISTERED_INPUT_SCHEMA_SYMBOL] }
947
+ }));
948
+ }
949
+ /** @internal Used by PolyfillTestingShim */
950
+ static executeToolForTesting(context, toolName, inputArgsJson, options) {
951
+ validateWebMcpAccess(context.#ownerDocument);
952
+ return context.#invokeToolByName(toolName, inputArgsJson, options);
953
+ }
954
+ /** @internal Used by cleanupWebMCPPolyfill */
955
+ static dispose(context) {
956
+ for (const name of context.#tools.keys()) context.#removeTool(name);
957
+ context.ontoolchange = null;
958
+ context.#testingShim?.dispose();
959
+ }
960
+ #removeTool(name, expected) {
961
+ const registered = this.#tools.get(name);
962
+ if (!registered || expected && registered !== expected) return false;
963
+ const signal = registered[REGISTRATION_SIGNAL_SYMBOL];
964
+ const abort = registered[REGISTRATION_ABORT_SYMBOL];
965
+ if (signal && abort) signal.removeEventListener("abort", abort);
966
+ return this.#tools.delete(name);
967
+ }
968
+ async #invokeToolByName(toolName, inputArgsJson, options) {
969
+ options?.signal?.throwIfAborted();
970
+ const tool = this.#tools.get(toolName);
971
+ if (!tool) throw createUnknownError(`Tool not found: ${toolName}`);
972
+ const args = parseChromeToolInput(inputArgsJson);
973
+ options?.signal?.throwIfAborted();
974
+ if (tool[REGISTRATION_SIGNAL_SYMBOL]?.aborted) throw createUnknownError("Tool unregistered");
975
+ let rawResult;
976
+ try {
977
+ const registrationSignal = tool[REGISTRATION_SIGNAL_SYMBOL];
978
+ rawResult = await withAbortSignal(withAbortSignal(Promise.resolve(tool.execute(args)), registrationSignal, () => createUnknownError("Tool unregistered")), options?.signal);
979
+ } catch (error) {
980
+ if (options?.signal?.aborted && error === options.signal.reason) throw error;
981
+ if (tool[REGISTRATION_SIGNAL_SYMBOL]?.aborted) throw error;
982
+ throw createToolInvocationFailedError(error);
983
+ }
984
+ return serializeChromeToolResult(rawResult);
985
+ }
986
+ async #notifyToolsChanged() {
987
+ await new Promise((resolve) => setTimeout(resolve, 0));
988
+ this.dispatchEvent(new Event("toolchange"));
989
+ this.#testingShim?.dispatchToolChange();
990
+ }
991
+ };
992
+ const modelContextConstructor = function ModelContext() {
993
+ throw new TypeError("Illegal constructor");
994
+ };
995
+ Object.defineProperty(modelContextConstructor, "name", { value: "ModelContext" });
996
+ Object.defineProperty(modelContextConstructor, "prototype", {
997
+ value: StrictWebMCPContext.prototype,
998
+ writable: false
999
+ });
1000
+ Object.setPrototypeOf(modelContextConstructor, EventTarget);
1001
+ Object.defineProperty(StrictWebMCPContext.prototype, "constructor", {
1002
+ configurable: true,
1003
+ writable: true,
1004
+ value: modelContextConstructor
1005
+ });
1006
+ Object.defineProperty(StrictWebMCPContext.prototype, Symbol.toStringTag, {
1007
+ configurable: true,
1008
+ value: "ModelContext"
1009
+ });
1010
+ for (const member of [
1011
+ "registerTool",
1012
+ "getTools",
1013
+ "executeTool",
1014
+ "ontoolchange"
1015
+ ]) {
1016
+ const descriptor = Object.getOwnPropertyDescriptor(StrictWebMCPContext.prototype, member);
1017
+ if (descriptor) Object.defineProperty(StrictWebMCPContext.prototype, member, {
1018
+ ...descriptor,
1019
+ enumerable: true
1020
+ });
1021
+ }
1022
+ /**
1023
+ * EventTarget-based testing shim matching the native Chromium ModelContextTesting surface.
1024
+ *
1025
+ * Fires `toolchange` events and supports the `ontoolchange` handler property.
1026
+ */
1027
+ var PolyfillTestingShim = class extends EventTarget {
1028
+ _ontoolchange = null;
1029
+ ontoolchangeListener = (event) => {
1030
+ this._ontoolchange?.call(this, event);
1031
+ };
1032
+ #context;
1033
+ constructor(context) {
1034
+ super();
1035
+ this.#context = context;
1036
+ }
1037
+ listTools() {
1038
+ return StrictWebMCPContext.getToolInfos(this.#context);
1039
+ }
1040
+ executeTool(toolName, inputArgsJson, options) {
1041
+ return StrictWebMCPContext.executeToolForTesting(this.#context, toolName, inputArgsJson, options);
1042
+ }
1043
+ get ontoolchange() {
1044
+ return this._ontoolchange;
1045
+ }
1046
+ set ontoolchange(handler) {
1047
+ const listener = typeof handler === "function" ? handler : null;
1048
+ if (listener === null) {
1049
+ this._ontoolchange = null;
1050
+ super.removeEventListener("toolchange", this.ontoolchangeListener);
1051
+ return;
1052
+ }
1053
+ if (this._ontoolchange === null) super.addEventListener("toolchange", this.ontoolchangeListener);
1054
+ this._ontoolchange = listener;
1055
+ }
1056
+ /** @internal Called by StrictWebMCPContext when tools change. */
1057
+ dispatchToolChange() {
1058
+ this.dispatchEvent(new Event("toolchange"));
1059
+ }
1060
+ dispose() {
1061
+ this.ontoolchange = null;
1062
+ }
1063
+ };
1064
+ function normalizeToolDescriptor(tool, existing) {
1065
+ if (!tool || typeof tool !== "object") throw new TypeError("registerTool(tool) requires a tool object");
1066
+ const coerced = coerceWebMcpToolDescriptor(tool);
1067
+ validateWebMcpToolDescriptor(coerced);
1068
+ if (existing.has(coerced.name)) throw createInvalidStateError(`Tool already registered: ${coerced.name}`);
1069
+ const registeredInputSchema = coerced.inputSchema === void 0 ? void 0 : serializeInputSchema(coerced.inputSchema);
1070
+ return {
1071
+ name: coerced.name,
1072
+ ...coerced.title === void 0 ? {} : { title: coerced.title },
1073
+ description: coerced.description,
1074
+ ...coerced.inputSchema === void 0 ? {} : { inputSchema: coerced.inputSchema },
1075
+ ...coerced.annotations === void 0 ? {} : { annotations: coerced.annotations },
1076
+ execute: (input) => Reflect.apply(coerced.execute, void 0, [input]),
1077
+ ...registeredInputSchema !== void 0 ? { [REGISTERED_INPUT_SCHEMA_SYMBOL]: registeredInputSchema } : {}
1078
+ };
1079
+ }
1080
+ let navigatorModelContextDeprecationWarned = false;
1081
+ /**
1082
+ * Backing store for the `Document.prototype.modelContext` getter.
1083
+ *
1084
+ * WebIDL puts `[SameObject] readonly attribute ModelContext modelContext` on
1085
+ * the Document *interface prototype object*, not on the document instance, and
1086
+ * Chrome matches that. One shared accessor therefore needs somewhere to keep
1087
+ * the per-document value, and keying it by document is what makes repeated
1088
+ * reads return the identical object, as `[SameObject]` requires.
1089
+ */
1090
+ const documentModelContexts = /* @__PURE__ */ new WeakMap();
1091
+ const { modelContext: documentModelContextGetter } = { modelContext() {
1092
+ if (!(this instanceof Document)) throw new TypeError("Illegal invocation");
1093
+ return documentModelContexts.get(this);
1094
+ } };
1095
+ Object.defineProperty(documentModelContextGetter, "name", { value: "get modelContext" });
1096
+ function defineDocumentModelContext(target, value) {
1097
+ documentModelContexts.set(target, value);
1098
+ if (Object.hasOwn(Document.prototype, "modelContext")) return;
1099
+ installProperty(Document.prototype, "modelContext", {
1100
+ configurable: true,
1101
+ enumerable: true,
1102
+ get: documentModelContextGetter
1103
+ });
1104
+ }
1105
+ function defineDeprecatedNavigatorModelContext(target, value) {
1106
+ installProperty(target, "modelContext", {
1107
+ configurable: true,
1108
+ enumerable: true,
1109
+ get() {
1110
+ if (!navigatorModelContextDeprecationWarned) {
1111
+ navigatorModelContextDeprecationWarned = true;
1112
+ console.warn("[WebMCPPolyfill] navigator.modelContext is deprecated. The May 27, 2026 WebMCP draft moved the modelContext getter from Navigator to Document — use document.modelContext instead. See https://github.com/webmachinelearning/webmcp/pull/184.");
1113
+ }
1114
+ return value;
1115
+ }
1116
+ });
1117
+ }
1118
+ function installSubmitEventPolyfill() {
1119
+ const prototype = SubmitEvent.prototype;
1120
+ if (!("agentInvoked" in prototype)) installProperty(prototype, "agentInvoked", {
1121
+ configurable: true,
1122
+ enumerable: true,
1123
+ get() {
1124
+ return isAgentInvokedSubmitEvent(this);
1125
+ }
1126
+ });
1127
+ if (!("respondWith" in prototype)) installProperty(prototype, "respondWith", {
1128
+ configurable: true,
1129
+ enumerable: true,
1130
+ writable: true,
1131
+ value(agentResponse) {
1132
+ respondWithAgentSubmitEvent(this, agentResponse);
1133
+ }
1134
+ });
1135
+ }
1136
+ function initializeWebMCPPolyfill(options) {
1137
+ if (globalThis.isSecureContext === false) return;
1138
+ const nav = typeof navigator === "undefined" ? null : navigator;
1139
+ const doc = typeof document === "undefined" ? null : document;
1140
+ if (!nav || !doc || typeof window === "undefined") return;
1141
+ if (doc.modelContext) return;
1142
+ const navigatorModelContext = nav.modelContext;
1143
+ if (installedProperties.length > 0) cleanupWebMCPPolyfill();
1144
+ if (navigatorModelContext) {
1145
+ defineDocumentModelContext(doc, navigatorModelContext);
1146
+ return;
1147
+ }
1148
+ const previousDescriptor = Object.getOwnPropertyDescriptor(window, "ModelContext");
1149
+ if (previousDescriptor && !previousDescriptor.configurable) {
1150
+ if (!Object.is(Reflect.get(window, "ModelContext"), modelContextConstructor)) throw new TypeError("Cannot install ModelContext over a non-configurable globalThis");
1151
+ } else installProperty(window, "ModelContext", {
1152
+ configurable: true,
1153
+ enumerable: false,
1154
+ writable: true,
1155
+ value: modelContextConstructor
1156
+ });
1157
+ const context = new StrictWebMCPContext(doc);
1158
+ installedContext = context;
1159
+ defineDocumentModelContext(doc, context);
1160
+ navigatorModelContextDeprecationWarned = false;
1161
+ defineDeprecatedNavigatorModelContext(nav, context);
1162
+ installSubmitEventPolyfill();
1163
+ if (options?.installTestingShim && !nav.modelContextTesting) installProperty(nav, "modelContextTesting", {
1164
+ configurable: true,
1165
+ enumerable: true,
1166
+ writable: false,
1167
+ value: StrictWebMCPContext.getTestingShim(context)
1168
+ });
1169
+ cleanupDeclarativeForms = installDeclarativeForms(doc, context);
1170
+ }
1171
+ function cleanupWebMCPPolyfill() {
1172
+ cleanupDeclarativeForms?.();
1173
+ cleanupDeclarativeForms = null;
1174
+ if (installedContext) StrictWebMCPContext.dispose(installedContext);
1175
+ installedContext = null;
1176
+ for (const { target, key, previous } of [...installedProperties].reverse()) if (previous) Object.defineProperty(target, key, previous);
1177
+ else Reflect.deleteProperty(target, key);
1178
+ installedProperties.length = 0;
1179
+ navigatorModelContextDeprecationWarned = false;
1180
+ }
1181
+
1182
+ //#endregion
1183
+ //#region src/subsystems/mcp/webmcp.ts
1184
+ var webmcp_exports = /* @__PURE__ */ __exportAll({
1185
+ CONSEQUENTIAL_TOOL_NAMES: () => CONSEQUENTIAL_TOOL_NAMES,
1186
+ READ_ONLY_TOOL_NAMES: () => READ_ONLY_TOOL_NAMES,
1187
+ executeWebMcpTool: () => executeWebMcpTool,
1188
+ extractAbortSignal: () => extractAbortSignal,
1189
+ getWebMcpMode: () => getWebMcpMode,
1190
+ getWebMcpTools: () => getWebMcpTools,
1191
+ parseWebMcpInputSchema: () => parseWebMcpInputSchema,
1192
+ registerWebMcpTools: () => registerWebMcpTools,
1193
+ resolveWebMcpToolAnnotations: () => resolveWebMcpToolAnnotations,
1194
+ setWebMcpMode: () => setWebMcpMode,
1195
+ unregisterWebMcpTools: () => unregisterWebMcpTools
1196
+ });
1197
+ const registeredToolControllers = /* @__PURE__ */ new Map();
1198
+ const registeredToolNames = /* @__PURE__ */ new Set();
1199
+ let currentMode = "polyfill";
1200
+ /**
1201
+ * Set the WebMCP mode (polyfill vs native).
1202
+ *
1203
+ * - `"polyfill"` (default): Uses `@mcp-b/webmcp-polyfill` for a pure-JS
1204
+ * `document.modelContext` that works in all browsers.
1205
+ * - `"native"`: Uses Chrome's native `document.modelContext` from
1206
+ * `chrome://flags/#enable-webmcp-testing`. Requires the flag to be
1207
+ * enabled. May crash in early Canary builds.
1208
+ *
1209
+ * Detection follows Chrome's recommended compat pattern:
1210
+ * `document.modelContext || navigator.modelContext`
1211
+ * `navigator.modelContext` was deprecated in Chrome 150 and removed in
1212
+ * Chrome 152.0.7943.0, but the fallback keeps older clients working.
1213
+ */
1214
+ function setWebMcpMode(mode) {
1215
+ currentMode = mode;
1216
+ }
1217
+ function getWebMcpMode() {
1218
+ return currentMode;
1219
+ }
1220
+ /**
1221
+ * Install the `@mcp-b/webmcp-polyfill` onto `document.modelContext`.
1222
+ *
1223
+ * The polyfill itself bails out when Chrome's native `document.modelContext`
1224
+ * is already present — it does NOT override the native API. We call it
1225
+ * unconditionally; if the polyfill is already installed it will detect the
1226
+ * existing install via its own `installState` guard and return quickly.
1227
+ */
1228
+ function ensurePolyfill() {
1229
+ try {
1230
+ initializeWebMCPPolyfill();
1231
+ } catch (err) {
1232
+ console.warn("WebMCP polyfill initialization failed:", err);
1233
+ }
1234
+ }
1235
+ /**
1236
+ * Access the WebMCP ModelContext API.
1237
+ *
1238
+ * In polyfill mode: installs the `@mcp-b/webmcp-polyfill` which surfaces
1239
+ * `document.modelContext`.
1240
+ * In native mode: follows Chrome's recommended feature-detection pattern:
1241
+ * `document.modelContext || navigator.modelContext`
1242
+ * `navigator.modelContext` was deprecated in Chrome 150 and removed in
1243
+ * Chrome 152.0.7943.0, but the fallback preserves compatibility with
1244
+ * earlier builds that may still be in the wild.
1245
+ */
1246
+ function getModelContextApi() {
1247
+ if (typeof document === "undefined" && typeof navigator === "undefined") return null;
1248
+ if (currentMode === "polyfill") ensurePolyfill();
1249
+ try {
1250
+ const modelContext = typeof document !== "undefined" && typeof document.modelContext !== "undefined" ? Reflect.get(document, "modelContext") : typeof navigator !== "undefined" && typeof navigator.modelContext !== "undefined" ? Reflect.get(navigator, "modelContext") : void 0;
1251
+ if (!modelContext || typeof modelContext !== "object") return null;
1252
+ const api = modelContext;
1253
+ if (typeof api.registerTool !== "function") return null;
1254
+ return api;
1255
+ } catch (err) {
1256
+ console.warn("WebMCP modelContext access failed:", err);
1257
+ return null;
1258
+ }
1259
+ }
1260
+ /**
1261
+ * Safely parse or normalize WebMCP input schema.
1262
+ *
1263
+ * Starting in Chrome 154.0.8014.0 (PR #241), `RegisteredTool#inputSchema` returns
1264
+ * a JavaScript object (a deep copy of the schema provided at registration).
1265
+ * In Chrome < 154.0.8014.0, `RegisteredTool#inputSchema` returned a stringified JSON schema (DOMString).
1266
+ *
1267
+ * This function provides backwards-compatible schema parsing:
1268
+ * - If inputSchema is a string: attempts JSON.parse.
1269
+ * - If inputSchema is an object: returns the object.
1270
+ * - Fallbacks gracefully to an empty object schema if null, undefined, or invalid JSON.
1271
+ */
1272
+ function parseWebMcpInputSchema(inputSchema) {
1273
+ if (typeof inputSchema === "string") {
1274
+ try {
1275
+ const parsed = JSON.parse(inputSchema);
1276
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
1277
+ } catch {}
1278
+ return {
1279
+ type: "object",
1280
+ properties: {}
1281
+ };
1282
+ }
1283
+ if (inputSchema && typeof inputSchema === "object" && !Array.isArray(inputSchema)) return inputSchema;
1284
+ return {
1285
+ type: "object",
1286
+ properties: {}
1287
+ };
1288
+ }
1289
+ /**
1290
+ * Safely extract AbortSignal from execute options/context.
1291
+ * Supports Chrome 153+ options object `{ signal }` (PR #247), direct AbortSignal instances,
1292
+ * or undefined for backward compatibility with Chrome < 153 and legacy callers.
1293
+ */
1294
+ function extractAbortSignal(context) {
1295
+ if (!context) return;
1296
+ if (typeof AbortSignal !== "undefined" && context instanceof AbortSignal) return context;
1297
+ if (typeof context === "object" && "signal" in context && typeof AbortSignal !== "undefined" && context.signal instanceof AbortSignal) return context.signal;
1298
+ }
1299
+ /**
1300
+ * Retrieve tools registered on the WebMCP ModelContext API.
1301
+ *
1302
+ * Practicing graceful degradation:
1303
+ * - Feature-detects `getTools()` on `document.modelContext` / `navigator.modelContext`.
1304
+ * - If `getTools()` is absent (older browser builds or polyfills without getTools),
1305
+ * returns an empty array `[]` without throwing.
1306
+ * - Normalizes `RegisteredTool#inputSchema` so caller receives a JavaScript object
1307
+ * whether running on Chrome 154+ (native object) or Chrome < 154 (DOMString JSON).
1308
+ */
1309
+ async function getWebMcpTools() {
1310
+ const modelContext = getModelContextApi();
1311
+ if (!modelContext || typeof modelContext.getTools !== "function") return [];
1312
+ try {
1313
+ const rawTools = await modelContext.getTools();
1314
+ if (!Array.isArray(rawTools)) return [];
1315
+ return rawTools.map((tool) => ({
1316
+ name: tool.name,
1317
+ ...tool.description ? { description: tool.description } : {},
1318
+ inputSchema: parseWebMcpInputSchema(tool.inputSchema),
1319
+ ...tool.annotations ? { annotations: tool.annotations } : {},
1320
+ ...tool.execute ? { execute: tool.execute } : {}
1321
+ }));
1322
+ } catch (err) {
1323
+ console.warn("Failed to retrieve WebMCP tools via getTools():", err);
1324
+ return [];
1325
+ }
1326
+ }
1327
+ /**
1328
+ * Gracefully execute a WebMCP tool on a ModelContext instance with backwards compatibility.
1329
+ *
1330
+ * Starting in Chrome 155.0.8052.0 (PR #246, PR #251), `document.modelContext.executeTool()`
1331
+ * accepts an optional JavaScript object directly instead of a JSON DOMString.
1332
+ * In Chrome < 155 and earlier polyfills, `executeTool()` required a stringified JSON arguments string.
1333
+ *
1334
+ * This function practices graceful degradation:
1335
+ * 1. Prepares both an `inputObject` (for Chrome 155+) and an `inputStr` (for Chrome < 155 & polyfills).
1336
+ * 2. Attempts to execute `executeTool(tool, inputObject, options)` first.
1337
+ * 3. Catches errors starting with "Failed to parse input" (or TypeErrors from WebIDL DOMString checks)
1338
+ * and retries transparently with `JSON.stringify(inputObject)`.
1339
+ * 4. Re-throws any unrelated execution errors.
1340
+ */
1341
+ async function executeWebMcpTool(modelContext, tool, input, options) {
1342
+ if (!modelContext || typeof modelContext.executeTool !== "function") throw new Error("ModelContext executeTool is not available");
1343
+ let inputObject;
1344
+ let inputStr;
1345
+ if (typeof input === "string") {
1346
+ inputStr = input;
1347
+ try {
1348
+ const parsed = JSON.parse(input);
1349
+ inputObject = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
1350
+ } catch {
1351
+ inputObject = {};
1352
+ }
1353
+ } else if (input && typeof input === "object" && !Array.isArray(input)) {
1354
+ inputObject = input;
1355
+ try {
1356
+ inputStr = JSON.stringify(input);
1357
+ } catch {
1358
+ inputStr = "{}";
1359
+ }
1360
+ } else {
1361
+ inputObject = {};
1362
+ inputStr = "{}";
1363
+ }
1364
+ try {
1365
+ return await modelContext.executeTool(tool, inputObject, options);
1366
+ } catch (err) {
1367
+ const isParseError = typeof err?.message === "string" && err.message.startsWith("Failed to parse input");
1368
+ const isTypeError = err instanceof TypeError;
1369
+ if (isParseError || isTypeError) return await modelContext.executeTool(tool, inputStr, options);
1370
+ throw err;
1371
+ }
1372
+ }
1373
+ /**
1374
+ * Consequential tools that perform high-stakes, irreversible, or external real-world actions
1375
+ * (such as deleting data, executing arbitrary system commands, or transmitting live communications).
1376
+ * Signals consuming agents to require explicit user confirmation prior to execution (Chrome 154.0.8017.0+).
1377
+ */
1378
+ const CONSEQUENTIAL_TOOL_NAMES = /* @__PURE__ */ new Set([
1379
+ "bash",
1380
+ "clear_chat",
1381
+ "delete_file",
1382
+ "delete_task",
1383
+ "email_send_message",
1384
+ "git_delete_branch",
1385
+ "git_delete_repo",
1386
+ "git_push",
1387
+ "git_reset"
1388
+ ]);
1389
+ /**
1390
+ * Read-only tools that query information without mutating state.
1391
+ */
1392
+ const READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
1393
+ "ask_user",
1394
+ "detect_language",
1395
+ "diff_files",
1396
+ "email_read_messages",
1397
+ "fetch_url",
1398
+ "get_current_time",
1399
+ "git_branches",
1400
+ "git_diff",
1401
+ "git_list_repos",
1402
+ "git_log",
1403
+ "git_read_file_at_ref",
1404
+ "git_show",
1405
+ "git_status",
1406
+ "list_components",
1407
+ "list_files",
1408
+ "list_room_members",
1409
+ "list_tasks",
1410
+ "list_tool_profiles",
1411
+ "proofread_text",
1412
+ "read_file",
1413
+ "remote_mcp_list_tools",
1414
+ "rewrite_text",
1415
+ "search_files",
1416
+ "summarize_text",
1417
+ "translate_text",
1418
+ "web_search",
1419
+ "write_text"
1420
+ ]);
1421
+ /**
1422
+ * Resolve annotations for a WebMCP tool registration.
1423
+ * Allows custom annotations (from declarative or customized tool definitions)
1424
+ * to override defaults.
1425
+ */
1426
+ function resolveWebMcpToolAnnotations(toolName, customAnnotations) {
1427
+ const isConsequential = CONSEQUENTIAL_TOOL_NAMES.has(toolName);
1428
+ return {
1429
+ readOnlyHint: !isConsequential && READ_ONLY_TOOL_NAMES.has(toolName),
1430
+ consequentialHint: isConsequential,
1431
+ untrustedContentHint: true,
1432
+ ...customAnnotations || {}
1433
+ };
1434
+ }
1435
+ /**
1436
+ * Register ShadowClaw tools with the WebMCP ModelContext API.
1437
+ *
1438
+ * Both the `@mcp-b/webmcp-polyfill` and Chrome's native API support
1439
+ * `registerTool(tool, { signal })`. We always use AbortController signals so
1440
+ * that unregistration works identically regardless of which implementation is
1441
+ * actually active.
1442
+ *
1443
+ * Key correctness detail: `initializeWebMCPPolyfill()` is a no-op when
1444
+ * Chrome's native `document.modelContext` already exists — it does NOT
1445
+ * override the native API. In that situation we are talking to the native
1446
+ * Chrome API even in "polyfill" mode. The native Chrome API only supports
1447
+ * signal-based unregistration, so using AbortController signals everywhere
1448
+ * prevents "Duplicate tool name" errors when tools are re-configured.
1449
+ */
1450
+ async function registerWebMcpTools(agentWorker, _emit, groupId = DEFAULT_GROUP_ID, tools) {
1451
+ const activeTools = Array.isArray(tools) ? tools : TOOL_DEFINITIONS;
1452
+ if (activeTools.length === 0) return true;
1453
+ const modelContext = getModelContextApi();
1454
+ if (!modelContext) return false;
1455
+ for (const def of activeTools) {
1456
+ if (registeredToolNames.has(def.name)) continue;
1457
+ const controller = new AbortController();
1458
+ registeredToolControllers.set(def.name, controller);
1459
+ registeredToolNames.add(def.name);
1460
+ try {
1461
+ const toolDef = {
1462
+ name: def.name,
1463
+ description: def.description,
1464
+ inputSchema: parseWebMcpInputSchema(def.input_schema),
1465
+ annotations: resolveWebMcpToolAnnotations(def.name, def.annotations),
1466
+ execute: (input, context) => {
1467
+ if (!agentWorker) throw new Error("Cannot execute tool: agent worker is not ready");
1468
+ const signal = extractAbortSignal(context);
1469
+ if (signal?.aborted) return Promise.reject(/* @__PURE__ */ new Error("Tool execution aborted"));
1470
+ return new Promise((resolve, reject) => {
1471
+ const callId = Date.now().toString(36) + Math.random().toString(36).slice(2);
1472
+ let timeout = null;
1473
+ const cleanup = () => {
1474
+ if (timeout !== null) {
1475
+ clearTimeout(timeout);
1476
+ timeout = null;
1477
+ }
1478
+ agentWorker?.removeEventListener("message", handler);
1479
+ if (signal && onAbort) signal.removeEventListener("abort", onAbort);
1480
+ };
1481
+ const onAbort = () => {
1482
+ cleanup();
1483
+ reject(/* @__PURE__ */ new Error("Tool execution aborted"));
1484
+ };
1485
+ if (signal) signal.addEventListener("abort", onAbort, { once: true });
1486
+ timeout = setTimeout(() => {
1487
+ cleanup();
1488
+ reject(/* @__PURE__ */ new Error("Timeout waiting for tool execution"));
1489
+ }, 6e5);
1490
+ const handler = (event) => {
1491
+ const data = event.data;
1492
+ if (data && data.type === "execute-tool-result" && data.callId === callId) {
1493
+ cleanup();
1494
+ if (data.error) reject(new Error(data.error));
1495
+ else resolve(data.result);
1496
+ }
1497
+ };
1498
+ agentWorker.addEventListener("message", handler);
1499
+ agentWorker.postMessage({
1500
+ type: "execute-tool",
1501
+ callId,
1502
+ payload: {
1503
+ name: def.name,
1504
+ input: input || {},
1505
+ groupId
1506
+ }
1507
+ });
1508
+ });
1509
+ }
1510
+ };
1511
+ await modelContext.registerTool(toolDef, { signal: controller.signal });
1512
+ await new Promise((resolve) => setTimeout(resolve, 0));
1513
+ } catch (err) {
1514
+ registeredToolControllers.delete(def.name);
1515
+ registeredToolNames.delete(def.name);
1516
+ if (!(err instanceof Error && (err.message.includes("already registered") || err.message.includes("Duplicate tool name")))) {
1517
+ console.error(`Failed to register tool ${def.name}:`, err);
1518
+ throw err;
1519
+ }
1520
+ }
1521
+ }
1522
+ return true;
1523
+ }
1524
+ /**
1525
+ * Unregister previously registered ShadowClaw WebMCP tools.
1526
+ *
1527
+ * Aborts every AbortController associated with a registered tool. This works
1528
+ * for both the polyfill (which listens for the `abort` event on the signal it
1529
+ * was given) and Chrome's native API (which also uses signal-based lifecycle).
1530
+ * The deprecated `unregisterTool(name)` is intentionally NOT called here
1531
+ * because it is absent from the native Chrome API and causes silent failures
1532
+ * that prevent proper cleanup.
1533
+ */
1534
+ function unregisterWebMcpTools() {
1535
+ for (const controller of registeredToolControllers.values()) try {
1536
+ controller.abort();
1537
+ } catch {}
1538
+ registeredToolControllers.clear();
1539
+ registeredToolNames.clear();
1540
+ }
1541
+
1542
+ //#endregion
1543
+ export { webmcp_exports as a, unregisterWebMcpTools as i, registerWebMcpTools as n, setWebMcpMode as r, getWebMcpMode as t };
1544
+ //# sourceMappingURL=webmcp-BVR2lBVo.js.map