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
package/package.json
CHANGED
package/src/cli/build/build.ts
CHANGED
|
@@ -186,23 +186,26 @@ export async function runBuild(options: RunBuildOptions = {}): Promise<void> {
|
|
|
186
186
|
|
|
187
187
|
await run("npm run -s rolldown");
|
|
188
188
|
|
|
189
|
+
const siteConfigCandidate = await findFirstExistingPath(
|
|
190
|
+
getSiteConfigCandidates(),
|
|
191
|
+
);
|
|
192
|
+
const siteConfigPath = siteConfigCandidate || "pages/site-config.json";
|
|
193
|
+
|
|
189
194
|
if (prerenderMainMemory) {
|
|
190
195
|
await prerenderDsdShell({
|
|
191
196
|
indexPath: "dist/public/index.html",
|
|
192
197
|
sourcePath: "pages/main",
|
|
193
198
|
prerenderPages,
|
|
199
|
+
siteConfigPath,
|
|
194
200
|
});
|
|
195
201
|
} else {
|
|
196
202
|
await prerenderDsdShell({
|
|
197
203
|
indexPath: "dist/public/index.html",
|
|
198
204
|
noSeed: true,
|
|
205
|
+
siteConfigPath,
|
|
199
206
|
});
|
|
200
207
|
}
|
|
201
208
|
|
|
202
|
-
const siteConfigCandidate = await findFirstExistingPath(
|
|
203
|
-
getSiteConfigCandidates(),
|
|
204
|
-
);
|
|
205
|
-
const siteConfigPath = siteConfigCandidate || "pages/site-config.json";
|
|
206
209
|
try {
|
|
207
210
|
await applySiteConfig("dist/public", siteConfigPath);
|
|
208
211
|
} catch {}
|
|
@@ -299,6 +302,7 @@ export async function runBuild(options: RunBuildOptions = {}): Promise<void> {
|
|
|
299
302
|
routesPath,
|
|
300
303
|
sourcePath: "pages/main",
|
|
301
304
|
prerenderPages,
|
|
305
|
+
siteConfigPath,
|
|
302
306
|
});
|
|
303
307
|
|
|
304
308
|
await run("npm run -s build:service-worker");
|
|
@@ -509,27 +513,29 @@ export async function runBuild(options: RunBuildOptions = {}): Promise<void> {
|
|
|
509
513
|
}
|
|
510
514
|
}
|
|
511
515
|
|
|
512
|
-
// 7. Prerender DSD Shell
|
|
516
|
+
// 7. Prerender DSD Shell & 8. Apply site-config
|
|
517
|
+
const siteConfigCandidate = await findFirstExistingPath(
|
|
518
|
+
getSiteConfigCandidates(contentRoot),
|
|
519
|
+
);
|
|
520
|
+
const siteConfigPath =
|
|
521
|
+
siteConfigCandidate || join(contentRoot, "pages/site-config.json");
|
|
522
|
+
|
|
513
523
|
const indexPath = join(distPublicDir, "index.html");
|
|
514
524
|
if (prerenderMainMemory && (await pathExists(contentPagesMain))) {
|
|
515
525
|
await prerenderDsdShell({
|
|
516
526
|
indexPath,
|
|
517
527
|
sourcePath: contentPagesMain,
|
|
518
528
|
prerenderPages,
|
|
529
|
+
siteConfigPath,
|
|
519
530
|
});
|
|
520
531
|
} else {
|
|
521
532
|
await prerenderDsdShell({
|
|
522
533
|
indexPath,
|
|
523
534
|
noSeed: true,
|
|
535
|
+
siteConfigPath,
|
|
524
536
|
});
|
|
525
537
|
}
|
|
526
538
|
|
|
527
|
-
// 8. Apply site-config
|
|
528
|
-
const siteConfigCandidate = await findFirstExistingPath(
|
|
529
|
-
getSiteConfigCandidates(contentRoot),
|
|
530
|
-
);
|
|
531
|
-
const siteConfigPath =
|
|
532
|
-
siteConfigCandidate || join(contentRoot, "pages/site-config.json");
|
|
533
539
|
try {
|
|
534
540
|
await applySiteConfig(distPublicDir, siteConfigPath);
|
|
535
541
|
} catch {}
|
|
@@ -656,6 +662,7 @@ export async function runBuild(options: RunBuildOptions = {}): Promise<void> {
|
|
|
656
662
|
routesPath,
|
|
657
663
|
sourcePath: mainSourcePath,
|
|
658
664
|
prerenderPages,
|
|
665
|
+
siteConfigPath,
|
|
659
666
|
});
|
|
660
667
|
|
|
661
668
|
// 11. Service Worker patch
|
|
@@ -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
|
|
|
@@ -962,7 +968,13 @@ export async function prerenderDsdShell(
|
|
|
962
968
|
let siteConfig: any = {};
|
|
963
969
|
const configCandidatePaths = [
|
|
964
970
|
options.siteConfigPath,
|
|
971
|
+
path.resolve("shadow-claw-config.json"),
|
|
972
|
+
path.resolve("shadow-claw.config.json"),
|
|
973
|
+
path.resolve("shadowclaw.config.json"),
|
|
974
|
+
path.resolve("pages/shadow-claw-config.json"),
|
|
975
|
+
path.resolve("pages/shadow-claw.config.json"),
|
|
965
976
|
path.resolve("site-config.json"),
|
|
977
|
+
path.resolve("pages/site-config.json"),
|
|
966
978
|
].filter(Boolean) as string[];
|
|
967
979
|
|
|
968
980
|
for (const cfgPath of configCandidatePaths) {
|
|
@@ -42,6 +42,7 @@ export interface PrerenderPrettyPathsOptions {
|
|
|
42
42
|
indexPath?: string;
|
|
43
43
|
prerenderPages?: string | number;
|
|
44
44
|
silent?: boolean;
|
|
45
|
+
siteConfigPath?: string;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
export interface PrerenderPrettyPathsResult {
|
|
@@ -64,6 +65,25 @@ export async function prerenderPrettyPaths(
|
|
|
64
65
|
options.indexPath || path.join(publicDir, "index.html"),
|
|
65
66
|
);
|
|
66
67
|
|
|
68
|
+
let siteConfig: any = {};
|
|
69
|
+
const configCandidatePaths = [
|
|
70
|
+
options.siteConfigPath,
|
|
71
|
+
path.resolve(path.dirname(sourcePath), "shadow-claw.config.json"),
|
|
72
|
+
path.resolve(path.dirname(sourcePath), "site-config.json"),
|
|
73
|
+
path.resolve("shadow-claw.config.json"),
|
|
74
|
+
path.resolve("site-config.json"),
|
|
75
|
+
path.join(publicDir, "shadow-claw.config.json"),
|
|
76
|
+
path.join(publicDir, "site-config.json"),
|
|
77
|
+
].filter(Boolean) as string[];
|
|
78
|
+
|
|
79
|
+
for (const candidate of configCandidatePaths) {
|
|
80
|
+
try {
|
|
81
|
+
const raw = await readFile(candidate, "utf8");
|
|
82
|
+
siteConfig = JSON.parse(raw);
|
|
83
|
+
break;
|
|
84
|
+
} catch {}
|
|
85
|
+
}
|
|
86
|
+
|
|
67
87
|
const rawPagesOpt =
|
|
68
88
|
options.prerenderPages !== undefined
|
|
69
89
|
? options.prerenderPages
|
|
@@ -360,6 +380,7 @@ export async function prerenderPrettyPaths(
|
|
|
360
380
|
shadowClawDsdTemplate = buildShadowClawDsdTemplateWithoutPages(
|
|
361
381
|
shadowClawTemplateContent,
|
|
362
382
|
shadowClawCssSource,
|
|
383
|
+
siteConfig.sidebar,
|
|
363
384
|
);
|
|
364
385
|
} else {
|
|
365
386
|
const pagesDsdHost = buildPagesDsdHost(
|
|
@@ -375,6 +396,7 @@ export async function prerenderPrettyPaths(
|
|
|
375
396
|
shadowClawTemplateContent,
|
|
376
397
|
pagesDsdHost,
|
|
377
398
|
shadowClawCssSource,
|
|
399
|
+
siteConfig.sidebar,
|
|
378
400
|
);
|
|
379
401
|
}
|
|
380
402
|
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { describe, it, expect } from "@jest/globals";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
findClosingHeadIndex,
|
|
4
|
+
insertBeforeClosingHead,
|
|
5
|
+
} from "./insert-before-closing-head.js";
|
|
3
6
|
|
|
4
7
|
describe("insertBeforeClosingHead", () => {
|
|
5
8
|
it("inserts content before </head> tag when present", () => {
|
|
@@ -16,4 +19,34 @@ describe("insertBeforeClosingHead", () => {
|
|
|
16
19
|
const result = insertBeforeClosingHead(html, tag);
|
|
17
20
|
expect(result.startsWith(`${tag}\n`)).toBe(true);
|
|
18
21
|
});
|
|
22
|
+
|
|
23
|
+
it("targets the first outer </head> tag when nested templates have their own head", () => {
|
|
24
|
+
const html =
|
|
25
|
+
'<!doctype html><html><head><title>Outer</title></head><body><template shadowrootmode="open"><head><title>Inner</title></head></template></body></html>';
|
|
26
|
+
const tag = '<script id="outer-test">true</script>';
|
|
27
|
+
const result = insertBeforeClosingHead(html, tag);
|
|
28
|
+
const outerIndex = result.indexOf(tag);
|
|
29
|
+
const firstHeadClose = result.indexOf("</head>");
|
|
30
|
+
const secondHeadClose = result.lastIndexOf("</head>");
|
|
31
|
+
expect(outerIndex).toBeLessThan(firstHeadClose);
|
|
32
|
+
expect(firstHeadClose).toBeLessThan(secondHeadClose);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("ignores </head> string literals inside inlined <script> blocks", () => {
|
|
36
|
+
const html =
|
|
37
|
+
'<!doctype html><html><head><title>Outer</title><script>var x = "<head></head>";</script></head><body></body></html>';
|
|
38
|
+
const tag = '<link rel="stylesheet" href="theme.css" />';
|
|
39
|
+
const result = insertBeforeClosingHead(html, tag);
|
|
40
|
+
expect(result).toContain(`${tag}\n</head><body>`);
|
|
41
|
+
expect(findClosingHeadIndex(html)).toBe(html.lastIndexOf("</head>"));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("ignores </head> inside comments and style blocks", () => {
|
|
45
|
+
const html =
|
|
46
|
+
"<!doctype html><html><head><!-- </head> --><style>/* </head> */</style></head><body></body></html>";
|
|
47
|
+
const tag = '<link rel="stylesheet" href="theme.css" />';
|
|
48
|
+
const result = insertBeforeClosingHead(html, tag);
|
|
49
|
+
expect(result).toContain(`${tag}\n</head><body>`);
|
|
50
|
+
expect(findClosingHeadIndex(html)).toBe(html.lastIndexOf("</head>"));
|
|
51
|
+
});
|
|
19
52
|
});
|
|
@@ -1,14 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds the index of the top-level </head> closing tag in an HTML document,
|
|
3
|
+
* skipping any occurrences of "</head>" inside <script>, <style>, <template>,
|
|
4
|
+
* or HTML comments (<!-- ... -->).
|
|
5
|
+
*/
|
|
6
|
+
export function findClosingHeadIndex(html: string): number {
|
|
7
|
+
const tokenRegex =
|
|
8
|
+
/<!--[\s\S]*?-->|<script\b[\s\S]*?<\/script>|<style\b[\s\S]*?<\/style>|<template\b[\s\S]*?<\/template>|<\/head>/gi;
|
|
9
|
+
let match: RegExpExecArray | null;
|
|
10
|
+
while ((match = tokenRegex.exec(html)) !== null) {
|
|
11
|
+
if (match[0].toLowerCase().startsWith("</head")) {
|
|
12
|
+
return match.index;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return -1;
|
|
16
|
+
}
|
|
17
|
+
|
|
1
18
|
export function insertBeforeClosingHead(
|
|
2
19
|
html: string,
|
|
3
20
|
contentToInsert: string,
|
|
4
21
|
): string {
|
|
5
|
-
const
|
|
6
|
-
if (
|
|
22
|
+
const headIndex = findClosingHeadIndex(html);
|
|
23
|
+
if (headIndex !== -1) {
|
|
7
24
|
return (
|
|
8
|
-
html.slice(0,
|
|
9
|
-
contentToInsert +
|
|
10
|
-
"\n" +
|
|
11
|
-
html.slice(lastHeadIndex)
|
|
25
|
+
html.slice(0, headIndex) + contentToInsert + "\n" + html.slice(headIndex)
|
|
12
26
|
);
|
|
13
27
|
}
|
|
14
28
|
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
|
});
|
|
@@ -14,6 +14,11 @@ import { fileURLToPath } from "node:url";
|
|
|
14
14
|
|
|
15
15
|
import { resolveCustomElementScripts } from "./custom-elements/resolve-custom-element-scripts.js";
|
|
16
16
|
import { sanitizeEmbeddedCustomElementScripts } from "./custom-elements/sanitize-embedded-custom-element-scripts.js";
|
|
17
|
+
import {
|
|
18
|
+
findClosingHeadIndex,
|
|
19
|
+
insertBeforeClosingHead,
|
|
20
|
+
} from "../prerender/utils/insert-before-closing-head.js";
|
|
21
|
+
import { applySidebarVisibilityToTemplate } from "../prerender/dsd-shell/prerender-dsd-shell.js";
|
|
17
22
|
|
|
18
23
|
export interface SiteConfigSite {
|
|
19
24
|
title?: string;
|
|
@@ -57,12 +62,44 @@ export interface SiteConfigPwa {
|
|
|
57
62
|
screenshots?: any[];
|
|
58
63
|
}
|
|
59
64
|
|
|
65
|
+
export interface SiteConfigSidebarSectionItem {
|
|
66
|
+
title?: string;
|
|
67
|
+
label?: string;
|
|
68
|
+
href?: string;
|
|
69
|
+
target?: string;
|
|
70
|
+
rel?: string;
|
|
71
|
+
active?: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface SiteConfigSidebarSection {
|
|
75
|
+
title?: string;
|
|
76
|
+
headerHref?: string;
|
|
77
|
+
items?: SiteConfigSidebarSectionItem[];
|
|
78
|
+
html?: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface SiteConfigSidebar {
|
|
82
|
+
pagesHidden?: boolean;
|
|
83
|
+
chatHidden?: boolean;
|
|
84
|
+
tasksHidden?: boolean;
|
|
85
|
+
filesHidden?: boolean;
|
|
86
|
+
defaultPage?: string;
|
|
87
|
+
slotHtml?: string;
|
|
88
|
+
slotPath?: string;
|
|
89
|
+
sections?: SiteConfigSidebarSection[];
|
|
90
|
+
}
|
|
91
|
+
|
|
60
92
|
export interface SiteConfig {
|
|
61
93
|
site?: SiteConfigSite;
|
|
62
94
|
branding?: SiteConfigBranding;
|
|
63
95
|
theme?: SiteConfigTheme;
|
|
64
96
|
pwa?: SiteConfigPwa;
|
|
65
|
-
|
|
97
|
+
sidebar?: SiteConfigSidebar;
|
|
98
|
+
pages?: {
|
|
99
|
+
notFoundPath?: string;
|
|
100
|
+
sortOrder?: string;
|
|
101
|
+
defaultPinnedPage?: string;
|
|
102
|
+
};
|
|
66
103
|
notFoundPath?: string;
|
|
67
104
|
manifestPath?: string;
|
|
68
105
|
sitemapPath?: string;
|
|
@@ -83,21 +120,7 @@ export function escapeHtml(str: string): string {
|
|
|
83
120
|
.replace(/'/g, "'");
|
|
84
121
|
}
|
|
85
122
|
|
|
86
|
-
export
|
|
87
|
-
html: string,
|
|
88
|
-
contentToInsert: string,
|
|
89
|
-
): string {
|
|
90
|
-
const lastHeadIndex = html.lastIndexOf("</head>");
|
|
91
|
-
if (lastHeadIndex !== -1) {
|
|
92
|
-
return (
|
|
93
|
-
html.slice(0, lastHeadIndex) +
|
|
94
|
-
contentToInsert +
|
|
95
|
-
"\n" +
|
|
96
|
-
html.slice(lastHeadIndex)
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
return `${contentToInsert}\n${html}`;
|
|
100
|
-
}
|
|
123
|
+
export { insertBeforeClosingHead, findClosingHeadIndex };
|
|
101
124
|
|
|
102
125
|
const FLATTENED_STYLESHEET_PREFIXES = [
|
|
103
126
|
"pages/resources/",
|
|
@@ -137,7 +160,67 @@ async function writeText(filePath: string, content: string): Promise<void> {
|
|
|
137
160
|
await writeFile(filePath, content, "utf8");
|
|
138
161
|
}
|
|
139
162
|
|
|
140
|
-
export function
|
|
163
|
+
export function renderSidebarSectionsHtml(
|
|
164
|
+
sections: SiteConfigSidebarSection[],
|
|
165
|
+
): string {
|
|
166
|
+
if (!Array.isArray(sections) || sections.length === 0) {
|
|
167
|
+
return "";
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const sectionsHtml = sections
|
|
171
|
+
.map((section, idx) => {
|
|
172
|
+
if (section.html) {
|
|
173
|
+
return section.html;
|
|
174
|
+
}
|
|
175
|
+
const sectionId = section.title
|
|
176
|
+
? `sidebar-${section.title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`
|
|
177
|
+
: `sidebar-section-${idx + 1}`;
|
|
178
|
+
|
|
179
|
+
const headerContent = section.headerHref
|
|
180
|
+
? `<a href="${escapeHtml(section.headerHref)}" class="sidebar-link">${escapeHtml(section.title || "")}</a>`
|
|
181
|
+
: `<span>${escapeHtml(section.title || "")}</span>`;
|
|
182
|
+
|
|
183
|
+
const headerHtml = section.title
|
|
184
|
+
? ` <div class="sidebar-section-header">${headerContent}</div>`
|
|
185
|
+
: "";
|
|
186
|
+
|
|
187
|
+
const itemsHtml = (section.items || [])
|
|
188
|
+
.map((item) => {
|
|
189
|
+
const title = item.title || item.label || "";
|
|
190
|
+
const href = item.href || "#";
|
|
191
|
+
const targetAttr = item.target
|
|
192
|
+
? ` target="${escapeHtml(item.target)}"`
|
|
193
|
+
: "";
|
|
194
|
+
const relAttr = item.rel
|
|
195
|
+
? ` rel="${escapeHtml(item.rel)}"`
|
|
196
|
+
: item.target === "_blank"
|
|
197
|
+
? ' rel="noopener noreferrer"'
|
|
198
|
+
: "";
|
|
199
|
+
const activeClass = item.active ? " active" : "";
|
|
200
|
+
const ariaCurrent = item.active ? ' aria-current="page"' : "";
|
|
201
|
+
return ` <div class="sidebar-item"><a href="${escapeHtml(href)}"${targetAttr}${relAttr} class="sidebar-link${activeClass}"${ariaCurrent}>${escapeHtml(title)}</a></div>`;
|
|
202
|
+
})
|
|
203
|
+
.join("\n");
|
|
204
|
+
|
|
205
|
+
return [
|
|
206
|
+
` <section class="sidebar-section" id="${sectionId}">`,
|
|
207
|
+
headerHtml,
|
|
208
|
+
itemsHtml,
|
|
209
|
+
` </section>`,
|
|
210
|
+
]
|
|
211
|
+
.filter(Boolean)
|
|
212
|
+
.join("\n");
|
|
213
|
+
})
|
|
214
|
+
.join("\n");
|
|
215
|
+
|
|
216
|
+
return `<nav slot="sidebar" class="sidebar-custom-sections" aria-label="Site Navigation">\n${sectionsHtml}\n</nav>`;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function patchIndexHtml(
|
|
220
|
+
html: string,
|
|
221
|
+
config: SiteConfig,
|
|
222
|
+
customSidebarHtml?: string,
|
|
223
|
+
): string {
|
|
141
224
|
let next = html;
|
|
142
225
|
|
|
143
226
|
const site = config.site || {};
|
|
@@ -265,10 +348,26 @@ export function patchIndexHtml(html: string, config: SiteConfig): string {
|
|
|
265
348
|
if (theme.stylesheet) {
|
|
266
349
|
const stylesheetHref = resolveThemeStylesheetHref(theme.stylesheet);
|
|
267
350
|
const themeCssTag = `<link rel="stylesheet" href="${escapeHtml(stylesheetHref)}" />`;
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
)
|
|
351
|
+
const escapedHrefPattern = escapeHtml(stylesheetHref).replace(
|
|
352
|
+
/[.*+?^${}()|[\]\\]/g,
|
|
353
|
+
"\\$&",
|
|
354
|
+
);
|
|
355
|
+
const rawHrefPattern = stylesheetHref.replace(
|
|
356
|
+
/[.*+?^${}()|[\]\\]/g,
|
|
357
|
+
"\\$&",
|
|
358
|
+
);
|
|
359
|
+
const linkRegex = new RegExp(
|
|
360
|
+
`<link\\s+[^>]*href=["'](?:${rawHrefPattern}|${escapedHrefPattern})["'][^>]*>`,
|
|
361
|
+
"iu",
|
|
362
|
+
);
|
|
363
|
+
const closingHeadIdx = findClosingHeadIndex(next);
|
|
364
|
+
const headContent =
|
|
365
|
+
closingHeadIdx !== -1 ? next.slice(0, closingHeadIdx) : next;
|
|
366
|
+
const headWithoutScripts = headContent.replace(
|
|
367
|
+
/<script\b[\s\S]*?<\/script>/gi,
|
|
368
|
+
"",
|
|
369
|
+
);
|
|
370
|
+
if (!linkRegex.test(headWithoutScripts)) {
|
|
272
371
|
if (/<link\s+rel="stylesheet"\s+href="index\.css"\s*\/?>/iu.test(next)) {
|
|
273
372
|
next = next.replace(
|
|
274
373
|
/(<link\s+rel="stylesheet"\s+href="index\.css"\s*\/?>)/iu,
|
|
@@ -313,6 +412,45 @@ export function patchIndexHtml(html: string, config: SiteConfig): string {
|
|
|
313
412
|
next = insertBeforeClosingHead(next, ` ${siteConfigScript}`);
|
|
314
413
|
}
|
|
315
414
|
|
|
415
|
+
const sidebarHtmlToInject =
|
|
416
|
+
customSidebarHtml ||
|
|
417
|
+
config.sidebar?.slotHtml ||
|
|
418
|
+
(config.sidebar?.sections
|
|
419
|
+
? renderSidebarSectionsHtml(config.sidebar.sections)
|
|
420
|
+
: "");
|
|
421
|
+
|
|
422
|
+
if (sidebarHtmlToInject) {
|
|
423
|
+
let formattedSidebarHtml = sidebarHtmlToInject.trim();
|
|
424
|
+
if (
|
|
425
|
+
!/\bslot="sidebar(?:-nav|-content|-footer)?"/iu.test(formattedSidebarHtml)
|
|
426
|
+
) {
|
|
427
|
+
formattedSidebarHtml = `<div slot="sidebar" class="sidebar-custom-sections">\n${formattedSidebarHtml}\n</div>`;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const existingMatch = next.match(
|
|
431
|
+
/<[^>]+?\bslot="sidebar(?:-nav|-content|-footer)?"[^>]*>[\s\S]*?<\/[^>]+>/iu,
|
|
432
|
+
);
|
|
433
|
+
if (existingMatch) {
|
|
434
|
+
next = next.replace(existingMatch[0], "");
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
if (next.includes("</shadow-claw>")) {
|
|
438
|
+
next = next.replace(
|
|
439
|
+
"</shadow-claw>",
|
|
440
|
+
` ${formattedSidebarHtml}\n</shadow-claw>`,
|
|
441
|
+
);
|
|
442
|
+
} else if (next.includes("<shadow-claw></shadow-claw>")) {
|
|
443
|
+
next = next.replace(
|
|
444
|
+
"<shadow-claw></shadow-claw>",
|
|
445
|
+
`<shadow-claw>\n ${formattedSidebarHtml}\n</shadow-claw>`,
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (config.sidebar) {
|
|
451
|
+
next = applySidebarVisibilityToTemplate(next, config.sidebar);
|
|
452
|
+
}
|
|
453
|
+
|
|
316
454
|
return next;
|
|
317
455
|
}
|
|
318
456
|
|
|
@@ -993,10 +1131,39 @@ export async function applySiteConfig(
|
|
|
993
1131
|
|
|
994
1132
|
await copyCustomSiteFiles(config, distPublicDir, siteConfigPath);
|
|
995
1133
|
|
|
1134
|
+
const configDir = siteConfigPath
|
|
1135
|
+
? path.dirname(path.resolve(siteConfigPath))
|
|
1136
|
+
: process.cwd();
|
|
1137
|
+
const templateRootDir = getTemplateRootDir(configDir);
|
|
1138
|
+
|
|
1139
|
+
let sidebarHtml: string | undefined;
|
|
1140
|
+
if (config.sidebar?.slotHtml) {
|
|
1141
|
+
sidebarHtml = config.sidebar.slotHtml;
|
|
1142
|
+
} else if (config.sidebar?.sections) {
|
|
1143
|
+
sidebarHtml = renderSidebarSectionsHtml(config.sidebar.sections);
|
|
1144
|
+
} else {
|
|
1145
|
+
const sidebarCandidates = [
|
|
1146
|
+
config.sidebar?.slotPath,
|
|
1147
|
+
"pages/main/sidebar.html",
|
|
1148
|
+
"pages/sidebar.html",
|
|
1149
|
+
"sidebar.html",
|
|
1150
|
+
"resources/sidebar.html",
|
|
1151
|
+
].filter(Boolean) as string[];
|
|
1152
|
+
|
|
1153
|
+
const candidatePaths = sidebarCandidates.flatMap((c) =>
|
|
1154
|
+
getCandidateFilePaths(c, configDir, templateRootDir),
|
|
1155
|
+
);
|
|
1156
|
+
const foundSidebar = await findFirstExisting(candidatePaths);
|
|
1157
|
+
if (foundSidebar) {
|
|
1158
|
+
sidebarHtml = (await readText(foundSidebar)) ?? undefined;
|
|
1159
|
+
console.log(` Found slotted sidebar: ${foundSidebar}`);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
996
1163
|
const indexPath = path.join(distPublicDir, "index.html");
|
|
997
1164
|
const indexHtml = await readText(indexPath);
|
|
998
1165
|
if (indexHtml) {
|
|
999
|
-
const patched = patchIndexHtml(indexHtml, config);
|
|
1166
|
+
const patched = patchIndexHtml(indexHtml, config, sidebarHtml);
|
|
1000
1167
|
await writeText(indexPath, patched);
|
|
1001
1168
|
console.log(" Patched index.html");
|
|
1002
1169
|
}
|
|
@@ -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
|
}
|