shadow-claw 1.40.1 → 1.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.well-known/mcp/server-card.json +1 -1
- package/.well-known/mcp.json +1 -1
- package/README.md +1 -0
- 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-BXg4-9Rq2.js → chunk-8CrZyP1b2.js} +1 -1
- package/dist/cli/{chunk-BP5Hg6CM.js → chunk-B--ueArB.js} +1 -1
- 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-Bc9nRNyN.js → chunk-BvVUnHTq.js} +12 -9
- 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-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-DID5VvOG.js → chunk-DTES-dE6.js} +3 -3
- 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-bQQkVCw-.js +94 -0
- 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 +2 -1
- package/dist/public/README.md +1 -0
- 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/example/article/index.html +4 -4
- package/dist/public/docs/guides/publishing-to-github-pages.md +49 -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/webmcp.md +89 -1
- package/dist/public/{downloadGroupFile-BiZQYY-O.js → downloadGroupFile-ChWHuap_.js} +1 -1
- package/dist/public/e2e/README.md +2 -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 +1 -1
- 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/prerender/dsd-shell/prerender-dsd-shell.test.ts +4 -1
- package/src/cli/prerender/dsd-shell/prerender-dsd-shell.ts +7 -1
- package/src/cli/prerender/utils/insert-before-closing-head.test.ts +12 -0
- package/src/cli/prerender/utils/insert-before-closing-head.ts +4 -6
- package/src/cli/site-config/apply.test.ts +90 -0
- package/src/cli/site-config/apply.ts +181 -13
- 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-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-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
package/package.json
CHANGED
|
@@ -502,11 +502,14 @@ describe("prerenderDsdShell purge flag pages", () => {
|
|
|
502
502
|
|
|
503
503
|
it("applies sidebar visibility config to template", () => {
|
|
504
504
|
const tpl =
|
|
505
|
-
'<li class="nav-item" data-page="chat">Chat</li><li class="nav-item" data-page="files">Files</li>';
|
|
505
|
+
'<li class="nav-item" data-page="chat">Chat</li><li class="nav-item" data-page="files">Files</li><shadow-claw-conversations></shadow-claw-conversations>';
|
|
506
506
|
const modified = applySidebarVisibilityToTemplate(tpl, {
|
|
507
507
|
chatHidden: true,
|
|
508
508
|
});
|
|
509
509
|
expect(modified).toContain('data-page="chat" hidden aria-hidden="true"');
|
|
510
|
+
expect(modified).toContain(
|
|
511
|
+
'<shadow-claw-conversations hidden aria-hidden="true">',
|
|
512
|
+
);
|
|
510
513
|
expect(modified).not.toContain('data-page="files" hidden');
|
|
511
514
|
});
|
|
512
515
|
|
|
@@ -675,7 +675,13 @@ export function applySidebarVisibilityToTemplate(
|
|
|
675
675
|
};
|
|
676
676
|
|
|
677
677
|
if (sidebarConfig.pagesHidden) hidePage("pages");
|
|
678
|
-
if (sidebarConfig.chatHidden)
|
|
678
|
+
if (sidebarConfig.chatHidden) {
|
|
679
|
+
hidePage("chat");
|
|
680
|
+
next = next.replace(
|
|
681
|
+
/(<shadow-claw-conversations)(?![^>]*\bhidden\b)([^>]*>)/iu,
|
|
682
|
+
'$1 hidden aria-hidden="true"$2',
|
|
683
|
+
);
|
|
684
|
+
}
|
|
679
685
|
if (sidebarConfig.tasksHidden) hidePage("tasks");
|
|
680
686
|
if (sidebarConfig.filesHidden) hidePage("files");
|
|
681
687
|
|
|
@@ -16,4 +16,16 @@ describe("insertBeforeClosingHead", () => {
|
|
|
16
16
|
const result = insertBeforeClosingHead(html, tag);
|
|
17
17
|
expect(result.startsWith(`${tag}\n`)).toBe(true);
|
|
18
18
|
});
|
|
19
|
+
|
|
20
|
+
it("targets the first outer </head> tag when nested templates have their own head", () => {
|
|
21
|
+
const html =
|
|
22
|
+
'<!doctype html><html><head><title>Outer</title></head><body><template shadowrootmode="open"><head><title>Inner</title></head></template></body></html>';
|
|
23
|
+
const tag = '<script id="outer-test">true</script>';
|
|
24
|
+
const result = insertBeforeClosingHead(html, tag);
|
|
25
|
+
const outerIndex = result.indexOf(tag);
|
|
26
|
+
const firstHeadClose = result.indexOf("</head>");
|
|
27
|
+
const secondHeadClose = result.lastIndexOf("</head>");
|
|
28
|
+
expect(outerIndex).toBeLessThan(firstHeadClose);
|
|
29
|
+
expect(firstHeadClose).toBeLessThan(secondHeadClose);
|
|
30
|
+
});
|
|
19
31
|
});
|
|
@@ -2,13 +2,11 @@ export function insertBeforeClosingHead(
|
|
|
2
2
|
html: string,
|
|
3
3
|
contentToInsert: string,
|
|
4
4
|
): string {
|
|
5
|
-
const
|
|
6
|
-
if (
|
|
5
|
+
const headMatch = /<\/head>/i.exec(html);
|
|
6
|
+
if (headMatch) {
|
|
7
|
+
const headIndex = headMatch.index;
|
|
7
8
|
return (
|
|
8
|
-
html.slice(0,
|
|
9
|
-
contentToInsert +
|
|
10
|
-
"\n" +
|
|
11
|
-
html.slice(lastHeadIndex)
|
|
9
|
+
html.slice(0, headIndex) + contentToInsert + "\n" + html.slice(headIndex)
|
|
12
10
|
);
|
|
13
11
|
}
|
|
14
12
|
return `${contentToInsert}\n${html}`;
|
|
@@ -202,6 +202,60 @@ describe("apply-site-config", () => {
|
|
|
202
202
|
'<link href="favicon.svg" rel="apple-touch-icon" />',
|
|
203
203
|
);
|
|
204
204
|
});
|
|
205
|
+
|
|
206
|
+
it("injects slotted sidebar html into shadow-claw light DOM when slotHtml is configured", () => {
|
|
207
|
+
const config = {
|
|
208
|
+
sidebar: {
|
|
209
|
+
slotHtml: '<nav class="custom-nav"><a href="/about">About</a></nav>',
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const patched = patchIndexHtml(baseHtml, config);
|
|
214
|
+
expect(patched).toContain('slot="sidebar"');
|
|
215
|
+
expect(patched).toContain('<a href="/about">About</a>');
|
|
216
|
+
expect(patched).toContain("<shadow-claw>");
|
|
217
|
+
expect(patched).toContain("</shadow-claw>");
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("renders and injects declarative sidebar sections into shadow-claw light DOM", () => {
|
|
221
|
+
const config = {
|
|
222
|
+
sidebar: {
|
|
223
|
+
sections: [
|
|
224
|
+
{
|
|
225
|
+
title: "Home",
|
|
226
|
+
headerHref: "/",
|
|
227
|
+
items: [{ title: "About", href: "/about" }],
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
title: "Links",
|
|
231
|
+
items: [
|
|
232
|
+
{
|
|
233
|
+
title: "GitHub",
|
|
234
|
+
href: "https://github.com/xt-ml/shadow-claw",
|
|
235
|
+
target: "_blank",
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const patched = patchIndexHtml(baseHtml, config);
|
|
244
|
+
expect(patched).toContain('slot="sidebar"');
|
|
245
|
+
expect(patched).toContain('class="sidebar-custom-sections"');
|
|
246
|
+
expect(patched).toContain('href="/" class="sidebar-link">Home</a>');
|
|
247
|
+
expect(patched).toContain('href="/about" class="sidebar-link">About</a>');
|
|
248
|
+
expect(patched).toContain(
|
|
249
|
+
'href="https://github.com/xt-ml/shadow-claw" target="_blank" rel="noopener noreferrer"',
|
|
250
|
+
);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("injects customSidebarHtml parameter directly into shadow-claw light DOM", () => {
|
|
254
|
+
const customHtml =
|
|
255
|
+
'<div slot="sidebar" class="my-custom-sidebar"><p>Hello</p></div>';
|
|
256
|
+
const patched = patchIndexHtml(baseHtml, {}, customHtml);
|
|
257
|
+
expect(patched).toContain(customHtml);
|
|
258
|
+
});
|
|
205
259
|
});
|
|
206
260
|
|
|
207
261
|
describe("patchManifest", () => {
|
|
@@ -756,5 +810,41 @@ https://example.com/about`;
|
|
|
756
810
|
),
|
|
757
811
|
).rejects.toThrow();
|
|
758
812
|
});
|
|
813
|
+
|
|
814
|
+
it("discovers pages/main/sidebar.html and injects it into dist/public/index.html", async () => {
|
|
815
|
+
const distPublicDir = path.join(tmpDir, "dist/public");
|
|
816
|
+
const repoDir = tmpDir;
|
|
817
|
+
const pagesMainDir = path.join(repoDir, "pages/main");
|
|
818
|
+
await mkdir(distPublicDir, { recursive: true });
|
|
819
|
+
await mkdir(pagesMainDir, { recursive: true });
|
|
820
|
+
|
|
821
|
+
const indexPath = path.join(distPublicDir, "index.html");
|
|
822
|
+
await writeFile(
|
|
823
|
+
indexPath,
|
|
824
|
+
"<!doctype html><html><head></head><body><shadow-claw></shadow-claw></body></html>",
|
|
825
|
+
"utf8",
|
|
826
|
+
);
|
|
827
|
+
|
|
828
|
+
const sidebarContent =
|
|
829
|
+
'<nav class="my-sidebar"><a href="/about">About Us</a></nav>';
|
|
830
|
+
await writeFile(
|
|
831
|
+
path.join(pagesMainDir, "sidebar.html"),
|
|
832
|
+
sidebarContent,
|
|
833
|
+
"utf8",
|
|
834
|
+
);
|
|
835
|
+
|
|
836
|
+
const siteConfigPath = path.join(repoDir, "shadow-claw.config.json");
|
|
837
|
+
const config = {
|
|
838
|
+
site: { title: "Custom Sidebar Site" },
|
|
839
|
+
};
|
|
840
|
+
await writeFile(siteConfigPath, JSON.stringify(config), "utf8");
|
|
841
|
+
|
|
842
|
+
const result = await applySiteConfig(distPublicDir, siteConfigPath);
|
|
843
|
+
expect(result.applied).toBe(true);
|
|
844
|
+
|
|
845
|
+
const patchedIndex = await readFile(indexPath, "utf8");
|
|
846
|
+
expect(patchedIndex).toContain('slot="sidebar"');
|
|
847
|
+
expect(patchedIndex).toContain("About Us");
|
|
848
|
+
});
|
|
759
849
|
});
|
|
760
850
|
});
|
|
@@ -57,12 +57,44 @@ export interface SiteConfigPwa {
|
|
|
57
57
|
screenshots?: any[];
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
export interface SiteConfigSidebarSectionItem {
|
|
61
|
+
title?: string;
|
|
62
|
+
label?: string;
|
|
63
|
+
href?: string;
|
|
64
|
+
target?: string;
|
|
65
|
+
rel?: string;
|
|
66
|
+
active?: boolean;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface SiteConfigSidebarSection {
|
|
70
|
+
title?: string;
|
|
71
|
+
headerHref?: string;
|
|
72
|
+
items?: SiteConfigSidebarSectionItem[];
|
|
73
|
+
html?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface SiteConfigSidebar {
|
|
77
|
+
pagesHidden?: boolean;
|
|
78
|
+
chatHidden?: boolean;
|
|
79
|
+
tasksHidden?: boolean;
|
|
80
|
+
filesHidden?: boolean;
|
|
81
|
+
defaultPage?: string;
|
|
82
|
+
slotHtml?: string;
|
|
83
|
+
slotPath?: string;
|
|
84
|
+
sections?: SiteConfigSidebarSection[];
|
|
85
|
+
}
|
|
86
|
+
|
|
60
87
|
export interface SiteConfig {
|
|
61
88
|
site?: SiteConfigSite;
|
|
62
89
|
branding?: SiteConfigBranding;
|
|
63
90
|
theme?: SiteConfigTheme;
|
|
64
91
|
pwa?: SiteConfigPwa;
|
|
65
|
-
|
|
92
|
+
sidebar?: SiteConfigSidebar;
|
|
93
|
+
pages?: {
|
|
94
|
+
notFoundPath?: string;
|
|
95
|
+
sortOrder?: string;
|
|
96
|
+
defaultPinnedPage?: string;
|
|
97
|
+
};
|
|
66
98
|
notFoundPath?: string;
|
|
67
99
|
manifestPath?: string;
|
|
68
100
|
sitemapPath?: string;
|
|
@@ -87,13 +119,11 @@ export function insertBeforeClosingHead(
|
|
|
87
119
|
html: string,
|
|
88
120
|
contentToInsert: string,
|
|
89
121
|
): string {
|
|
90
|
-
const
|
|
91
|
-
if (
|
|
122
|
+
const headMatch = /<\/head>/i.exec(html);
|
|
123
|
+
if (headMatch) {
|
|
124
|
+
const headIndex = headMatch.index;
|
|
92
125
|
return (
|
|
93
|
-
html.slice(0,
|
|
94
|
-
contentToInsert +
|
|
95
|
-
"\n" +
|
|
96
|
-
html.slice(lastHeadIndex)
|
|
126
|
+
html.slice(0, headIndex) + contentToInsert + "\n" + html.slice(headIndex)
|
|
97
127
|
);
|
|
98
128
|
}
|
|
99
129
|
return `${contentToInsert}\n${html}`;
|
|
@@ -137,7 +167,67 @@ async function writeText(filePath: string, content: string): Promise<void> {
|
|
|
137
167
|
await writeFile(filePath, content, "utf8");
|
|
138
168
|
}
|
|
139
169
|
|
|
140
|
-
export function
|
|
170
|
+
export function renderSidebarSectionsHtml(
|
|
171
|
+
sections: SiteConfigSidebarSection[],
|
|
172
|
+
): string {
|
|
173
|
+
if (!Array.isArray(sections) || sections.length === 0) {
|
|
174
|
+
return "";
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const sectionsHtml = sections
|
|
178
|
+
.map((section, idx) => {
|
|
179
|
+
if (section.html) {
|
|
180
|
+
return section.html;
|
|
181
|
+
}
|
|
182
|
+
const sectionId = section.title
|
|
183
|
+
? `sidebar-${section.title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`
|
|
184
|
+
: `sidebar-section-${idx + 1}`;
|
|
185
|
+
|
|
186
|
+
const headerContent = section.headerHref
|
|
187
|
+
? `<a href="${escapeHtml(section.headerHref)}" class="sidebar-link">${escapeHtml(section.title || "")}</a>`
|
|
188
|
+
: `<span>${escapeHtml(section.title || "")}</span>`;
|
|
189
|
+
|
|
190
|
+
const headerHtml = section.title
|
|
191
|
+
? ` <div class="sidebar-section-header">${headerContent}</div>`
|
|
192
|
+
: "";
|
|
193
|
+
|
|
194
|
+
const itemsHtml = (section.items || [])
|
|
195
|
+
.map((item) => {
|
|
196
|
+
const title = item.title || item.label || "";
|
|
197
|
+
const href = item.href || "#";
|
|
198
|
+
const targetAttr = item.target
|
|
199
|
+
? ` target="${escapeHtml(item.target)}"`
|
|
200
|
+
: "";
|
|
201
|
+
const relAttr = item.rel
|
|
202
|
+
? ` rel="${escapeHtml(item.rel)}"`
|
|
203
|
+
: item.target === "_blank"
|
|
204
|
+
? ' rel="noopener noreferrer"'
|
|
205
|
+
: "";
|
|
206
|
+
const activeClass = item.active ? " active" : "";
|
|
207
|
+
const ariaCurrent = item.active ? ' aria-current="page"' : "";
|
|
208
|
+
return ` <div class="sidebar-item"><a href="${escapeHtml(href)}"${targetAttr}${relAttr} class="sidebar-link${activeClass}"${ariaCurrent}>${escapeHtml(title)}</a></div>`;
|
|
209
|
+
})
|
|
210
|
+
.join("\n");
|
|
211
|
+
|
|
212
|
+
return [
|
|
213
|
+
` <section class="sidebar-section" id="${sectionId}">`,
|
|
214
|
+
headerHtml,
|
|
215
|
+
itemsHtml,
|
|
216
|
+
` </section>`,
|
|
217
|
+
]
|
|
218
|
+
.filter(Boolean)
|
|
219
|
+
.join("\n");
|
|
220
|
+
})
|
|
221
|
+
.join("\n");
|
|
222
|
+
|
|
223
|
+
return `<nav slot="sidebar" class="sidebar-custom-sections" aria-label="Site Navigation">\n${sectionsHtml}\n</nav>`;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function patchIndexHtml(
|
|
227
|
+
html: string,
|
|
228
|
+
config: SiteConfig,
|
|
229
|
+
customSidebarHtml?: string,
|
|
230
|
+
): string {
|
|
141
231
|
let next = html;
|
|
142
232
|
|
|
143
233
|
const site = config.site || {};
|
|
@@ -265,10 +355,24 @@ export function patchIndexHtml(html: string, config: SiteConfig): string {
|
|
|
265
355
|
if (theme.stylesheet) {
|
|
266
356
|
const stylesheetHref = resolveThemeStylesheetHref(theme.stylesheet);
|
|
267
357
|
const themeCssTag = `<link rel="stylesheet" href="${escapeHtml(stylesheetHref)}" />`;
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
)
|
|
358
|
+
const escapedHrefPattern = escapeHtml(stylesheetHref).replace(
|
|
359
|
+
/[.*+?^${}()|[\]\\]/g,
|
|
360
|
+
"\\$&",
|
|
361
|
+
);
|
|
362
|
+
const rawHrefPattern = stylesheetHref.replace(
|
|
363
|
+
/[.*+?^${}()|[\]\\]/g,
|
|
364
|
+
"\\$&",
|
|
365
|
+
);
|
|
366
|
+
const linkRegex = new RegExp(
|
|
367
|
+
`<link\\s+[^>]*href=["'](?:${rawHrefPattern}|${escapedHrefPattern})["'][^>]*>`,
|
|
368
|
+
"iu",
|
|
369
|
+
);
|
|
370
|
+
const headContent = next.slice(0, Math.max(0, next.indexOf("</head>")));
|
|
371
|
+
const headWithoutScripts = headContent.replace(
|
|
372
|
+
/<script\b[\s\S]*?<\/script>/gi,
|
|
373
|
+
"",
|
|
374
|
+
);
|
|
375
|
+
if (!linkRegex.test(headWithoutScripts)) {
|
|
272
376
|
if (/<link\s+rel="stylesheet"\s+href="index\.css"\s*\/?>/iu.test(next)) {
|
|
273
377
|
next = next.replace(
|
|
274
378
|
/(<link\s+rel="stylesheet"\s+href="index\.css"\s*\/?>)/iu,
|
|
@@ -313,6 +417,41 @@ export function patchIndexHtml(html: string, config: SiteConfig): string {
|
|
|
313
417
|
next = insertBeforeClosingHead(next, ` ${siteConfigScript}`);
|
|
314
418
|
}
|
|
315
419
|
|
|
420
|
+
const sidebarHtmlToInject =
|
|
421
|
+
customSidebarHtml ||
|
|
422
|
+
config.sidebar?.slotHtml ||
|
|
423
|
+
(config.sidebar?.sections
|
|
424
|
+
? renderSidebarSectionsHtml(config.sidebar.sections)
|
|
425
|
+
: "");
|
|
426
|
+
|
|
427
|
+
if (sidebarHtmlToInject) {
|
|
428
|
+
let formattedSidebarHtml = sidebarHtmlToInject.trim();
|
|
429
|
+
if (
|
|
430
|
+
!/\bslot="sidebar(?:-nav|-content|-footer)?"/iu.test(formattedSidebarHtml)
|
|
431
|
+
) {
|
|
432
|
+
formattedSidebarHtml = `<div slot="sidebar" class="sidebar-custom-sections">\n${formattedSidebarHtml}\n</div>`;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const existingMatch = next.match(
|
|
436
|
+
/<[^>]+?\bslot="sidebar(?:-nav|-content|-footer)?"[^>]*>[\s\S]*?<\/[^>]+>/iu,
|
|
437
|
+
);
|
|
438
|
+
if (existingMatch) {
|
|
439
|
+
next = next.replace(existingMatch[0], "");
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (next.includes("</shadow-claw>")) {
|
|
443
|
+
next = next.replace(
|
|
444
|
+
"</shadow-claw>",
|
|
445
|
+
` ${formattedSidebarHtml}\n</shadow-claw>`,
|
|
446
|
+
);
|
|
447
|
+
} else if (next.includes("<shadow-claw></shadow-claw>")) {
|
|
448
|
+
next = next.replace(
|
|
449
|
+
"<shadow-claw></shadow-claw>",
|
|
450
|
+
`<shadow-claw>\n ${formattedSidebarHtml}\n</shadow-claw>`,
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
316
455
|
return next;
|
|
317
456
|
}
|
|
318
457
|
|
|
@@ -993,10 +1132,39 @@ export async function applySiteConfig(
|
|
|
993
1132
|
|
|
994
1133
|
await copyCustomSiteFiles(config, distPublicDir, siteConfigPath);
|
|
995
1134
|
|
|
1135
|
+
const configDir = siteConfigPath
|
|
1136
|
+
? path.dirname(path.resolve(siteConfigPath))
|
|
1137
|
+
: process.cwd();
|
|
1138
|
+
const templateRootDir = getTemplateRootDir(configDir);
|
|
1139
|
+
|
|
1140
|
+
let sidebarHtml: string | undefined;
|
|
1141
|
+
if (config.sidebar?.slotHtml) {
|
|
1142
|
+
sidebarHtml = config.sidebar.slotHtml;
|
|
1143
|
+
} else if (config.sidebar?.sections) {
|
|
1144
|
+
sidebarHtml = renderSidebarSectionsHtml(config.sidebar.sections);
|
|
1145
|
+
} else {
|
|
1146
|
+
const sidebarCandidates = [
|
|
1147
|
+
config.sidebar?.slotPath,
|
|
1148
|
+
"pages/main/sidebar.html",
|
|
1149
|
+
"pages/sidebar.html",
|
|
1150
|
+
"sidebar.html",
|
|
1151
|
+
"resources/sidebar.html",
|
|
1152
|
+
].filter(Boolean) as string[];
|
|
1153
|
+
|
|
1154
|
+
const candidatePaths = sidebarCandidates.flatMap((c) =>
|
|
1155
|
+
getCandidateFilePaths(c, configDir, templateRootDir),
|
|
1156
|
+
);
|
|
1157
|
+
const foundSidebar = await findFirstExisting(candidatePaths);
|
|
1158
|
+
if (foundSidebar) {
|
|
1159
|
+
sidebarHtml = (await readText(foundSidebar)) ?? undefined;
|
|
1160
|
+
console.log(` Found slotted sidebar: ${foundSidebar}`);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
|
|
996
1164
|
const indexPath = path.join(distPublicDir, "index.html");
|
|
997
1165
|
const indexHtml = await readText(indexPath);
|
|
998
1166
|
if (indexHtml) {
|
|
999
|
-
const patched = patchIndexHtml(indexHtml, config);
|
|
1167
|
+
const patched = patchIndexHtml(indexHtml, config, sidebarHtml);
|
|
1000
1168
|
await writeText(indexPath, patched);
|
|
1001
1169
|
console.log(" Patched index.html");
|
|
1002
1170
|
}
|
|
@@ -90,6 +90,10 @@ a:hover {
|
|
|
90
90
|
transition: transform 0.2s ease;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
.header-main-toggle {
|
|
94
|
+
display: var(--shadow-claw-header-main-toggle-display, block);
|
|
95
|
+
}
|
|
96
|
+
|
|
93
97
|
.header-main-toggle[aria-pressed="true"],
|
|
94
98
|
.activity-log-toggle[aria-pressed="true"] {
|
|
95
99
|
box-shadow: 0 0 0.5rem
|
|
@@ -279,6 +283,28 @@ a:hover {
|
|
|
279
283
|
padding: 0.5rem;
|
|
280
284
|
}
|
|
281
285
|
|
|
286
|
+
.nav-menu:not(:has(.nav-item:not([hidden]))) {
|
|
287
|
+
display: none;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
slot[name="sidebar"],
|
|
291
|
+
slot[name="sidebar-nav"],
|
|
292
|
+
slot[name="sidebar-content"],
|
|
293
|
+
slot[name="sidebar-footer"] {
|
|
294
|
+
display: block;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
::slotted([slot="sidebar"]),
|
|
298
|
+
::slotted([slot="sidebar-nav"]),
|
|
299
|
+
::slotted([slot="sidebar-content"]),
|
|
300
|
+
::slotted([slot="sidebar-footer"]) {
|
|
301
|
+
display: block;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.sidebar-footer {
|
|
305
|
+
display: var(--shadow-claw-sidebar-footer-display, block);
|
|
306
|
+
}
|
|
307
|
+
|
|
282
308
|
.sidebar-spacer {
|
|
283
309
|
flex: 1;
|
|
284
310
|
}
|
|
@@ -136,8 +136,12 @@
|
|
|
136
136
|
<li class="nav-item" data-page="files">📁 Files</li>
|
|
137
137
|
</ul>
|
|
138
138
|
</nav>
|
|
139
|
+
<slot name="sidebar-nav"></slot>
|
|
140
|
+
<slot name="sidebar"></slot>
|
|
141
|
+
<slot name="sidebar-content"></slot>
|
|
139
142
|
<div class="sidebar-spacer"></div>
|
|
140
143
|
<shadow-claw-conversations></shadow-claw-conversations>
|
|
144
|
+
<slot name="sidebar-footer"></slot>
|
|
141
145
|
<div class="sidebar-footer">
|
|
142
146
|
<button class="settings-btn" data-action="show-settings">
|
|
143
147
|
⚙️ Settings
|
|
@@ -2,6 +2,7 @@ import { DEFAULT_GROUP_ID } from "../../../config/config.js";
|
|
|
2
2
|
|
|
3
3
|
import { applyAnchorWithRetry } from "./applyAnchorWithRetry.js";
|
|
4
4
|
import { showPage } from "./showPage.js";
|
|
5
|
+
import { syncSlottedSidebarActiveLinks } from "./syncSlottedSidebarActiveLinks.js";
|
|
5
6
|
|
|
6
7
|
import type { ShadowClawDatabase } from "../../../db/types.js";
|
|
7
8
|
import type { ShadowClawAppRoute } from "../../../core/app-routes.js";
|
|
@@ -139,4 +140,6 @@ export async function applyRoute(
|
|
|
139
140
|
}
|
|
140
141
|
}
|
|
141
142
|
}
|
|
143
|
+
|
|
144
|
+
syncSlottedSidebarActiveLinks(shadowClaw);
|
|
142
145
|
}
|
|
@@ -817,6 +817,12 @@ describe("bindEventListeners", () => {
|
|
|
817
817
|
oStore,
|
|
818
818
|
new URL("https://example.com/files/main/"),
|
|
819
819
|
);
|
|
820
|
+
|
|
821
|
+
// Verify that popstateListener does not call applyRouteFromCurrentLocation when inFeedScroll is true
|
|
822
|
+
mockApplyRouteFromCurrentLocation.mockClear();
|
|
823
|
+
(win as any).history = { state: { inFeedScroll: true } };
|
|
824
|
+
shadowClaw.popstateListener();
|
|
825
|
+
expect(mockApplyRouteFromCurrentLocation).not.toHaveBeenCalled();
|
|
820
826
|
});
|
|
821
827
|
});
|
|
822
828
|
|
|
@@ -12,6 +12,7 @@ import { showPage } from "./showPage.js";
|
|
|
12
12
|
import { supportsNavigationApi } from "./supportsNavigationApi.js";
|
|
13
13
|
import { setupAppLifecycle } from "./setupAppLifecycle.js";
|
|
14
14
|
import { syncPageHeaderMainVisibilityOverride } from "./syncPageHeaderMainVisibilityOverride.js";
|
|
15
|
+
import { setupSlottedSidebarActiveLinks } from "./syncSlottedSidebarActiveLinks.js";
|
|
15
16
|
|
|
16
17
|
import { toggleActivityLogVisibility } from "./toggleActivityLogVisibility.js";
|
|
17
18
|
import { togglePageHeaderMainVisibility } from "./togglePageHeaderMainVisibility.js";
|
|
@@ -88,6 +89,28 @@ export function bindEventListeners(
|
|
|
88
89
|
});
|
|
89
90
|
});
|
|
90
91
|
|
|
92
|
+
sidebar.addEventListener("click", (e: Event) => {
|
|
93
|
+
const target = e.target as HTMLElement | null;
|
|
94
|
+
if (
|
|
95
|
+
win.innerWidth < 896 &&
|
|
96
|
+
target?.closest("a, button, .nav-item, .sidebar-link, .sidebar-item")
|
|
97
|
+
) {
|
|
98
|
+
sidebar.classList.remove("open");
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
if (typeof (shadowClaw as any)?.addEventListener === "function") {
|
|
103
|
+
shadowClaw.addEventListener("click", (e: Event) => {
|
|
104
|
+
const target = e.target as HTMLElement | null;
|
|
105
|
+
if (
|
|
106
|
+
win.innerWidth < 896 &&
|
|
107
|
+
target?.closest('[slot^="sidebar"] a, .sidebar-custom-sections a')
|
|
108
|
+
) {
|
|
109
|
+
sidebar.classList.remove("open");
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
91
114
|
// Close sidebar when clicking outside of it (mobile only).
|
|
92
115
|
// Use composedPath() instead of e.target because Shadow DOM event
|
|
93
116
|
// retargeting makes e.target the host element at the doc level,
|
|
@@ -251,7 +274,11 @@ export function bindEventListeners(
|
|
|
251
274
|
|
|
252
275
|
shadowClaw.navigationListenerAttached = true;
|
|
253
276
|
} else {
|
|
254
|
-
shadowClaw.popstateListener = () => {
|
|
277
|
+
shadowClaw.popstateListener = (ev?: any) => {
|
|
278
|
+
const state = ev?.state || (win as any).history?.state;
|
|
279
|
+
if (state?.inFeedScroll || state?.scrollSpy || state?.suppressRouter) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
255
282
|
applyRouteFromCurrentLocation(
|
|
256
283
|
shadow,
|
|
257
284
|
shadowClaw,
|
|
@@ -312,4 +339,6 @@ export function bindEventListeners(
|
|
|
312
339
|
shadowClaw.orchestrator,
|
|
313
340
|
);
|
|
314
341
|
}
|
|
342
|
+
|
|
343
|
+
setupSlottedSidebarActiveLinks(shadowClaw);
|
|
315
344
|
}
|
|
@@ -93,4 +93,56 @@ describe("getRoute", () => {
|
|
|
93
93
|
|
|
94
94
|
expect(result).toBeUndefined();
|
|
95
95
|
});
|
|
96
|
+
|
|
97
|
+
it("returns undefined if destination state indicates an in-feed scroll", () => {
|
|
98
|
+
const navigateEvent = new Event("navigate") as any;
|
|
99
|
+
navigateEvent.navigationType = "replace";
|
|
100
|
+
navigateEvent.destination = {
|
|
101
|
+
url: `${window.location.origin}/test`,
|
|
102
|
+
getState: () => ({ inFeedScroll: true }),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const result = getRoute(db, navigateEvent);
|
|
106
|
+
expect(result).toBeUndefined();
|
|
107
|
+
expect(isPossibleAppRouteMock).not.toHaveBeenCalled();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("returns undefined if window.history.state indicates an in-feed scroll", () => {
|
|
111
|
+
const origState = window.history.state;
|
|
112
|
+
try {
|
|
113
|
+
window.history.replaceState({ inFeedScroll: true }, "", "/test");
|
|
114
|
+
const navigateEvent = new Event("navigate") as any;
|
|
115
|
+
navigateEvent.navigationType = "replace";
|
|
116
|
+
navigateEvent.destination = {
|
|
117
|
+
url: `${window.location.origin}/test`,
|
|
118
|
+
getState: () => null,
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const result = getRoute(db, navigateEvent);
|
|
122
|
+
expect(result).toBeUndefined();
|
|
123
|
+
expect(isPossibleAppRouteMock).not.toHaveBeenCalled();
|
|
124
|
+
} finally {
|
|
125
|
+
window.history.replaceState(origState, "", "/");
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("does not ignore push navigation even if window.history.state has inFeedScroll: true", () => {
|
|
130
|
+
const origState = window.history.state;
|
|
131
|
+
try {
|
|
132
|
+
window.history.replaceState({ inFeedScroll: true }, "", "/");
|
|
133
|
+
const navigateEvent = new Event("navigate") as any;
|
|
134
|
+
navigateEvent.navigationType = "push";
|
|
135
|
+
navigateEvent.destination = {
|
|
136
|
+
url: `${window.location.origin}/about`,
|
|
137
|
+
getState: () => null,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const result = getRoute(db, navigateEvent);
|
|
141
|
+
expect(result).toBeDefined();
|
|
142
|
+
expect(result?.parsedUrl.pathname).toBe("/about");
|
|
143
|
+
expect(isPossibleAppRouteMock).toHaveBeenCalledWith("/about");
|
|
144
|
+
} finally {
|
|
145
|
+
window.history.replaceState(origState, "", "/");
|
|
146
|
+
}
|
|
147
|
+
});
|
|
96
148
|
});
|
|
@@ -11,6 +11,24 @@ export function getRoute(db: ShadowClawDatabase, ev: Event) {
|
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
const destinationState =
|
|
15
|
+
typeof navigateEvent?.destination?.getState === "function"
|
|
16
|
+
? navigateEvent.destination.getState()
|
|
17
|
+
: null;
|
|
18
|
+
const navState =
|
|
19
|
+
destinationState ||
|
|
20
|
+
(navigateEvent.navigationType === "replace" &&
|
|
21
|
+
typeof history !== "undefined"
|
|
22
|
+
? history.state
|
|
23
|
+
: null);
|
|
24
|
+
if (
|
|
25
|
+
navState?.inFeedScroll ||
|
|
26
|
+
navState?.scrollSpy ||
|
|
27
|
+
navState?.suppressRouter
|
|
28
|
+
) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
14
32
|
const destinationUrl = navigateEvent?.destination?.url;
|
|
15
33
|
if (typeof destinationUrl !== "string") {
|
|
16
34
|
return;
|
|
@@ -111,4 +111,25 @@ describe("navigateToRoute", () => {
|
|
|
111
111
|
route,
|
|
112
112
|
);
|
|
113
113
|
});
|
|
114
|
+
|
|
115
|
+
it("should applyRoute directly without calling nav.navigate if already at finalPath", async () => {
|
|
116
|
+
mockSupportsNavigationApi.mockReturnValue(true);
|
|
117
|
+
const origPathname = window.location.pathname;
|
|
118
|
+
try {
|
|
119
|
+
window.history.replaceState({}, "", "/base/chat");
|
|
120
|
+
await navigateToRoute(shadowRoot, shadowClaw, db, fStore, oStore, route);
|
|
121
|
+
|
|
122
|
+
expect(mockNav.navigate).not.toHaveBeenCalled();
|
|
123
|
+
expect(mockApplyRoute).toHaveBeenCalledWith(
|
|
124
|
+
shadowRoot,
|
|
125
|
+
shadowClaw,
|
|
126
|
+
db,
|
|
127
|
+
fStore,
|
|
128
|
+
oStore,
|
|
129
|
+
route,
|
|
130
|
+
);
|
|
131
|
+
} finally {
|
|
132
|
+
window.history.replaceState({}, "", origPathname);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
114
135
|
});
|