shadow-claw 1.40.1 → 1.41.1

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 (325) hide show
  1. package/.well-known/mcp/server-card.json +1 -1
  2. package/.well-known/mcp.json +1 -1
  3. package/README.md +2 -1
  4. package/dist/cli/build/build.js +1 -1
  5. package/dist/cli/{chunk-Bfz2NYgD.js → chunk-0IeC97mU.js} +7 -7
  6. package/dist/cli/chunk-3oLxlxPn.js +1 -0
  7. package/dist/cli/chunk-63s8NnIS.js +93 -0
  8. package/dist/cli/{chunk-BXg4-9Rq2.js → chunk-8CrZyP1b2.js} +1 -1
  9. package/dist/cli/{chunk-BP5Hg6CM.js → chunk-B--ueArB.js} +1 -1
  10. package/dist/cli/chunk-BATVgkFY.js +17 -0
  11. package/dist/cli/chunk-BIh7rXlJ2.js +1 -0
  12. package/dist/cli/{chunk-Drr0VSGA2.js → chunk-BKnTOLLS2.js} +1 -1
  13. package/dist/cli/{chunk-C5PuRV08.js → chunk-BLMC1Bxv.js} +1 -1
  14. package/dist/cli/{chunk-B2tNSlFy2.js → chunk-BOigzz2U2.js} +1 -1
  15. package/dist/cli/{chunk-DOf3DZdR.js → chunk-BOzn335y.js} +1 -1
  16. package/dist/cli/chunk-BjOeVLb42.js +1 -0
  17. package/dist/cli/{chunk-DqTx0rRp2.js → chunk-Bjqh5_SU2.js} +1 -1
  18. package/dist/cli/chunk-BqWBd_jF2.js +1 -0
  19. package/dist/cli/{chunk-DIbSoQmd2.js → chunk-C6FFByBU2.js} +2 -2
  20. package/dist/cli/{chunk-Drq18VZe.js → chunk-C9-aL3rF.js} +1 -1
  21. package/dist/cli/{chunk-BUhqHeEA2.js → chunk-C9czddEh2.js} +2 -2
  22. package/dist/cli/chunk-CCx8WOwz2.js +1 -0
  23. package/dist/cli/{chunk-BkMSjVJb.js → chunk-CK6ejMig.js} +1 -1
  24. package/dist/cli/chunk-CUUERioR2.js +1 -0
  25. package/dist/cli/chunk-CXAobnJd.js +1 -0
  26. package/dist/cli/chunk-CY1X0pOF2.js +1 -0
  27. package/dist/cli/chunk-CZvvgLVv.js +1 -0
  28. package/dist/cli/chunk-CbcwbfJB.js +1 -0
  29. package/dist/cli/{chunk-quilB3TV2.js → chunk-Ci9OJGcd2.js} +1 -1
  30. package/dist/cli/chunk-Cj9wl0qx.js +1 -0
  31. package/dist/cli/{chunk-3gRhOmGo2.js → chunk-CjJsVrKI2.js} +1 -1
  32. package/dist/cli/{chunk-CmEfzm-_.js → chunk-ClPZ4Rea.js} +1 -1
  33. package/dist/cli/chunk-Cmdxoq9q.js +13 -0
  34. package/dist/cli/{chunk-WMPAfIvV2.js → chunk-DHJCGRuG2.js} +1 -1
  35. package/dist/cli/{chunk-C7Y2xIk4.js → chunk-DKVkYTV9.js} +1 -1
  36. package/dist/cli/chunk-DR2XtWRo.js +1 -0
  37. package/dist/cli/{chunk-BiVJVh_S.js → chunk-DUlIqkaX.js} +7 -7
  38. package/dist/cli/{chunk-CkpueGaZ2.js → chunk-DjWle8FF2.js} +1 -1
  39. package/dist/cli/{chunk-CSvHmNOk.js → chunk-DmRXVLfy.js} +1 -1
  40. package/dist/cli/{chunk-BT1xXZn72.js → chunk-HlSiTC-u2.js} +1 -1
  41. package/dist/cli/{chunk-da0bsiOn.js → chunk-P4JSeFBI.js} +1 -1
  42. package/dist/cli/chunk-UcNbHaRQ.js +1 -0
  43. package/dist/cli/{chunk-BXFHFbEd.js → chunk-UweLmfQS.js} +1 -1
  44. package/dist/cli/{chunk-CGiXWHTi2.js → chunk-gwpxl-0W2.js} +1 -1
  45. package/dist/cli/{chunk-NH8koEis2.js → chunk-nmDhxXH_2.js} +1 -1
  46. package/dist/cli/chunk-p0n_c-I2.js +1 -0
  47. package/dist/cli/{chunk-D7xP72La.js → chunk-q7r4FosZ.js} +1 -1
  48. package/dist/cli/cli.js +1 -1
  49. package/dist/cli/prerender/dsd-shell/prerender-dsd-shell.js +1 -1
  50. package/dist/electron/main.cjs +1 -1
  51. package/dist/headless-agent.js +1 -1
  52. package/dist/lib/{app-routes-BAEMLu9g.js → app-routes-CKkiX12g.js} +7 -2
  53. package/dist/lib/app-routes-CKkiX12g.js.map +1 -0
  54. package/dist/lib/components/index.js +26 -26
  55. package/dist/lib/components/settings/shadow-claw-accounts.js +1 -1
  56. package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
  57. package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
  58. package/dist/lib/components/settings/shadow-claw-git.js +1 -1
  59. package/dist/lib/components/settings/shadow-claw-integrations.js +1 -1
  60. package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
  61. package/dist/lib/components/settings/shadow-claw-mcp-remote.js +1 -1
  62. package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
  63. package/dist/lib/components/settings/shadow-claw-notifications.js +1 -1
  64. package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
  65. package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
  66. package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
  67. package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
  68. package/dist/lib/components/shadow-claw/utils/syncSlottedSidebarActiveLinks.d.ts +10 -0
  69. package/dist/lib/components/shadow-claw-a2ui.js +1 -1
  70. package/dist/lib/components/shadow-claw-accounts.js +1 -1
  71. package/dist/lib/components/shadow-claw-channel-config.js +1 -1
  72. package/dist/lib/components/shadow-claw-channels.js +1 -1
  73. package/dist/lib/components/shadow-claw-chat.js +1 -1
  74. package/dist/lib/components/shadow-claw-control-plane.js +1 -1
  75. package/dist/lib/components/shadow-claw-conversations.js +1 -1
  76. package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
  77. package/dist/lib/components/shadow-claw-files.js +1 -1
  78. package/dist/lib/components/shadow-claw-git.js +1 -1
  79. package/dist/lib/components/shadow-claw-integrations.js +1 -1
  80. package/dist/lib/components/shadow-claw-llm.js +1 -1
  81. package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
  82. package/dist/lib/components/shadow-claw-networking.js +1 -1
  83. package/dist/lib/components/shadow-claw-notifications.js +1 -1
  84. package/dist/lib/components/shadow-claw-page-header.js +1 -1
  85. package/dist/lib/components/shadow-claw-pages.js +1 -1
  86. package/dist/lib/components/shadow-claw-peerjs.js +1 -1
  87. package/dist/lib/components/shadow-claw-settings.js +1 -1
  88. package/dist/lib/components/shadow-claw-storage.js +1 -1
  89. package/dist/lib/components/shadow-claw-task-server.js +1 -1
  90. package/dist/lib/components/shadow-claw-tasks.js +1 -1
  91. package/dist/lib/components/shadow-claw-terminal.js +1 -1
  92. package/dist/lib/components/shadow-claw-tools.js +1 -1
  93. package/dist/lib/components/shadow-claw-webvm.js +1 -1
  94. package/dist/lib/components/shadow-claw.js +1 -1
  95. package/dist/lib/{config-CPHDmyTx.js → config-DZkF9LiO.js} +2 -2
  96. package/dist/lib/{config-CPHDmyTx.js.map → config-DZkF9LiO.js.map} +1 -1
  97. package/dist/lib/{configurePeerJs-BsJoycQd.js → configurePeerJs-B3IE9BY2.js} +3 -3
  98. package/dist/lib/{configurePeerJs-BsJoycQd.js.map → configurePeerJs-B3IE9BY2.js.map} +1 -1
  99. package/dist/lib/{connections-BdIru7bF.js → connections-CalJGWvZ.js} +2 -2
  100. package/dist/lib/{connections-BdIru7bF.js.map → connections-CalJGWvZ.js.map} +1 -1
  101. package/dist/lib/{downloadGroupFile-Dn0KsMlV.js → downloadGroupFile-DDE1fIhJ.js} +2 -2
  102. package/dist/lib/{downloadGroupFile-Dn0KsMlV.js.map → downloadGroupFile-DDE1fIhJ.js.map} +1 -1
  103. package/dist/lib/{file-viewer-BYrXXu-X.js → file-viewer-Bll2EoGc.js} +5 -5
  104. package/dist/lib/{file-viewer-BYrXXu-X.js.map → file-viewer-Bll2EoGc.js.map} +1 -1
  105. package/dist/lib/{getGroupDir-DF-RZO8X.js → getGroupDir-MHv7Lvmp.js} +4 -4
  106. package/dist/lib/{getGroupDir-DF-RZO8X.js.map → getGroupDir-MHv7Lvmp.js.map} +1 -1
  107. package/dist/lib/{git-s_0cgKm1.js → git-Bv_M3dgw.js} +3 -3
  108. package/dist/lib/{git-s_0cgKm1.js.map → git-Bv_M3dgw.js.map} +1 -1
  109. package/dist/lib/{iframe-sanitizer-DFdda1jJ.js → iframe-sanitizer-C7ZGDjEI.js} +2 -2
  110. package/dist/lib/{iframe-sanitizer-DFdda1jJ.js.map → iframe-sanitizer-C7ZGDjEI.js.map} +1 -1
  111. package/dist/lib/{iframe-storage-proxy-qrhZmQyO.js → iframe-storage-proxy-CR8ZYHPd.js} +2 -2
  112. package/dist/lib/{iframe-storage-proxy-qrhZmQyO.js.map → iframe-storage-proxy-CR8ZYHPd.js.map} +1 -1
  113. package/dist/lib/index.js +27 -27
  114. package/dist/lib/{initChatSplitResize-DuNlwCuI.js → initChatSplitResize-DiKTI-wk.js} +2 -2
  115. package/dist/lib/{initChatSplitResize-DuNlwCuI.js.map → initChatSplitResize-DiKTI-wk.js.map} +1 -1
  116. package/dist/lib/{initControlPlane-D4UZ4EhV.js → initControlPlane-CzjtQ4aM.js} +15 -15
  117. package/dist/lib/{initControlPlane-D4UZ4EhV.js.map → initControlPlane-CzjtQ4aM.js.map} +1 -1
  118. package/dist/lib/{markdown-CRRwbN9h.js → markdown-k8wA9LKy.js} +4 -4
  119. package/dist/lib/{markdown-CRRwbN9h.js.map → markdown-k8wA9LKy.js.map} +1 -1
  120. package/dist/lib/{mcp-reconnect-COdZ-cea.js → mcp-reconnect-CGIdfZnS.js} +2 -2
  121. package/dist/lib/{mcp-reconnect-COdZ-cea.js.map → mcp-reconnect-CGIdfZnS.js.map} +1 -1
  122. package/dist/lib/{memoryStorage-BsMe2FOQ.js → memoryStorage-DL-Bo3dh.js} +2 -2
  123. package/dist/lib/{memoryStorage-BsMe2FOQ.js.map → memoryStorage-DL-Bo3dh.js.map} +1 -1
  124. package/dist/lib/{orchestrator-D9f5fDCb.js → orchestrator-DKHCoikY.js} +11 -11
  125. package/dist/lib/{orchestrator-D9f5fDCb.js.map → orchestrator-DKHCoikY.js.map} +1 -1
  126. package/dist/lib/{orchestrator-CMN43L0F.js → orchestrator-Dn1ZOz9B.js} +12 -12
  127. package/dist/lib/{orchestrator-CMN43L0F.js.map → orchestrator-Dn1ZOz9B.js.map} +1 -1
  128. package/dist/lib/{peerjs-6u8KtenE.js → peerjs-BK41iBvP.js} +7 -7
  129. package/dist/lib/{peerjs-6u8KtenE.js.map → peerjs-BK41iBvP.js.map} +1 -1
  130. package/dist/lib/{push-client-DCnB2-OU.js → push-client-DKgVFD2Z.js} +3 -3
  131. package/dist/lib/{push-client-DCnB2-OU.js.map → push-client-DKgVFD2Z.js.map} +1 -1
  132. package/dist/lib/{readGroupFileBytes-nKNJ6sbl.js → readGroupFileBytes-CgU_UfGv.js} +2 -2
  133. package/dist/lib/{readGroupFileBytes-nKNJ6sbl.js.map → readGroupFileBytes-CgU_UfGv.js.map} +1 -1
  134. package/dist/lib/{shadow-claw-4x3LqlII.js → shadow-claw-CtCj5Rn_.js} +121 -16
  135. package/dist/lib/shadow-claw-CtCj5Rn_.js.map +1 -0
  136. package/dist/lib/{shadow-claw-a2ui-Dipe8nY2.js → shadow-claw-a2ui-CvK5w940.js} +2 -2
  137. package/dist/lib/{shadow-claw-a2ui-Dipe8nY2.js.map → shadow-claw-a2ui-CvK5w940.js.map} +1 -1
  138. package/dist/lib/{shadow-claw-accounts-BgCkz3Zv.js → shadow-claw-accounts-Br3XdHro.js} +3 -3
  139. package/dist/lib/{shadow-claw-accounts-BgCkz3Zv.js.map → shadow-claw-accounts-Br3XdHro.js.map} +1 -1
  140. package/dist/lib/{shadow-claw-channel-config-CIm_Bxd2.js → shadow-claw-channel-config-Da2dN19M.js} +3 -3
  141. package/dist/lib/{shadow-claw-channel-config-CIm_Bxd2.js.map → shadow-claw-channel-config-Da2dN19M.js.map} +1 -1
  142. package/dist/lib/{shadow-claw-channels-CaceK52s.js → shadow-claw-channels-BofYHgz8.js} +3 -3
  143. package/dist/lib/{shadow-claw-channels-CaceK52s.js.map → shadow-claw-channels-BofYHgz8.js.map} +1 -1
  144. package/dist/lib/{shadow-claw-chat-BD18-mAR.js → shadow-claw-chat-Dw32DPV2.js} +12 -12
  145. package/dist/lib/{shadow-claw-chat-BD18-mAR.js.map → shadow-claw-chat-Dw32DPV2.js.map} +1 -1
  146. package/dist/lib/{shadow-claw-control-plane-U6LsfRPm.js → shadow-claw-control-plane-CwFotFDh.js} +7 -7
  147. package/dist/lib/{shadow-claw-control-plane-U6LsfRPm.js.map → shadow-claw-control-plane-CwFotFDh.js.map} +1 -1
  148. package/dist/lib/{shadow-claw-conversations-CDsza_oB.js → shadow-claw-conversations-0UXge23k.js} +5 -5
  149. package/dist/lib/{shadow-claw-conversations-CDsza_oB.js.map → shadow-claw-conversations-0UXge23k.js.map} +1 -1
  150. package/dist/lib/{shadow-claw-file-viewer-CuDhkVcL.js → shadow-claw-file-viewer-CAsn9NxH.js} +10 -10
  151. package/dist/lib/{shadow-claw-file-viewer-CuDhkVcL.js.map → shadow-claw-file-viewer-CAsn9NxH.js.map} +1 -1
  152. package/dist/lib/{shadow-claw-files-BI0P3m8a.js → shadow-claw-files-xGGhsHNH.js} +9 -9
  153. package/dist/lib/{shadow-claw-files-BI0P3m8a.js.map → shadow-claw-files-xGGhsHNH.js.map} +1 -1
  154. package/dist/lib/{shadow-claw-git-xRApLEMN.js → shadow-claw-git-B606hcMU.js} +6 -6
  155. package/dist/lib/{shadow-claw-git-xRApLEMN.js.map → shadow-claw-git-B606hcMU.js.map} +1 -1
  156. package/dist/lib/{shadow-claw-integrations-B2e1Nfg1.js → shadow-claw-integrations-Bwq5cba1.js} +4 -4
  157. package/dist/lib/{shadow-claw-integrations-B2e1Nfg1.js.map → shadow-claw-integrations-Bwq5cba1.js.map} +1 -1
  158. package/dist/lib/{shadow-claw-llm-Bc2mWuGb.js → shadow-claw-llm-BgpcMBIy.js} +6 -6
  159. package/dist/lib/{shadow-claw-llm-Bc2mWuGb.js.map → shadow-claw-llm-BgpcMBIy.js.map} +1 -1
  160. package/dist/lib/{shadow-claw-mcp-remote-D_Bh3aeC.js → shadow-claw-mcp-remote-DvQCA-Bk.js} +4 -4
  161. package/dist/lib/{shadow-claw-mcp-remote-D_Bh3aeC.js.map → shadow-claw-mcp-remote-DvQCA-Bk.js.map} +1 -1
  162. package/dist/lib/{shadow-claw-networking-F5W3n5ci.js → shadow-claw-networking-Cxvf9c7E.js} +2 -2
  163. package/dist/lib/{shadow-claw-networking-F5W3n5ci.js.map → shadow-claw-networking-Cxvf9c7E.js.map} +1 -1
  164. package/dist/lib/{shadow-claw-notifications-lvMt9WJ1.js → shadow-claw-notifications-CGVcFYBy.js} +3 -3
  165. package/dist/lib/{shadow-claw-notifications-lvMt9WJ1.js.map → shadow-claw-notifications-CGVcFYBy.js.map} +1 -1
  166. package/dist/lib/{shadow-claw-page-header-6gq6EMqX.js → shadow-claw-page-header-DAYz3I_o.js} +2 -2
  167. package/dist/lib/{shadow-claw-page-header-6gq6EMqX.js.map → shadow-claw-page-header-DAYz3I_o.js.map} +1 -1
  168. package/dist/lib/{shadow-claw-pages-Bo8_z2S-.js → shadow-claw-pages-BLeEZb9k.js} +24 -12
  169. package/dist/lib/shadow-claw-pages-BLeEZb9k.js.map +1 -0
  170. package/dist/lib/{shadow-claw-peerjs-DRTLCVDQ.js → shadow-claw-peerjs-BcFnbK74.js} +3 -3
  171. package/dist/lib/{shadow-claw-peerjs-DRTLCVDQ.js.map → shadow-claw-peerjs-BcFnbK74.js.map} +1 -1
  172. package/dist/lib/{shadow-claw-settings-D00B4p4L.js → shadow-claw-settings-B7o0Z4hu.js} +9 -9
  173. package/dist/lib/{shadow-claw-settings-D00B4p4L.js.map → shadow-claw-settings-B7o0Z4hu.js.map} +1 -1
  174. package/dist/lib/{shadow-claw-storage-DgMe7-Zo.js → shadow-claw-storage-afMVqB7E.js} +5 -5
  175. package/dist/lib/{shadow-claw-storage-DgMe7-Zo.js.map → shadow-claw-storage-afMVqB7E.js.map} +1 -1
  176. package/dist/lib/{shadow-claw-task-server-D103YOuI.js → shadow-claw-task-server-B9-MQjl6.js} +2 -2
  177. package/dist/lib/{shadow-claw-task-server-D103YOuI.js.map → shadow-claw-task-server-B9-MQjl6.js.map} +1 -1
  178. package/dist/lib/{shadow-claw-tasks-6OhALkq1.js → shadow-claw-tasks-Dc4BC-t-.js} +8 -8
  179. package/dist/lib/{shadow-claw-tasks-6OhALkq1.js.map → shadow-claw-tasks-Dc4BC-t-.js.map} +1 -1
  180. package/dist/lib/{shadow-claw-terminal-BGtxA1qD.js → shadow-claw-terminal-BINcTdsk.js} +2 -2
  181. package/dist/lib/{shadow-claw-terminal-BGtxA1qD.js.map → shadow-claw-terminal-BINcTdsk.js.map} +1 -1
  182. package/dist/lib/{shadow-claw-tools-OeIwAnnd.js → shadow-claw-tools-BjFgXNLR.js} +7 -7
  183. package/dist/lib/{shadow-claw-tools-OeIwAnnd.js.map → shadow-claw-tools-BjFgXNLR.js.map} +1 -1
  184. package/dist/lib/{shadow-claw-webvm-gVFZ197u.js → shadow-claw-webvm-Xe3ByMDw.js} +3 -3
  185. package/dist/lib/{shadow-claw-webvm-gVFZ197u.js.map → shadow-claw-webvm-Xe3ByMDw.js.map} +1 -1
  186. package/dist/lib/subsystems/mcp/webmcp.d.ts +64 -0
  187. package/dist/lib/{syncWebMcpRegistration-Bbph0XZl.js → syncWebMcpRegistration-D7alChz0.js} +21 -6
  188. package/dist/lib/syncWebMcpRegistration-D7alChz0.js.map +1 -0
  189. package/dist/lib/{tools-D0OlSzMD.js → tools-Cmhpk3X8.js} +4 -4
  190. package/dist/lib/{tools-D0OlSzMD.js.map → tools-Cmhpk3X8.js.map} +1 -1
  191. package/dist/lib/utils/index.js +1 -1
  192. package/dist/lib/utils/namespacedStorage.js +1 -1
  193. package/dist/lib/utils/utils.js +1 -1
  194. package/dist/lib/{utils-DYdrO2KI.js → utils-CzgKe_XZ.js} +4 -4
  195. package/dist/lib/{utils-DYdrO2KI.js.map → utils-CzgKe_XZ.js.map} +1 -1
  196. package/dist/lib/{webmcp-D2bocsgh.js → webmcp-oEP9YpR2.js} +119 -3
  197. package/dist/lib/{webmcp-D2bocsgh.js.map → webmcp-oEP9YpR2.js.map} +1 -1
  198. package/dist/public/.well-known/mcp/server-card.json +1 -1
  199. package/dist/public/.well-known/mcp.json +1 -1
  200. package/dist/public/AGENTS.md +8 -2
  201. package/dist/public/README.md +2 -1
  202. package/dist/public/agent.worker.js +1 -1
  203. package/dist/public/app-routes-C6-H2zPH.js +1 -0
  204. package/dist/public/components/shadow-claw/shadow-claw.css +1 -1
  205. package/dist/public/components/shadow-claw/shadow-claw.html +1 -1
  206. package/dist/public/components/shadow-claw-pages/shadow-claw-pages.css +1 -1
  207. package/dist/public/{config-D4lVqMs8.js → config-Dewnqegf.js} +1 -1
  208. package/dist/public/{configurePeerJs-DDOAVSaH.js → configurePeerJs-CaPU2sN5.js} +1 -1
  209. package/dist/public/{connections-CiukjGiH.js → connections-CwE7jE9l.js} +1 -1
  210. package/dist/public/{custom-element-security-piU2U-Ec.js → custom-element-security-DLgHMf5R.js} +1 -1
  211. package/dist/public/docs/README.md +1 -0
  212. package/dist/public/docs/example/article/index.html +4 -4
  213. package/dist/public/docs/guides/publishing-to-github-pages.md +95 -6
  214. package/dist/public/docs/publishing/index.html +4 -4
  215. package/dist/public/docs/skill-creator/index.html +4 -4
  216. package/dist/public/docs/subsystems/pages.md +10 -3
  217. package/dist/public/docs/subsystems/theming.md +242 -0
  218. package/dist/public/docs/subsystems/webmcp.md +89 -1
  219. package/dist/public/{downloadGroupFile-BiZQYY-O.js → downloadGroupFile-ChWHuap_.js} +1 -1
  220. package/dist/public/e2e/README.md +3 -2
  221. package/dist/public/{e2e-bridge-CybB810Q.js → e2e-bridge-BkaldjV2.js} +1 -1
  222. package/dist/public/{file-viewer-DLUBvOVD.js → file-viewer-Df4qUJCn.js} +1 -1
  223. package/dist/public/{getGroupDir-CLz5c8cg.js → getGroupDir-CeSr4fzS.js} +1 -1
  224. package/dist/public/{git-Ba8AeviI.js → git-Bscc1tK-.js} +2 -2
  225. package/dist/public/{iframe-sanitizer-CKOO7cxp.js → iframe-sanitizer-BVdkQsor.js} +1 -1
  226. package/dist/public/{iframe-storage-proxy-BvRiccH0.js → iframe-storage-proxy-Cg8aFw7o.js} +1 -1
  227. package/dist/public/index.css +1 -1
  228. package/dist/public/index.html +4 -4
  229. package/dist/public/index.js +1 -1
  230. package/dist/public/{initChatSplitResize-osJXM2gu.js → initChatSplitResize-C3Rp1LeZ.js} +1 -1
  231. package/dist/public/{initControlPlane-CNggzsRw.js → initControlPlane-C1pnzG16.js} +1 -1
  232. package/dist/public/llms.txt +2 -2
  233. package/dist/public/main/index.html +4 -4
  234. package/dist/public/main/memory/index.html +4 -4
  235. package/dist/public/{markdown-CZA-Ye2Q.js → markdown-D3A902nT.js} +1 -1
  236. package/dist/public/{mcp-reconnect-BK1bYBdC.js → mcp-reconnect-BJWxQBm_.js} +1 -1
  237. package/dist/public/{memoryStorage-Bew1X8Uy.js → memoryStorage-ykv-Ri-y.js} +1 -1
  238. package/dist/public/{orchestrator-D6tel2Zp.js → orchestrator-BVnC4Vtt.js} +2 -2
  239. package/dist/public/{orchestrator-Dc_Q73La.js → orchestrator-CQcc7OFA.js} +2 -2
  240. package/dist/public/{peerjs-CYs1F7sq.js → peerjs-CYC2cI1Y.js} +1 -1
  241. package/dist/public/{push-client-_HUyJlFJ.js → push-client-BJrnOULM.js} +1 -1
  242. package/dist/public/service-worker/fetch-proxy.js +1 -1
  243. package/dist/public/service-worker.js +1 -1
  244. package/dist/public/{shadow-claw-Dabb2AEp.js → shadow-claw-WwfOu-tu.js} +33 -3
  245. package/dist/public/{shadow-claw-accounts-BqGrm47Z.js → shadow-claw-accounts-BFZxrPsH.js} +1 -1
  246. package/dist/public/{shadow-claw-channels-Ci2UPaaA.js → shadow-claw-channels-C0w0c1EF.js} +1 -1
  247. package/dist/public/{shadow-claw-chat-BxR6cBYQ.js → shadow-claw-chat-DIJ0A-QN.js} +1 -1
  248. package/dist/public/{shadow-claw-control-plane-C1A-CZ9H.js → shadow-claw-control-plane-DZoxUd-1.js} +2 -2
  249. package/dist/public/{shadow-claw-conversations-DcwG05-H.js → shadow-claw-conversations-DMyG_5zj.js} +1 -1
  250. package/dist/public/{shadow-claw-file-viewer-CDs1QGXk.js → shadow-claw-file-viewer-DYgZjZb9.js} +1 -1
  251. package/dist/public/{shadow-claw-files-B774Xz1d.js → shadow-claw-files-DIOUdKJr.js} +1 -1
  252. package/dist/public/{shadow-claw-git-CTIPP0vs.js → shadow-claw-git-if5S0QJr.js} +2 -2
  253. package/dist/public/{shadow-claw-integrations-CjtkA6l0.js → shadow-claw-integrations-BQt4hcWe.js} +1 -1
  254. package/dist/public/{shadow-claw-llm-DfmITHde.js → shadow-claw-llm-9uf1KFA0.js} +2 -2
  255. package/dist/public/{shadow-claw-mcp-remote-BPuV22So.js → shadow-claw-mcp-remote-COpNIzJd.js} +1 -1
  256. package/dist/public/{shadow-claw-networking-DEMMygy0.js → shadow-claw-networking-AOVRUn6B.js} +1 -1
  257. package/dist/public/{shadow-claw-notifications-B9Xhcj1P.js → shadow-claw-notifications-CKB-W1TA.js} +1 -1
  258. package/dist/public/{shadow-claw-page-header-CAXokjQy.js → shadow-claw-page-header-D4LmUigA.js} +1 -1
  259. package/dist/public/{shadow-claw-pages-BRQw8bTm.js → shadow-claw-pages-BpHRY4vH.js} +12 -3
  260. package/dist/public/{shadow-claw-settings-BGrDNyqh.js → shadow-claw-settings-CE-aUo_J.js} +3 -3
  261. package/dist/public/{shadow-claw-storage-DK3pf11w.js → shadow-claw-storage-CFKC-Y3V.js} +1 -1
  262. package/dist/public/{shadow-claw-task-server-CMp5Vjza.js → shadow-claw-task-server-B_ZjqK4B.js} +1 -1
  263. package/dist/public/{shadow-claw-tasks-BO8aXM2B.js → shadow-claw-tasks-CGsEv48K.js} +1 -1
  264. package/dist/public/{shadow-claw-terminal-BSeTuyDa.js → shadow-claw-terminal-DcaS7cPH.js} +1 -1
  265. package/dist/public/{shadow-claw-tools-Bj6DLZ-2.js → shadow-claw-tools-Cnu9hKy0.js} +1 -1
  266. package/dist/public/{shadow-claw-webvm-M7d5RH8H.js → shadow-claw-webvm-BB8SFvJ8.js} +1 -1
  267. package/dist/public/syncWebMcpRegistration-D2Zx4oA1.js +1 -0
  268. package/dist/public/theme-init.js +1 -1
  269. package/dist/public/{tools-nysPKnGT.js → tools-sOLCHTj8.js} +1 -1
  270. package/dist/public/{webmcp-Bo3KTgRb.js → webmcp-YFt6vM1_.js} +1 -1
  271. package/dist/server.js +188 -188
  272. package/package.json +1 -1
  273. package/src/cli/build/build.ts +18 -11
  274. package/src/cli/prerender/dsd-shell/prerender-dsd-shell.test.ts +4 -1
  275. package/src/cli/prerender/dsd-shell/prerender-dsd-shell.ts +13 -1
  276. package/src/cli/prerender/pretty-paths/prerender-pretty-paths.ts +22 -0
  277. package/src/cli/prerender/utils/insert-before-closing-head.test.ts +34 -1
  278. package/src/cli/prerender/utils/insert-before-closing-head.ts +20 -6
  279. package/src/cli/site-config/apply.test.ts +90 -0
  280. package/src/cli/site-config/apply.ts +189 -22
  281. package/src/components/shadow-claw/shadow-claw.css +26 -0
  282. package/src/components/shadow-claw/shadow-claw.html +4 -0
  283. package/src/components/shadow-claw/utils/applyRoute.ts +3 -0
  284. package/src/components/shadow-claw/utils/bindEventListeners.test.ts +6 -0
  285. package/src/components/shadow-claw/utils/bindEventListeners.ts +30 -1
  286. package/src/components/shadow-claw/utils/getRoute.test.ts +52 -0
  287. package/src/components/shadow-claw/utils/getRoute.ts +18 -0
  288. package/src/components/shadow-claw/utils/navigateToRoute.test.ts +21 -0
  289. package/src/components/shadow-claw/utils/navigateToRoute.ts +10 -0
  290. package/src/components/shadow-claw/utils/sidebarVisibility.ts +12 -4
  291. package/src/components/shadow-claw/utils/syncSlottedSidebarActiveLinks.test.ts +93 -0
  292. package/src/components/shadow-claw/utils/syncSlottedSidebarActiveLinks.ts +100 -0
  293. package/src/components/shadow-claw-pages/shadow-claw-pages.css +10 -1
  294. package/src/components/shadow-claw-pages/utils/removePreviewIframe.ts +3 -0
  295. package/src/core/orchestrator/utils/syncWebMcpRegistration.test.ts +52 -0
  296. package/src/core/orchestrator/utils/syncWebMcpRegistration.ts +28 -1
  297. package/src/server/middleware/static-files.test.ts +36 -0
  298. package/src/server/middleware/static-files.ts +14 -6
  299. package/src/storage/staticRouting.test.ts +36 -0
  300. package/src/storage/staticRouting.ts +31 -3
  301. package/src/subsystems/mcp/webmcp.test.ts +255 -0
  302. package/src/subsystems/mcp/webmcp.ts +253 -0
  303. package/dist/cli/chunk-00GAzVPl2.js +0 -1
  304. package/dist/cli/chunk-2hnFoNNC.js +0 -1
  305. package/dist/cli/chunk-BKQL4nzF2.js +0 -1
  306. package/dist/cli/chunk-BQ4K3fqj2.js +0 -1
  307. package/dist/cli/chunk-BVCGo6uf2.js +0 -1
  308. package/dist/cli/chunk-Bc9nRNyN.js +0 -11
  309. package/dist/cli/chunk-BcTH_-FL.js +0 -1
  310. package/dist/cli/chunk-BmD_sPRt.js +0 -1
  311. package/dist/cli/chunk-BsxNqqer.js +0 -1
  312. package/dist/cli/chunk-CCcF5T-c.js +0 -1
  313. package/dist/cli/chunk-CFhvwUeL.js +0 -91
  314. package/dist/cli/chunk-CwWtvULn.js +0 -1
  315. package/dist/cli/chunk-DID5VvOG.js +0 -17
  316. package/dist/cli/chunk-Drf-hXIR2.js +0 -1
  317. package/dist/cli/chunk-Dt5HNYVi.js +0 -1
  318. package/dist/cli/chunk-DwZQi9Ax.js +0 -1
  319. package/dist/cli/chunk-m9ZX7TyF2.js +0 -1
  320. package/dist/lib/app-routes-BAEMLu9g.js.map +0 -1
  321. package/dist/lib/shadow-claw-4x3LqlII.js.map +0 -1
  322. package/dist/lib/shadow-claw-pages-Bo8_z2S-.js.map +0 -1
  323. package/dist/lib/syncWebMcpRegistration-Bbph0XZl.js.map +0 -1
  324. package/dist/public/app-routes-BMQ4HFaM.js +0 -1
  325. package/dist/public/syncWebMcpRegistration-4bT0YUyZ.js +0 -1
@@ -112,15 +112,18 @@ export function registerStaticFilesMiddleware(app: Express, rootPath: string) {
112
112
  }
113
113
 
114
114
  const urlPathname = new URL(req.url || "/", "http://localhost").pathname;
115
+ if (
116
+ isSpaShellRequest(req, requestPath) ||
117
+ isSpaShellRequest(req, urlPathname)
118
+ ) {
119
+ res.sendFile(path.join(rootPath, "index.html"));
120
+
121
+ return;
122
+ }
123
+
115
124
  const filePath = path.join(rootPath, urlPathname);
116
125
  fs.stat(filePath, (err, stats) => {
117
126
  if (err || !stats) {
118
- if (isSpaShellRequest(req, requestPath)) {
119
- res.sendFile(path.join(rootPath, "index.html"));
120
-
121
- return;
122
- }
123
-
124
127
  // Check if request has a subpath prefix matching a root file (e.g. /shadow-claw/index.js -> /index.js)
125
128
  const strippedSegmentPath = requestPath.replace(/^\/[^/]+/, "");
126
129
  if (strippedSegmentPath) {
@@ -212,6 +215,11 @@ export function registerStaticFilesMiddleware(app: Express, rootPath: string) {
212
215
  } else {
213
216
  res.sendFile(indexPath);
214
217
  }
218
+ } else if (
219
+ isSpaShellRequest(req, requestPath) ||
220
+ isSpaShellRequest(req, urlPathname)
221
+ ) {
222
+ res.sendFile(path.join(rootPath, "index.html"));
215
223
  } else {
216
224
  next();
217
225
  }
@@ -73,12 +73,29 @@ describe("staticRouting", () => {
73
73
  "/pages/main/posts/2026-07-01_03-37-38.md": {
74
74
  prettyPath: "/2026/06/30/on-developing-loops/",
75
75
  },
76
+ "/pages/main/index.html": {
77
+ prettyPath: "/",
78
+ },
76
79
  "/pages/main/about.md": {
77
80
  prettyPath: "/about",
78
81
  },
79
82
  },
80
83
  };
81
84
 
85
+ // Test root path "/"
86
+ expect(resolvePrettyPathToRoute("/", manifest)).toEqual({
87
+ page: "pages",
88
+ groupId: "br:main",
89
+ path: "index.html",
90
+ });
91
+
92
+ // Test root index.html
93
+ expect(resolvePrettyPathToRoute("/index.html", manifest)).toEqual({
94
+ page: "pages",
95
+ groupId: "br:main",
96
+ path: "index.html",
97
+ });
98
+
82
99
  // Test with explicit manifest
83
100
  expect(
84
101
  resolvePrettyPathToRoute("/2026/06/30/on-developing-loops/", manifest),
@@ -155,6 +172,25 @@ describe("staticRouting", () => {
155
172
  manifest,
156
173
  ),
157
174
  ).toBeNull();
175
+
176
+ const manifestWithRoot: StaticRoutesManifest = {
177
+ routes: {
178
+ "/pages/main/index.html": {
179
+ prettyPath: "/",
180
+ },
181
+ },
182
+ };
183
+
184
+ expect(
185
+ resolveRouteToPrettyPath(
186
+ { page: "pages", groupId: "br:main" },
187
+ manifestWithRoot,
188
+ ),
189
+ ).toBe("/");
190
+
191
+ expect(resolveRouteToPrettyPath({ page: "pages" }, manifestWithRoot)).toBe(
192
+ "/",
193
+ );
158
194
  });
159
195
 
160
196
  it("fetches static routing manifest when not embedded in DOM", async () => {
@@ -214,9 +214,6 @@ export function resolvePrettyPathToRoute(
214
214
  }
215
215
 
216
216
  const normalizedPath = normalizePrettyPathKey(pathname);
217
- if (!normalizedPath) {
218
- return null;
219
- }
220
217
 
221
218
  for (const [canonicalKey, routeDef] of Object.entries(
222
219
  routesManifest.routes,
@@ -363,6 +360,29 @@ export function resolveRouteToPrettyPath(
363
360
  candidateKeys.push(`pages/${normalizedGroupId}/${cleanPath}`);
364
361
  candidateKeys.push(`/pages/${groupId}/${cleanPath}`);
365
362
  }
363
+ } else if (page === "pages" && !path) {
364
+ if (normalizedGroupId === "main" || !normalizedGroupId) {
365
+ candidateKeys.push(
366
+ "/pages/main/index.html",
367
+ "pages/main/index.html",
368
+ "/pages/br:main/index.html",
369
+ "/pages/br-main/index.html",
370
+ "/main/index.html",
371
+ "main/index.html",
372
+ "/index.html",
373
+ "index.html",
374
+ "/pages/main",
375
+ "pages/main",
376
+ "/pages",
377
+ "pages",
378
+ );
379
+ } else if (normalizedGroupId) {
380
+ candidateKeys.push(
381
+ `/pages/${normalizedGroupId}/index.html`,
382
+ `pages/${normalizedGroupId}/index.html`,
383
+ `/pages/${groupId}/index.html`,
384
+ );
385
+ }
366
386
  } else if (page === "files" && path) {
367
387
  const cleanPath = trimSlashes(path);
368
388
  if (normalizedGroupId) {
@@ -386,5 +406,13 @@ export function resolveRouteToPrettyPath(
386
406
  }
387
407
  }
388
408
 
409
+ if (page === "pages" && !path) {
410
+ for (const routeDef of Object.values(routesManifest.routes)) {
411
+ if (routeDef && routeDef.prettyPath === "/") {
412
+ return "/";
413
+ }
414
+ }
415
+ }
416
+
389
417
  return null;
390
418
  }
@@ -817,4 +817,259 @@ describe("webmcp integration", () => {
817
817
  errorSpy.mockRestore();
818
818
  });
819
819
  });
820
+
821
+ describe("WebMCP lifecycle events (PR #245 / Chrome 156+)", () => {
822
+ let originalWindowOntoolactivated: any;
823
+ let originalWindowOntoolcancel: any;
824
+
825
+ beforeEach(() => {
826
+ originalWindowOntoolactivated = (globalThis as any).window
827
+ ?.ontoolactivated;
828
+ originalWindowOntoolcancel = (globalThis as any).window?.ontoolcancel;
829
+ if (typeof window !== "undefined") {
830
+ delete (window as any).ontoolactivated;
831
+ delete (window as any).ontoolcancel;
832
+ }
833
+ });
834
+
835
+ afterEach(() => {
836
+ if (typeof window !== "undefined") {
837
+ if (originalWindowOntoolactivated !== undefined) {
838
+ (window as any).ontoolactivated = originalWindowOntoolactivated;
839
+ } else {
840
+ delete (window as any).ontoolactivated;
841
+ }
842
+ if (originalWindowOntoolcancel !== undefined) {
843
+ (window as any).ontoolcancel = originalWindowOntoolcancel;
844
+ } else {
845
+ delete (window as any).ontoolcancel;
846
+ }
847
+ }
848
+ });
849
+
850
+ describe("getWebMcpEventTarget", () => {
851
+ it("resolves to document.modelContext when ontoolactivated is in document.modelContext (Chrome 156+ / PR #245)", async () => {
852
+ const { getWebMcpEventTarget } = await import("./webmcp.js");
853
+
854
+ const mockTarget = new EventTarget();
855
+ (mockTarget as any).ontoolactivated = null;
856
+ (mockTarget as any).ontoolcancel = null;
857
+
858
+ Object.defineProperty((globalThis as any).document, "modelContext", {
859
+ configurable: true,
860
+ value: mockTarget,
861
+ });
862
+
863
+ // Also define ontoolactivated on window to ensure modelContext takes precedence
864
+ if (typeof window !== "undefined") {
865
+ (window as any).ontoolactivated = null;
866
+ }
867
+
868
+ expect(getWebMcpEventTarget("toolactivated")).toBe(mockTarget);
869
+ expect(getWebMcpEventTarget("toolcancel")).toBe(mockTarget);
870
+ });
871
+
872
+ it("falls back to window when ontoolactivated is only present on window (legacy Chrome < 156)", async () => {
873
+ const { getWebMcpEventTarget } = await import("./webmcp.js");
874
+
875
+ const mockModelContext = {
876
+ registerTool: jest.fn(),
877
+ // No ontoolactivated or ontoolcancel
878
+ };
879
+
880
+ Object.defineProperty((globalThis as any).document, "modelContext", {
881
+ configurable: true,
882
+ value: mockModelContext,
883
+ });
884
+
885
+ if (typeof window !== "undefined") {
886
+ (window as any).ontoolactivated = null;
887
+ (window as any).ontoolcancel = null;
888
+ }
889
+
890
+ expect(getWebMcpEventTarget("toolactivated")).toBe(window);
891
+ expect(getWebMcpEventTarget("toolcancel")).toBe(window);
892
+ });
893
+
894
+ it("resolves to navigator.modelContext if document.modelContext is absent (Chrome < 152)", async () => {
895
+ const { getWebMcpEventTarget } = await import("./webmcp.js");
896
+
897
+ delete ((globalThis as any).document as any).modelContext;
898
+
899
+ const navTarget = new EventTarget();
900
+ (navTarget as any).ontoolactivated = null;
901
+
902
+ Object.defineProperty((globalThis as any).navigator, "modelContext", {
903
+ configurable: true,
904
+ value: navTarget,
905
+ });
906
+
907
+ expect(getWebMcpEventTarget("toolactivated")).toBe(navTarget);
908
+
909
+ delete ((globalThis as any).navigator as any).modelContext;
910
+ });
911
+
912
+ it("prefers modelContext when neither target has on{type} property but modelContext is an EventTarget", async () => {
913
+ const { getWebMcpEventTarget } = await import("./webmcp.js");
914
+
915
+ const mockTarget = new EventTarget();
916
+ Object.defineProperty((globalThis as any).document, "modelContext", {
917
+ configurable: true,
918
+ value: mockTarget,
919
+ });
920
+
921
+ expect(getWebMcpEventTarget("toolactivated")).toBe(mockTarget);
922
+ expect(getWebMcpEventTarget()).toBe(mockTarget);
923
+ });
924
+
925
+ it("falls back to window if modelContext lacks addEventListener", async () => {
926
+ const { getWebMcpEventTarget } = await import("./webmcp.js");
927
+
928
+ Object.defineProperty((globalThis as any).document, "modelContext", {
929
+ configurable: true,
930
+ value: {
931
+ // Not an EventTarget
932
+ registerTool: jest.fn(),
933
+ },
934
+ });
935
+
936
+ expect(getWebMcpEventTarget("toolactivated")).toBe(window);
937
+ });
938
+ });
939
+
940
+ describe("addWebMcpEventListener and convenience helpers", () => {
941
+ it("listens to toolactivated on document.modelContext in Chrome 156+", async () => {
942
+ const { addWebMcpEventListener } = await import("./webmcp.js");
943
+
944
+ const mockTarget = new EventTarget();
945
+ (mockTarget as any).ontoolactivated = null;
946
+
947
+ Object.defineProperty((globalThis as any).document, "modelContext", {
948
+ configurable: true,
949
+ value: mockTarget,
950
+ });
951
+
952
+ const listener = jest.fn();
953
+ const unsubscribe = addWebMcpEventListener("toolactivated", listener);
954
+
955
+ const event = new CustomEvent("toolactivated");
956
+ (event as any).toolName = "read_file";
957
+ mockTarget.dispatchEvent(event);
958
+
959
+ expect(listener).toHaveBeenCalledTimes(1);
960
+ expect(listener).toHaveBeenCalledWith(
961
+ expect.objectContaining({ toolName: "read_file" }),
962
+ );
963
+
964
+ // Unsubscribe should remove the listener
965
+ unsubscribe();
966
+ mockTarget.dispatchEvent(event);
967
+ expect(listener).toHaveBeenCalledTimes(1);
968
+ });
969
+
970
+ it("normalizes toolName from detail.toolName if event.toolName is not directly set", async () => {
971
+ const { onWebMcpToolActivated } = await import("./webmcp.js");
972
+
973
+ const mockTarget = new EventTarget();
974
+ (mockTarget as any).ontoolactivated = null;
975
+
976
+ Object.defineProperty((globalThis as any).document, "modelContext", {
977
+ configurable: true,
978
+ value: mockTarget,
979
+ });
980
+
981
+ const listener = jest.fn();
982
+ const unsubscribe = onWebMcpToolActivated(listener);
983
+
984
+ const legacyEvent = new CustomEvent("toolactivated", {
985
+ detail: { toolName: "bash" },
986
+ });
987
+ mockTarget.dispatchEvent(legacyEvent);
988
+
989
+ expect(listener).toHaveBeenCalledTimes(1);
990
+ expect(listener).toHaveBeenCalledWith(
991
+ expect.objectContaining({ toolName: "bash" }),
992
+ );
993
+
994
+ unsubscribe();
995
+ });
996
+
997
+ it("listens to toolcancel on window in legacy Chrome < 156", async () => {
998
+ const { onWebMcpToolCancel } = await import("./webmcp.js");
999
+
1000
+ delete ((globalThis as any).document as any).modelContext;
1001
+ (window as any).ontoolcancel = null;
1002
+
1003
+ const listener = jest.fn();
1004
+ const unsubscribe = onWebMcpToolCancel(listener);
1005
+
1006
+ const event = new CustomEvent("toolcancel");
1007
+ (event as any).toolName = "fetch_url";
1008
+ window.dispatchEvent(event);
1009
+
1010
+ expect(listener).toHaveBeenCalledTimes(1);
1011
+ expect(listener).toHaveBeenCalledWith(
1012
+ expect.objectContaining({ toolName: "fetch_url" }),
1013
+ );
1014
+
1015
+ unsubscribe();
1016
+ window.dispatchEvent(event);
1017
+ expect(listener).toHaveBeenCalledTimes(1);
1018
+ });
1019
+
1020
+ it("automatically cleans up when AbortSignal is aborted", async () => {
1021
+ const { onWebMcpToolActivated } = await import("./webmcp.js");
1022
+
1023
+ const mockTarget = new EventTarget();
1024
+ (mockTarget as any).ontoolactivated = null;
1025
+
1026
+ Object.defineProperty((globalThis as any).document, "modelContext", {
1027
+ configurable: true,
1028
+ value: mockTarget,
1029
+ });
1030
+
1031
+ const controller = new AbortController();
1032
+ const listener = jest.fn();
1033
+ onWebMcpToolActivated(listener, { signal: controller.signal });
1034
+
1035
+ controller.abort();
1036
+
1037
+ const event = new CustomEvent("toolactivated");
1038
+ (event as any).toolName = "write_file";
1039
+ mockTarget.dispatchEvent(event);
1040
+
1041
+ expect(listener).not.toHaveBeenCalled();
1042
+ });
1043
+
1044
+ it("supports listenBoth: true and deduplicates events within same tick", async () => {
1045
+ const { addWebMcpEventListener } = await import("./webmcp.js");
1046
+
1047
+ const mockTarget = new EventTarget();
1048
+ (mockTarget as any).ontoolactivated = null;
1049
+
1050
+ Object.defineProperty((globalThis as any).document, "modelContext", {
1051
+ configurable: true,
1052
+ value: mockTarget,
1053
+ });
1054
+
1055
+ const listener = jest.fn();
1056
+ const unsubscribe = addWebMcpEventListener("toolactivated", listener, {
1057
+ listenBoth: true,
1058
+ });
1059
+
1060
+ const evt1 = new CustomEvent("toolactivated");
1061
+ (evt1 as any).toolName = "list_files";
1062
+ const evt2 = new CustomEvent("toolactivated");
1063
+ (evt2 as any).toolName = "list_files";
1064
+
1065
+ // Dispatch on both targets
1066
+ mockTarget.dispatchEvent(evt1);
1067
+ window.dispatchEvent(evt2);
1068
+
1069
+ expect(listener).toHaveBeenCalledTimes(1);
1070
+
1071
+ unsubscribe();
1072
+ });
1073
+ });
1074
+ });
820
1075
  });
@@ -343,6 +343,259 @@ export function isWebMcpSupported(): boolean {
343
343
  return !!getModelContextApi();
344
344
  }
345
345
 
346
+ /**
347
+ * Event fired when a tool execution begins (PR #245 / Chrome 156+).
348
+ * Dispatched on `document.modelContext` in Chrome 156+, or `window` in Chrome < 156.
349
+ */
350
+ export interface WebMcpToolActivatedEvent extends Event {
351
+ readonly toolName: string;
352
+ }
353
+
354
+ /**
355
+ * Event fired when a tool execution is cancelled (PR #245 / Chrome 156+).
356
+ * Dispatched on `document.modelContext` in Chrome 156+, or `window` in Chrome < 156.
357
+ */
358
+ export interface WebMcpToolCancelEvent extends Event {
359
+ readonly toolName: string;
360
+ }
361
+
362
+ export type WebMcpEventTarget = EventTarget & {
363
+ addEventListener: (type: string, listener: any, options?: any) => void;
364
+ removeEventListener: (type: string, listener: any, options?: any) => void;
365
+ };
366
+
367
+ export interface WebMcpEventListenerOptions extends AddEventListenerOptions {
368
+ /**
369
+ * If true, also attaches a fallback listener to window when modelContext is selected
370
+ * (or vice versa), deduplicating events by toolName within the same tick if both fire.
371
+ */
372
+ listenBoth?: boolean;
373
+ }
374
+
375
+ /**
376
+ * Resolves the appropriate EventTarget for WebMCP lifecycle events
377
+ * (`toolactivated` and `toolcancel`) with backwards compatibility.
378
+ *
379
+ * Starting in Chrome 156.0.8076.0 (PR #245), `ontoolactivated` and `ontoolcancel`
380
+ * event handler properties and lifecycle events moved from `window` to `document.modelContext`.
381
+ * In Chrome < 156, these events were fired on `window`.
382
+ *
383
+ * This function practices robust feature detection and graceful degradation:
384
+ * 1. Safely checks for existence of `document` and `window` to avoid ReferenceErrors
385
+ * in non-DOM / headless / Node.js environments.
386
+ * 2. Checks if `on${type}` is present in `document.modelContext` (or `navigator.modelContext`).
387
+ * If present and it supports `addEventListener`, `modelContext` is returned.
388
+ * 3. Checks if `on${type}` is present in `window`. If present and `window` supports
389
+ * `addEventListener`, `window` is returned (legacy Chrome < 156 path).
390
+ * 4. Fallback: If neither has `on${type}` (e.g. polyfill, synthetic mock, or uninitialized prototype),
391
+ * prefers `modelContext` if it supports `addEventListener`, otherwise falls back to `window`.
392
+ * 5. Returns `null` if no valid EventTarget is found.
393
+ */
394
+ export function getWebMcpEventTarget(
395
+ type?: "toolactivated" | "toolcancel" | string,
396
+ ): WebMcpEventTarget | null {
397
+ const doc = typeof document !== "undefined" ? document : undefined;
398
+ const win = typeof window !== "undefined" ? window : undefined;
399
+ const nav = typeof navigator !== "undefined" ? navigator : undefined;
400
+
401
+ const modelContext: any =
402
+ (doc as any)?.modelContext ?? (nav as any)?.modelContext;
403
+
404
+ const hasModelContextListener =
405
+ modelContext && typeof modelContext.addEventListener === "function";
406
+ const hasWindowListener =
407
+ win && typeof (win as any).addEventListener === "function";
408
+
409
+ if (type) {
410
+ const handlerKey = `on${type}`;
411
+
412
+ // 1. Chrome 156+ path (PR #245): ontoolactivated / ontoolcancel on document.modelContext
413
+ if (modelContext && handlerKey in modelContext && hasModelContextListener) {
414
+ return modelContext as WebMcpEventTarget;
415
+ }
416
+
417
+ // 2. Chrome < 156 legacy path: ontoolactivated / ontoolcancel on window
418
+ if (win && handlerKey in win && hasWindowListener) {
419
+ return win as WebMcpEventTarget;
420
+ }
421
+ }
422
+
423
+ // 3. Fallback when neither target explicitly reflects on${type}
424
+ if (hasModelContextListener) {
425
+ return modelContext as WebMcpEventTarget;
426
+ }
427
+
428
+ if (hasWindowListener) {
429
+ return win as WebMcpEventTarget;
430
+ }
431
+
432
+ return null;
433
+ }
434
+
435
+ /**
436
+ * Safely registers a listener for WebMCP lifecycle events (`toolactivated`, `toolcancel`)
437
+ * with graceful degradation, event payload normalization, and automatic unsubscription.
438
+ *
439
+ * Returns an idempotent unsubscribe cleanup function.
440
+ */
441
+ export function addWebMcpEventListener<
442
+ T extends "toolactivated" | "toolcancel" | string =
443
+ | "toolactivated"
444
+ | "toolcancel",
445
+ >(
446
+ type: T,
447
+ listener: (
448
+ event: T extends "toolactivated"
449
+ ? WebMcpToolActivatedEvent
450
+ : T extends "toolcancel"
451
+ ? WebMcpToolCancelEvent
452
+ : Event & { toolName?: string },
453
+ ) => void,
454
+ options?: boolean | WebMcpEventListenerOptions,
455
+ ): () => void {
456
+ const target = getWebMcpEventTarget(type);
457
+ const opts = typeof options === "object" ? options : undefined;
458
+ const listenBoth = opts?.listenBoth ?? false;
459
+
460
+ const win =
461
+ typeof window !== "undefined" &&
462
+ typeof (window as any).addEventListener === "function"
463
+ ? (window as unknown as WebMcpEventTarget)
464
+ : null;
465
+ const doc = typeof document !== "undefined" ? document : null;
466
+ const nav = typeof navigator !== "undefined" ? navigator : null;
467
+ const modelContext: any =
468
+ (doc as any)?.modelContext ?? (nav as any)?.modelContext;
469
+ const hasMc =
470
+ modelContext && typeof modelContext.addEventListener === "function";
471
+
472
+ const secondaryTarget: WebMcpEventTarget | null = listenBoth
473
+ ? target === modelContext
474
+ ? win !== target
475
+ ? win
476
+ : null
477
+ : hasMc
478
+ ? (modelContext as WebMcpEventTarget)
479
+ : null
480
+ : null;
481
+
482
+ if (!target && !secondaryTarget) {
483
+ return () => {};
484
+ }
485
+
486
+ let recentToolNames: Set<string> | null = null;
487
+ let clearTimer: ReturnType<typeof setTimeout> | null = null;
488
+
489
+ const wrapHandler = (evt: Event) => {
490
+ let toolName = (evt as any).toolName;
491
+ if (
492
+ typeof toolName !== "string" &&
493
+ "detail" in evt &&
494
+ typeof (evt as any).detail === "object"
495
+ ) {
496
+ toolName = (evt as any).detail?.toolName;
497
+ }
498
+ if (typeof toolName !== "string") {
499
+ toolName = "";
500
+ }
501
+
502
+ if (!("toolName" in evt) || (evt as any).toolName !== toolName) {
503
+ try {
504
+ Object.defineProperty(evt, "toolName", {
505
+ value: toolName,
506
+ configurable: true,
507
+ enumerable: true,
508
+ });
509
+ } catch {
510
+ // Ignore errors if event is sealed
511
+ }
512
+ }
513
+
514
+ if (listenBoth && toolName) {
515
+ if (!recentToolNames) {
516
+ recentToolNames = new Set();
517
+ }
518
+ if (recentToolNames.has(toolName)) {
519
+ return;
520
+ }
521
+ recentToolNames.add(toolName);
522
+ if (!clearTimer) {
523
+ clearTimer = setTimeout(() => {
524
+ recentToolNames?.clear();
525
+ clearTimer = null;
526
+ }, 100);
527
+ }
528
+ }
529
+
530
+ listener(evt as any);
531
+ };
532
+
533
+ if (target) {
534
+ target.addEventListener(type, wrapHandler as EventListener, options);
535
+ }
536
+ if (secondaryTarget) {
537
+ secondaryTarget.addEventListener(
538
+ type,
539
+ wrapHandler as EventListener,
540
+ options,
541
+ );
542
+ }
543
+
544
+ let unsubscribed = false;
545
+ const unsubscribe = () => {
546
+ if (unsubscribed) {
547
+ return;
548
+ }
549
+ unsubscribed = true;
550
+ if (clearTimer) {
551
+ clearTimeout(clearTimer);
552
+ clearTimer = null;
553
+ }
554
+ if (target) {
555
+ target.removeEventListener(type, wrapHandler as EventListener, options);
556
+ }
557
+ if (secondaryTarget) {
558
+ secondaryTarget.removeEventListener(
559
+ type,
560
+ wrapHandler as EventListener,
561
+ options,
562
+ );
563
+ }
564
+ };
565
+
566
+ if (opts?.signal) {
567
+ if (opts.signal.aborted) {
568
+ unsubscribe();
569
+ return () => {};
570
+ }
571
+ opts.signal.addEventListener("abort", () => unsubscribe(), { once: true });
572
+ }
573
+
574
+ return unsubscribe;
575
+ }
576
+
577
+ /**
578
+ * Convenience helper to subscribe to tool execution start events (`toolactivated`).
579
+ * Returns an unsubscribe cleanup function.
580
+ */
581
+ export function onWebMcpToolActivated(
582
+ listener: (event: WebMcpToolActivatedEvent) => void,
583
+ options?: boolean | WebMcpEventListenerOptions,
584
+ ): () => void {
585
+ return addWebMcpEventListener("toolactivated", listener, options);
586
+ }
587
+
588
+ /**
589
+ * Convenience helper to subscribe to tool execution cancel events (`toolcancel`).
590
+ * Returns an unsubscribe cleanup function.
591
+ */
592
+ export function onWebMcpToolCancel(
593
+ listener: (event: WebMcpToolCancelEvent) => void,
594
+ options?: boolean | WebMcpEventListenerOptions,
595
+ ): () => void {
596
+ return addWebMcpEventListener("toolcancel", listener, options);
597
+ }
598
+
346
599
  /**
347
600
  * Consequential tools that perform high-stakes, irreversible, or external real-world actions
348
601
  * (such as deleting data, executing arbitrary system commands, or transmitting live communications).
@@ -1 +0,0 @@
1
- import{t as e}from"./chunk-WMPAfIvV2.js";export{e as fetchDiscoveryManifest};
@@ -1 +0,0 @@
1
- import{a as e}from"./chunk-BXFHFbEd.js";export{e as getMemoryOpfsRoot};
@@ -1 +0,0 @@
1
- import{r as e}from"./chunk-DIbSoQmd2.js";export{e as orchestratorStore};
@@ -1 +0,0 @@
1
- import{r as e}from"./chunk-BUhqHeEA2.js";export{e as orchestratorStore};
@@ -1 +0,0 @@
1
- import{t as e}from"./chunk-3gRhOmGo2.js";export{e as importRemoteArtifacts};