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.
- package/.well-known/mcp/server-card.json +1 -1
- package/.well-known/mcp.json +1 -1
- package/README.md +2 -1
- package/dist/cli/build/build.js +1 -1
- package/dist/cli/{chunk-Bfz2NYgD.js → chunk-0IeC97mU.js} +7 -7
- package/dist/cli/chunk-3oLxlxPn.js +1 -0
- package/dist/cli/chunk-63s8NnIS.js +93 -0
- package/dist/cli/{chunk-BXg4-9Rq2.js → chunk-8CrZyP1b2.js} +1 -1
- package/dist/cli/{chunk-BP5Hg6CM.js → chunk-B--ueArB.js} +1 -1
- package/dist/cli/chunk-BATVgkFY.js +17 -0
- package/dist/cli/chunk-BIh7rXlJ2.js +1 -0
- package/dist/cli/{chunk-Drr0VSGA2.js → chunk-BKnTOLLS2.js} +1 -1
- package/dist/cli/{chunk-C5PuRV08.js → chunk-BLMC1Bxv.js} +1 -1
- package/dist/cli/{chunk-B2tNSlFy2.js → chunk-BOigzz2U2.js} +1 -1
- package/dist/cli/{chunk-DOf3DZdR.js → chunk-BOzn335y.js} +1 -1
- package/dist/cli/chunk-BjOeVLb42.js +1 -0
- package/dist/cli/{chunk-DqTx0rRp2.js → chunk-Bjqh5_SU2.js} +1 -1
- package/dist/cli/chunk-BqWBd_jF2.js +1 -0
- package/dist/cli/{chunk-DIbSoQmd2.js → chunk-C6FFByBU2.js} +2 -2
- package/dist/cli/{chunk-Drq18VZe.js → chunk-C9-aL3rF.js} +1 -1
- package/dist/cli/{chunk-BUhqHeEA2.js → chunk-C9czddEh2.js} +2 -2
- package/dist/cli/chunk-CCx8WOwz2.js +1 -0
- package/dist/cli/{chunk-BkMSjVJb.js → chunk-CK6ejMig.js} +1 -1
- package/dist/cli/chunk-CUUERioR2.js +1 -0
- package/dist/cli/chunk-CXAobnJd.js +1 -0
- package/dist/cli/chunk-CY1X0pOF2.js +1 -0
- package/dist/cli/chunk-CZvvgLVv.js +1 -0
- package/dist/cli/chunk-CbcwbfJB.js +1 -0
- package/dist/cli/{chunk-quilB3TV2.js → chunk-Ci9OJGcd2.js} +1 -1
- package/dist/cli/chunk-Cj9wl0qx.js +1 -0
- package/dist/cli/{chunk-3gRhOmGo2.js → chunk-CjJsVrKI2.js} +1 -1
- package/dist/cli/{chunk-CmEfzm-_.js → chunk-ClPZ4Rea.js} +1 -1
- package/dist/cli/chunk-Cmdxoq9q.js +13 -0
- package/dist/cli/{chunk-WMPAfIvV2.js → chunk-DHJCGRuG2.js} +1 -1
- package/dist/cli/{chunk-C7Y2xIk4.js → chunk-DKVkYTV9.js} +1 -1
- package/dist/cli/chunk-DR2XtWRo.js +1 -0
- package/dist/cli/{chunk-BiVJVh_S.js → chunk-DUlIqkaX.js} +7 -7
- package/dist/cli/{chunk-CkpueGaZ2.js → chunk-DjWle8FF2.js} +1 -1
- package/dist/cli/{chunk-CSvHmNOk.js → chunk-DmRXVLfy.js} +1 -1
- package/dist/cli/{chunk-BT1xXZn72.js → chunk-HlSiTC-u2.js} +1 -1
- package/dist/cli/{chunk-da0bsiOn.js → chunk-P4JSeFBI.js} +1 -1
- package/dist/cli/chunk-UcNbHaRQ.js +1 -0
- package/dist/cli/{chunk-BXFHFbEd.js → chunk-UweLmfQS.js} +1 -1
- package/dist/cli/{chunk-CGiXWHTi2.js → chunk-gwpxl-0W2.js} +1 -1
- package/dist/cli/{chunk-NH8koEis2.js → chunk-nmDhxXH_2.js} +1 -1
- package/dist/cli/chunk-p0n_c-I2.js +1 -0
- package/dist/cli/{chunk-D7xP72La.js → chunk-q7r4FosZ.js} +1 -1
- package/dist/cli/cli.js +1 -1
- package/dist/cli/prerender/dsd-shell/prerender-dsd-shell.js +1 -1
- package/dist/electron/main.cjs +1 -1
- package/dist/headless-agent.js +1 -1
- package/dist/lib/{app-routes-BAEMLu9g.js → app-routes-CKkiX12g.js} +7 -2
- package/dist/lib/app-routes-CKkiX12g.js.map +1 -0
- package/dist/lib/components/index.js +26 -26
- package/dist/lib/components/settings/shadow-claw-accounts.js +1 -1
- package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/settings/shadow-claw-git.js +1 -1
- package/dist/lib/components/settings/shadow-claw-integrations.js +1 -1
- package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
- package/dist/lib/components/settings/shadow-claw-mcp-remote.js +1 -1
- package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
- package/dist/lib/components/settings/shadow-claw-notifications.js +1 -1
- package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
- package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw/utils/syncSlottedSidebarActiveLinks.d.ts +10 -0
- package/dist/lib/components/shadow-claw-a2ui.js +1 -1
- package/dist/lib/components/shadow-claw-accounts.js +1 -1
- package/dist/lib/components/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/shadow-claw-channels.js +1 -1
- package/dist/lib/components/shadow-claw-chat.js +1 -1
- package/dist/lib/components/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/shadow-claw-conversations.js +1 -1
- package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
- package/dist/lib/components/shadow-claw-files.js +1 -1
- package/dist/lib/components/shadow-claw-git.js +1 -1
- package/dist/lib/components/shadow-claw-integrations.js +1 -1
- package/dist/lib/components/shadow-claw-llm.js +1 -1
- package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
- package/dist/lib/components/shadow-claw-networking.js +1 -1
- package/dist/lib/components/shadow-claw-notifications.js +1 -1
- package/dist/lib/components/shadow-claw-page-header.js +1 -1
- package/dist/lib/components/shadow-claw-pages.js +1 -1
- package/dist/lib/components/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/shadow-claw-settings.js +1 -1
- package/dist/lib/components/shadow-claw-storage.js +1 -1
- package/dist/lib/components/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/shadow-claw-tasks.js +1 -1
- package/dist/lib/components/shadow-claw-terminal.js +1 -1
- package/dist/lib/components/shadow-claw-tools.js +1 -1
- package/dist/lib/components/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw.js +1 -1
- package/dist/lib/{config-CPHDmyTx.js → config-DZkF9LiO.js} +2 -2
- package/dist/lib/{config-CPHDmyTx.js.map → config-DZkF9LiO.js.map} +1 -1
- package/dist/lib/{configurePeerJs-BsJoycQd.js → configurePeerJs-B3IE9BY2.js} +3 -3
- package/dist/lib/{configurePeerJs-BsJoycQd.js.map → configurePeerJs-B3IE9BY2.js.map} +1 -1
- package/dist/lib/{connections-BdIru7bF.js → connections-CalJGWvZ.js} +2 -2
- package/dist/lib/{connections-BdIru7bF.js.map → connections-CalJGWvZ.js.map} +1 -1
- package/dist/lib/{downloadGroupFile-Dn0KsMlV.js → downloadGroupFile-DDE1fIhJ.js} +2 -2
- package/dist/lib/{downloadGroupFile-Dn0KsMlV.js.map → downloadGroupFile-DDE1fIhJ.js.map} +1 -1
- package/dist/lib/{file-viewer-BYrXXu-X.js → file-viewer-Bll2EoGc.js} +5 -5
- package/dist/lib/{file-viewer-BYrXXu-X.js.map → file-viewer-Bll2EoGc.js.map} +1 -1
- package/dist/lib/{getGroupDir-DF-RZO8X.js → getGroupDir-MHv7Lvmp.js} +4 -4
- package/dist/lib/{getGroupDir-DF-RZO8X.js.map → getGroupDir-MHv7Lvmp.js.map} +1 -1
- package/dist/lib/{git-s_0cgKm1.js → git-Bv_M3dgw.js} +3 -3
- package/dist/lib/{git-s_0cgKm1.js.map → git-Bv_M3dgw.js.map} +1 -1
- package/dist/lib/{iframe-sanitizer-DFdda1jJ.js → iframe-sanitizer-C7ZGDjEI.js} +2 -2
- package/dist/lib/{iframe-sanitizer-DFdda1jJ.js.map → iframe-sanitizer-C7ZGDjEI.js.map} +1 -1
- package/dist/lib/{iframe-storage-proxy-qrhZmQyO.js → iframe-storage-proxy-CR8ZYHPd.js} +2 -2
- package/dist/lib/{iframe-storage-proxy-qrhZmQyO.js.map → iframe-storage-proxy-CR8ZYHPd.js.map} +1 -1
- package/dist/lib/index.js +27 -27
- package/dist/lib/{initChatSplitResize-DuNlwCuI.js → initChatSplitResize-DiKTI-wk.js} +2 -2
- package/dist/lib/{initChatSplitResize-DuNlwCuI.js.map → initChatSplitResize-DiKTI-wk.js.map} +1 -1
- package/dist/lib/{initControlPlane-D4UZ4EhV.js → initControlPlane-CzjtQ4aM.js} +15 -15
- package/dist/lib/{initControlPlane-D4UZ4EhV.js.map → initControlPlane-CzjtQ4aM.js.map} +1 -1
- package/dist/lib/{markdown-CRRwbN9h.js → markdown-k8wA9LKy.js} +4 -4
- package/dist/lib/{markdown-CRRwbN9h.js.map → markdown-k8wA9LKy.js.map} +1 -1
- package/dist/lib/{mcp-reconnect-COdZ-cea.js → mcp-reconnect-CGIdfZnS.js} +2 -2
- package/dist/lib/{mcp-reconnect-COdZ-cea.js.map → mcp-reconnect-CGIdfZnS.js.map} +1 -1
- package/dist/lib/{memoryStorage-BsMe2FOQ.js → memoryStorage-DL-Bo3dh.js} +2 -2
- package/dist/lib/{memoryStorage-BsMe2FOQ.js.map → memoryStorage-DL-Bo3dh.js.map} +1 -1
- package/dist/lib/{orchestrator-D9f5fDCb.js → orchestrator-DKHCoikY.js} +11 -11
- package/dist/lib/{orchestrator-D9f5fDCb.js.map → orchestrator-DKHCoikY.js.map} +1 -1
- package/dist/lib/{orchestrator-CMN43L0F.js → orchestrator-Dn1ZOz9B.js} +12 -12
- package/dist/lib/{orchestrator-CMN43L0F.js.map → orchestrator-Dn1ZOz9B.js.map} +1 -1
- package/dist/lib/{peerjs-6u8KtenE.js → peerjs-BK41iBvP.js} +7 -7
- package/dist/lib/{peerjs-6u8KtenE.js.map → peerjs-BK41iBvP.js.map} +1 -1
- package/dist/lib/{push-client-DCnB2-OU.js → push-client-DKgVFD2Z.js} +3 -3
- package/dist/lib/{push-client-DCnB2-OU.js.map → push-client-DKgVFD2Z.js.map} +1 -1
- package/dist/lib/{readGroupFileBytes-nKNJ6sbl.js → readGroupFileBytes-CgU_UfGv.js} +2 -2
- package/dist/lib/{readGroupFileBytes-nKNJ6sbl.js.map → readGroupFileBytes-CgU_UfGv.js.map} +1 -1
- package/dist/lib/{shadow-claw-4x3LqlII.js → shadow-claw-CtCj5Rn_.js} +121 -16
- package/dist/lib/shadow-claw-CtCj5Rn_.js.map +1 -0
- package/dist/lib/{shadow-claw-a2ui-Dipe8nY2.js → shadow-claw-a2ui-CvK5w940.js} +2 -2
- package/dist/lib/{shadow-claw-a2ui-Dipe8nY2.js.map → shadow-claw-a2ui-CvK5w940.js.map} +1 -1
- package/dist/lib/{shadow-claw-accounts-BgCkz3Zv.js → shadow-claw-accounts-Br3XdHro.js} +3 -3
- package/dist/lib/{shadow-claw-accounts-BgCkz3Zv.js.map → shadow-claw-accounts-Br3XdHro.js.map} +1 -1
- package/dist/lib/{shadow-claw-channel-config-CIm_Bxd2.js → shadow-claw-channel-config-Da2dN19M.js} +3 -3
- package/dist/lib/{shadow-claw-channel-config-CIm_Bxd2.js.map → shadow-claw-channel-config-Da2dN19M.js.map} +1 -1
- package/dist/lib/{shadow-claw-channels-CaceK52s.js → shadow-claw-channels-BofYHgz8.js} +3 -3
- package/dist/lib/{shadow-claw-channels-CaceK52s.js.map → shadow-claw-channels-BofYHgz8.js.map} +1 -1
- package/dist/lib/{shadow-claw-chat-BD18-mAR.js → shadow-claw-chat-Dw32DPV2.js} +12 -12
- package/dist/lib/{shadow-claw-chat-BD18-mAR.js.map → shadow-claw-chat-Dw32DPV2.js.map} +1 -1
- package/dist/lib/{shadow-claw-control-plane-U6LsfRPm.js → shadow-claw-control-plane-CwFotFDh.js} +7 -7
- package/dist/lib/{shadow-claw-control-plane-U6LsfRPm.js.map → shadow-claw-control-plane-CwFotFDh.js.map} +1 -1
- package/dist/lib/{shadow-claw-conversations-CDsza_oB.js → shadow-claw-conversations-0UXge23k.js} +5 -5
- package/dist/lib/{shadow-claw-conversations-CDsza_oB.js.map → shadow-claw-conversations-0UXge23k.js.map} +1 -1
- package/dist/lib/{shadow-claw-file-viewer-CuDhkVcL.js → shadow-claw-file-viewer-CAsn9NxH.js} +10 -10
- package/dist/lib/{shadow-claw-file-viewer-CuDhkVcL.js.map → shadow-claw-file-viewer-CAsn9NxH.js.map} +1 -1
- package/dist/lib/{shadow-claw-files-BI0P3m8a.js → shadow-claw-files-xGGhsHNH.js} +9 -9
- package/dist/lib/{shadow-claw-files-BI0P3m8a.js.map → shadow-claw-files-xGGhsHNH.js.map} +1 -1
- package/dist/lib/{shadow-claw-git-xRApLEMN.js → shadow-claw-git-B606hcMU.js} +6 -6
- package/dist/lib/{shadow-claw-git-xRApLEMN.js.map → shadow-claw-git-B606hcMU.js.map} +1 -1
- package/dist/lib/{shadow-claw-integrations-B2e1Nfg1.js → shadow-claw-integrations-Bwq5cba1.js} +4 -4
- package/dist/lib/{shadow-claw-integrations-B2e1Nfg1.js.map → shadow-claw-integrations-Bwq5cba1.js.map} +1 -1
- package/dist/lib/{shadow-claw-llm-Bc2mWuGb.js → shadow-claw-llm-BgpcMBIy.js} +6 -6
- package/dist/lib/{shadow-claw-llm-Bc2mWuGb.js.map → shadow-claw-llm-BgpcMBIy.js.map} +1 -1
- package/dist/lib/{shadow-claw-mcp-remote-D_Bh3aeC.js → shadow-claw-mcp-remote-DvQCA-Bk.js} +4 -4
- package/dist/lib/{shadow-claw-mcp-remote-D_Bh3aeC.js.map → shadow-claw-mcp-remote-DvQCA-Bk.js.map} +1 -1
- package/dist/lib/{shadow-claw-networking-F5W3n5ci.js → shadow-claw-networking-Cxvf9c7E.js} +2 -2
- package/dist/lib/{shadow-claw-networking-F5W3n5ci.js.map → shadow-claw-networking-Cxvf9c7E.js.map} +1 -1
- package/dist/lib/{shadow-claw-notifications-lvMt9WJ1.js → shadow-claw-notifications-CGVcFYBy.js} +3 -3
- package/dist/lib/{shadow-claw-notifications-lvMt9WJ1.js.map → shadow-claw-notifications-CGVcFYBy.js.map} +1 -1
- package/dist/lib/{shadow-claw-page-header-6gq6EMqX.js → shadow-claw-page-header-DAYz3I_o.js} +2 -2
- package/dist/lib/{shadow-claw-page-header-6gq6EMqX.js.map → shadow-claw-page-header-DAYz3I_o.js.map} +1 -1
- package/dist/lib/{shadow-claw-pages-Bo8_z2S-.js → shadow-claw-pages-BLeEZb9k.js} +24 -12
- package/dist/lib/shadow-claw-pages-BLeEZb9k.js.map +1 -0
- package/dist/lib/{shadow-claw-peerjs-DRTLCVDQ.js → shadow-claw-peerjs-BcFnbK74.js} +3 -3
- package/dist/lib/{shadow-claw-peerjs-DRTLCVDQ.js.map → shadow-claw-peerjs-BcFnbK74.js.map} +1 -1
- package/dist/lib/{shadow-claw-settings-D00B4p4L.js → shadow-claw-settings-B7o0Z4hu.js} +9 -9
- package/dist/lib/{shadow-claw-settings-D00B4p4L.js.map → shadow-claw-settings-B7o0Z4hu.js.map} +1 -1
- package/dist/lib/{shadow-claw-storage-DgMe7-Zo.js → shadow-claw-storage-afMVqB7E.js} +5 -5
- package/dist/lib/{shadow-claw-storage-DgMe7-Zo.js.map → shadow-claw-storage-afMVqB7E.js.map} +1 -1
- package/dist/lib/{shadow-claw-task-server-D103YOuI.js → shadow-claw-task-server-B9-MQjl6.js} +2 -2
- package/dist/lib/{shadow-claw-task-server-D103YOuI.js.map → shadow-claw-task-server-B9-MQjl6.js.map} +1 -1
- package/dist/lib/{shadow-claw-tasks-6OhALkq1.js → shadow-claw-tasks-Dc4BC-t-.js} +8 -8
- package/dist/lib/{shadow-claw-tasks-6OhALkq1.js.map → shadow-claw-tasks-Dc4BC-t-.js.map} +1 -1
- package/dist/lib/{shadow-claw-terminal-BGtxA1qD.js → shadow-claw-terminal-BINcTdsk.js} +2 -2
- package/dist/lib/{shadow-claw-terminal-BGtxA1qD.js.map → shadow-claw-terminal-BINcTdsk.js.map} +1 -1
- package/dist/lib/{shadow-claw-tools-OeIwAnnd.js → shadow-claw-tools-BjFgXNLR.js} +7 -7
- package/dist/lib/{shadow-claw-tools-OeIwAnnd.js.map → shadow-claw-tools-BjFgXNLR.js.map} +1 -1
- package/dist/lib/{shadow-claw-webvm-gVFZ197u.js → shadow-claw-webvm-Xe3ByMDw.js} +3 -3
- package/dist/lib/{shadow-claw-webvm-gVFZ197u.js.map → shadow-claw-webvm-Xe3ByMDw.js.map} +1 -1
- package/dist/lib/subsystems/mcp/webmcp.d.ts +64 -0
- package/dist/lib/{syncWebMcpRegistration-Bbph0XZl.js → syncWebMcpRegistration-D7alChz0.js} +21 -6
- package/dist/lib/syncWebMcpRegistration-D7alChz0.js.map +1 -0
- package/dist/lib/{tools-D0OlSzMD.js → tools-Cmhpk3X8.js} +4 -4
- package/dist/lib/{tools-D0OlSzMD.js.map → tools-Cmhpk3X8.js.map} +1 -1
- package/dist/lib/utils/index.js +1 -1
- package/dist/lib/utils/namespacedStorage.js +1 -1
- package/dist/lib/utils/utils.js +1 -1
- package/dist/lib/{utils-DYdrO2KI.js → utils-CzgKe_XZ.js} +4 -4
- package/dist/lib/{utils-DYdrO2KI.js.map → utils-CzgKe_XZ.js.map} +1 -1
- package/dist/lib/{webmcp-D2bocsgh.js → webmcp-oEP9YpR2.js} +119 -3
- package/dist/lib/{webmcp-D2bocsgh.js.map → webmcp-oEP9YpR2.js.map} +1 -1
- package/dist/public/.well-known/mcp/server-card.json +1 -1
- package/dist/public/.well-known/mcp.json +1 -1
- package/dist/public/AGENTS.md +8 -2
- package/dist/public/README.md +2 -1
- package/dist/public/agent.worker.js +1 -1
- package/dist/public/app-routes-C6-H2zPH.js +1 -0
- package/dist/public/components/shadow-claw/shadow-claw.css +1 -1
- package/dist/public/components/shadow-claw/shadow-claw.html +1 -1
- package/dist/public/components/shadow-claw-pages/shadow-claw-pages.css +1 -1
- package/dist/public/{config-D4lVqMs8.js → config-Dewnqegf.js} +1 -1
- package/dist/public/{configurePeerJs-DDOAVSaH.js → configurePeerJs-CaPU2sN5.js} +1 -1
- package/dist/public/{connections-CiukjGiH.js → connections-CwE7jE9l.js} +1 -1
- package/dist/public/{custom-element-security-piU2U-Ec.js → custom-element-security-DLgHMf5R.js} +1 -1
- package/dist/public/docs/README.md +1 -0
- package/dist/public/docs/example/article/index.html +4 -4
- package/dist/public/docs/guides/publishing-to-github-pages.md +95 -6
- package/dist/public/docs/publishing/index.html +4 -4
- package/dist/public/docs/skill-creator/index.html +4 -4
- package/dist/public/docs/subsystems/pages.md +10 -3
- package/dist/public/docs/subsystems/theming.md +242 -0
- package/dist/public/docs/subsystems/webmcp.md +89 -1
- package/dist/public/{downloadGroupFile-BiZQYY-O.js → downloadGroupFile-ChWHuap_.js} +1 -1
- package/dist/public/e2e/README.md +3 -2
- package/dist/public/{e2e-bridge-CybB810Q.js → e2e-bridge-BkaldjV2.js} +1 -1
- package/dist/public/{file-viewer-DLUBvOVD.js → file-viewer-Df4qUJCn.js} +1 -1
- package/dist/public/{getGroupDir-CLz5c8cg.js → getGroupDir-CeSr4fzS.js} +1 -1
- package/dist/public/{git-Ba8AeviI.js → git-Bscc1tK-.js} +2 -2
- package/dist/public/{iframe-sanitizer-CKOO7cxp.js → iframe-sanitizer-BVdkQsor.js} +1 -1
- package/dist/public/{iframe-storage-proxy-BvRiccH0.js → iframe-storage-proxy-Cg8aFw7o.js} +1 -1
- package/dist/public/index.css +1 -1
- package/dist/public/index.html +4 -4
- package/dist/public/index.js +1 -1
- package/dist/public/{initChatSplitResize-osJXM2gu.js → initChatSplitResize-C3Rp1LeZ.js} +1 -1
- package/dist/public/{initControlPlane-CNggzsRw.js → initControlPlane-C1pnzG16.js} +1 -1
- package/dist/public/llms.txt +2 -2
- package/dist/public/main/index.html +4 -4
- package/dist/public/main/memory/index.html +4 -4
- package/dist/public/{markdown-CZA-Ye2Q.js → markdown-D3A902nT.js} +1 -1
- package/dist/public/{mcp-reconnect-BK1bYBdC.js → mcp-reconnect-BJWxQBm_.js} +1 -1
- package/dist/public/{memoryStorage-Bew1X8Uy.js → memoryStorage-ykv-Ri-y.js} +1 -1
- package/dist/public/{orchestrator-D6tel2Zp.js → orchestrator-BVnC4Vtt.js} +2 -2
- package/dist/public/{orchestrator-Dc_Q73La.js → orchestrator-CQcc7OFA.js} +2 -2
- package/dist/public/{peerjs-CYs1F7sq.js → peerjs-CYC2cI1Y.js} +1 -1
- package/dist/public/{push-client-_HUyJlFJ.js → push-client-BJrnOULM.js} +1 -1
- package/dist/public/service-worker/fetch-proxy.js +1 -1
- package/dist/public/service-worker.js +1 -1
- package/dist/public/{shadow-claw-Dabb2AEp.js → shadow-claw-WwfOu-tu.js} +33 -3
- package/dist/public/{shadow-claw-accounts-BqGrm47Z.js → shadow-claw-accounts-BFZxrPsH.js} +1 -1
- package/dist/public/{shadow-claw-channels-Ci2UPaaA.js → shadow-claw-channels-C0w0c1EF.js} +1 -1
- package/dist/public/{shadow-claw-chat-BxR6cBYQ.js → shadow-claw-chat-DIJ0A-QN.js} +1 -1
- package/dist/public/{shadow-claw-control-plane-C1A-CZ9H.js → shadow-claw-control-plane-DZoxUd-1.js} +2 -2
- package/dist/public/{shadow-claw-conversations-DcwG05-H.js → shadow-claw-conversations-DMyG_5zj.js} +1 -1
- package/dist/public/{shadow-claw-file-viewer-CDs1QGXk.js → shadow-claw-file-viewer-DYgZjZb9.js} +1 -1
- package/dist/public/{shadow-claw-files-B774Xz1d.js → shadow-claw-files-DIOUdKJr.js} +1 -1
- package/dist/public/{shadow-claw-git-CTIPP0vs.js → shadow-claw-git-if5S0QJr.js} +2 -2
- package/dist/public/{shadow-claw-integrations-CjtkA6l0.js → shadow-claw-integrations-BQt4hcWe.js} +1 -1
- package/dist/public/{shadow-claw-llm-DfmITHde.js → shadow-claw-llm-9uf1KFA0.js} +2 -2
- package/dist/public/{shadow-claw-mcp-remote-BPuV22So.js → shadow-claw-mcp-remote-COpNIzJd.js} +1 -1
- package/dist/public/{shadow-claw-networking-DEMMygy0.js → shadow-claw-networking-AOVRUn6B.js} +1 -1
- package/dist/public/{shadow-claw-notifications-B9Xhcj1P.js → shadow-claw-notifications-CKB-W1TA.js} +1 -1
- package/dist/public/{shadow-claw-page-header-CAXokjQy.js → shadow-claw-page-header-D4LmUigA.js} +1 -1
- package/dist/public/{shadow-claw-pages-BRQw8bTm.js → shadow-claw-pages-BpHRY4vH.js} +12 -3
- package/dist/public/{shadow-claw-settings-BGrDNyqh.js → shadow-claw-settings-CE-aUo_J.js} +3 -3
- package/dist/public/{shadow-claw-storage-DK3pf11w.js → shadow-claw-storage-CFKC-Y3V.js} +1 -1
- package/dist/public/{shadow-claw-task-server-CMp5Vjza.js → shadow-claw-task-server-B_ZjqK4B.js} +1 -1
- package/dist/public/{shadow-claw-tasks-BO8aXM2B.js → shadow-claw-tasks-CGsEv48K.js} +1 -1
- package/dist/public/{shadow-claw-terminal-BSeTuyDa.js → shadow-claw-terminal-DcaS7cPH.js} +1 -1
- package/dist/public/{shadow-claw-tools-Bj6DLZ-2.js → shadow-claw-tools-Cnu9hKy0.js} +1 -1
- package/dist/public/{shadow-claw-webvm-M7d5RH8H.js → shadow-claw-webvm-BB8SFvJ8.js} +1 -1
- package/dist/public/syncWebMcpRegistration-D2Zx4oA1.js +1 -0
- package/dist/public/theme-init.js +1 -1
- package/dist/public/{tools-nysPKnGT.js → tools-sOLCHTj8.js} +1 -1
- package/dist/public/{webmcp-Bo3KTgRb.js → webmcp-YFt6vM1_.js} +1 -1
- package/dist/server.js +188 -188
- package/package.json +1 -1
- package/src/cli/build/build.ts +18 -11
- package/src/cli/prerender/dsd-shell/prerender-dsd-shell.test.ts +4 -1
- package/src/cli/prerender/dsd-shell/prerender-dsd-shell.ts +13 -1
- package/src/cli/prerender/pretty-paths/prerender-pretty-paths.ts +22 -0
- package/src/cli/prerender/utils/insert-before-closing-head.test.ts +34 -1
- package/src/cli/prerender/utils/insert-before-closing-head.ts +20 -6
- package/src/cli/site-config/apply.test.ts +90 -0
- package/src/cli/site-config/apply.ts +189 -22
- package/src/components/shadow-claw/shadow-claw.css +26 -0
- package/src/components/shadow-claw/shadow-claw.html +4 -0
- package/src/components/shadow-claw/utils/applyRoute.ts +3 -0
- package/src/components/shadow-claw/utils/bindEventListeners.test.ts +6 -0
- package/src/components/shadow-claw/utils/bindEventListeners.ts +30 -1
- package/src/components/shadow-claw/utils/getRoute.test.ts +52 -0
- package/src/components/shadow-claw/utils/getRoute.ts +18 -0
- package/src/components/shadow-claw/utils/navigateToRoute.test.ts +21 -0
- package/src/components/shadow-claw/utils/navigateToRoute.ts +10 -0
- package/src/components/shadow-claw/utils/sidebarVisibility.ts +12 -4
- package/src/components/shadow-claw/utils/syncSlottedSidebarActiveLinks.test.ts +93 -0
- package/src/components/shadow-claw/utils/syncSlottedSidebarActiveLinks.ts +100 -0
- package/src/components/shadow-claw-pages/shadow-claw-pages.css +10 -1
- package/src/components/shadow-claw-pages/utils/removePreviewIframe.ts +3 -0
- package/src/core/orchestrator/utils/syncWebMcpRegistration.test.ts +52 -0
- package/src/core/orchestrator/utils/syncWebMcpRegistration.ts +28 -1
- package/src/server/middleware/static-files.test.ts +36 -0
- package/src/server/middleware/static-files.ts +14 -6
- package/src/storage/staticRouting.test.ts +36 -0
- package/src/storage/staticRouting.ts +31 -3
- package/src/subsystems/mcp/webmcp.test.ts +255 -0
- package/src/subsystems/mcp/webmcp.ts +253 -0
- package/dist/cli/chunk-00GAzVPl2.js +0 -1
- package/dist/cli/chunk-2hnFoNNC.js +0 -1
- package/dist/cli/chunk-BKQL4nzF2.js +0 -1
- package/dist/cli/chunk-BQ4K3fqj2.js +0 -1
- package/dist/cli/chunk-BVCGo6uf2.js +0 -1
- package/dist/cli/chunk-Bc9nRNyN.js +0 -11
- package/dist/cli/chunk-BcTH_-FL.js +0 -1
- package/dist/cli/chunk-BmD_sPRt.js +0 -1
- package/dist/cli/chunk-BsxNqqer.js +0 -1
- package/dist/cli/chunk-CCcF5T-c.js +0 -1
- package/dist/cli/chunk-CFhvwUeL.js +0 -91
- package/dist/cli/chunk-CwWtvULn.js +0 -1
- package/dist/cli/chunk-DID5VvOG.js +0 -17
- package/dist/cli/chunk-Drf-hXIR2.js +0 -1
- package/dist/cli/chunk-Dt5HNYVi.js +0 -1
- package/dist/cli/chunk-DwZQi9Ax.js +0 -1
- package/dist/cli/chunk-m9ZX7TyF2.js +0 -1
- package/dist/lib/app-routes-BAEMLu9g.js.map +0 -1
- package/dist/lib/shadow-claw-4x3LqlII.js.map +0 -1
- package/dist/lib/shadow-claw-pages-Bo8_z2S-.js.map +0 -1
- package/dist/lib/syncWebMcpRegistration-Bbph0XZl.js.map +0 -1
- package/dist/public/app-routes-BMQ4HFaM.js +0 -1
- 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};
|