shadow-claw 1.54.0 → 1.55.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 -1
- package/dist/cli/build/build.js +1 -1
- package/dist/cli/{chunk-DO2t9bUI.js → chunk--IuVyWfT.js} +24 -23
- package/dist/cli/{chunk-2ZYd9gYC.js → chunk--JpdI-Ht.js} +1 -1
- package/dist/cli/{chunk-m4Ineemy.js → chunk-4O8yrQuN.js} +1 -1
- package/dist/cli/{chunk-BiH9IXnQ.js → chunk-7S9Ywlfy.js} +1 -1
- package/dist/cli/{chunk-BmMOdYvk.js → chunk-B0SqqDSK.js} +1 -1
- package/dist/cli/chunk-BNaWaEm-.js +1 -0
- package/dist/cli/chunk-BXCsxO9e.js +1 -0
- package/dist/cli/chunk-Bq37qDoZ.js +18 -0
- package/dist/cli/{chunk-C1htf-nO.js → chunk-BrEeCKIo.js} +2 -2
- package/dist/cli/{chunk-BI1SOTM1.js → chunk-Bu3ylrhT.js} +8 -8
- package/dist/cli/{chunk-3smiGQoQ.js → chunk-C1v_s0Kb.js} +1 -1
- package/dist/cli/{chunk-DGeysxz3.js → chunk-C44G533y.js} +1 -1
- package/dist/cli/{chunk-9KiBalKu.js → chunk-C7hJLmsL.js} +1 -1
- package/dist/cli/{chunk-BFv9XSNd.js → chunk-CAaQWd6t.js} +1 -1
- package/dist/cli/chunk-CIkgn5Fh.js +1 -0
- package/dist/cli/chunk-CWEIN2kc.js +1 -0
- package/dist/cli/{chunk-BDeDZ-0L.js → chunk-CYg1lO1a.js} +1 -1
- package/dist/cli/{chunk-DXLmEQ3i.js → chunk-Ce09lwXT.js} +1 -1
- package/dist/cli/{chunk-XsfHeN4m.js → chunk-CpdqRSO-.js} +1 -1
- package/dist/cli/chunk-DB4x5L-B.js +1 -0
- package/dist/cli/{chunk-DaNyMqrk.js → chunk-DBvObsBQ.js} +1 -1
- package/dist/cli/chunk-DGPpt7Ka.js +1 -0
- package/dist/cli/chunk-DGagHluH.js +1 -0
- package/dist/cli/chunk-DUIs23D9.js +1 -0
- package/dist/cli/{chunk-CyvfQV16.js → chunk-DaurYOqg.js} +1 -1
- package/dist/cli/{chunk-DSFrcSyA.js → chunk-DfwRL0Ue.js} +1 -1
- package/dist/cli/{chunk-M2tZrzY5.js → chunk-DudYQk0p.js} +1 -1
- package/dist/cli/chunk-DvKo50Tp.js +2 -0
- package/dist/cli/{chunk-H_Mw5ypp.js → chunk-Dvrqte5Q.js} +2 -2
- package/dist/cli/{chunk-BtNO-m9T.js → chunk-DzhSExU0.js} +1 -1
- package/dist/cli/{chunk-IOMO88kZ.js → chunk-ENKlt3i9.js} +1 -1
- package/dist/cli/{chunk-Bspgzwsm.js → chunk-FWRwAX75.js} +8 -8
- package/dist/cli/chunk-Lf-Z-h48.js +32 -0
- package/dist/cli/{chunk-BucXnZ4Z.js → chunk-VRfkSLrD.js} +1 -1
- package/dist/cli/chunk-uaTxD024.js +1 -0
- package/dist/cli/cli.js +1 -1
- package/dist/cli/prerender/dsd-shell/prerender-dsd-shell.js +1 -1
- package/dist/headless-agent.js +2 -2
- package/dist/lib/components/index.js +25 -25
- 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/get-route.d.ts +3 -0
- package/dist/lib/components/shadow-claw/utils/sync-slotted-sidebar-active-links.d.ts +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/{configure-peer-js-D5jDCtLx.js → configure-peer-js-C9554Slv.js} +2 -2
- package/dist/lib/{configure-peer-js-D5jDCtLx.js.map → configure-peer-js-C9554Slv.js.map} +1 -1
- package/dist/lib/{file-viewer-B4CL4e0i.js → file-viewer-DBc5dxNy.js} +2 -2
- package/dist/lib/{file-viewer-B4CL4e0i.js.map → file-viewer-DBc5dxNy.js.map} +1 -1
- package/dist/lib/index.js +28 -27
- package/dist/lib/{init-control-plane-l2uFnhGV.js → init-control-plane-D-41Fm5q.js} +12 -12
- package/dist/lib/{init-control-plane-l2uFnhGV.js.map → init-control-plane-D-41Fm5q.js.map} +1 -1
- package/dist/lib/{markdown-0_p_zfxL.js → markdown-KnDWzWJJ.js} +2 -2
- package/dist/lib/{markdown-0_p_zfxL.js.map → markdown-KnDWzWJJ.js.map} +1 -1
- package/dist/lib/{orchestrator-D6wm8Sec.js → orchestrator-BEZcqgR5.js} +9 -9
- package/dist/lib/{orchestrator-D6wm8Sec.js.map → orchestrator-BEZcqgR5.js.map} +1 -1
- package/dist/lib/{orchestrator-Dh-hnIpK.js → orchestrator-Cda13e5U.js} +4 -4
- package/dist/lib/{orchestrator-Dh-hnIpK.js.map → orchestrator-Cda13e5U.js.map} +1 -1
- package/dist/lib/{peerjs-BWZnsD0B.js → peerjs-DYkUTcee.js} +5 -5
- package/dist/lib/{peerjs-BWZnsD0B.js.map → peerjs-DYkUTcee.js.map} +1 -1
- package/dist/lib/{push-client-MybDfOdi.js → push-client-CQtCFDaD.js} +3 -3
- package/dist/lib/{push-client-MybDfOdi.js.map → push-client-CQtCFDaD.js.map} +1 -1
- package/dist/lib/security/custom-element-security.d.ts +8 -4
- package/dist/lib/{shadow-claw-PdOpgTxH.js → shadow-claw-DYe9u6Tp.js} +142 -33
- package/dist/lib/shadow-claw-DYe9u6Tp.js.map +1 -0
- package/dist/lib/{shadow-claw-accounts-3bR76EOb.js → shadow-claw-accounts-D2URoHys.js} +2 -2
- package/dist/lib/{shadow-claw-accounts-3bR76EOb.js.map → shadow-claw-accounts-D2URoHys.js.map} +1 -1
- package/dist/lib/{shadow-claw-channel-config-ChdZ1iB8.js → shadow-claw-channel-config-buXoz2xv.js} +3 -3
- package/dist/lib/{shadow-claw-channel-config-ChdZ1iB8.js.map → shadow-claw-channel-config-buXoz2xv.js.map} +1 -1
- package/dist/lib/{shadow-claw-channels-CK9sc7h_.js → shadow-claw-channels-5yVJ1gLk.js} +3 -3
- package/dist/lib/{shadow-claw-channels-CK9sc7h_.js.map → shadow-claw-channels-5yVJ1gLk.js.map} +1 -1
- package/dist/lib/{shadow-claw-chat-B6uuZnJ7.js → shadow-claw-chat-CVc-7ycM.js} +7 -7
- package/dist/lib/{shadow-claw-chat-B6uuZnJ7.js.map → shadow-claw-chat-CVc-7ycM.js.map} +1 -1
- package/dist/lib/{shadow-claw-control-plane-BpRcl312.js → shadow-claw-control-plane-B5vsF91B.js} +6 -6
- package/dist/lib/{shadow-claw-control-plane-BpRcl312.js.map → shadow-claw-control-plane-B5vsF91B.js.map} +1 -1
- package/dist/lib/{shadow-claw-conversations-Dc_Xk2mB.js → shadow-claw-conversations-PGK5zqn3.js} +54 -12
- package/dist/lib/{shadow-claw-conversations-Dc_Xk2mB.js.map → shadow-claw-conversations-PGK5zqn3.js.map} +1 -1
- package/dist/lib/{shadow-claw-file-viewer-C4x1PtB2.js → shadow-claw-file-viewer-DSqn0hgx.js} +6 -6
- package/dist/lib/{shadow-claw-file-viewer-C4x1PtB2.js.map → shadow-claw-file-viewer-DSqn0hgx.js.map} +1 -1
- package/dist/lib/{shadow-claw-files-DhnHbXKf.js → shadow-claw-files-vOa9ZWbr.js} +6 -6
- package/dist/lib/{shadow-claw-files-DhnHbXKf.js.map → shadow-claw-files-vOa9ZWbr.js.map} +1 -1
- package/dist/lib/{shadow-claw-git-BeQ1ElUd.js → shadow-claw-git-D54Z85Bj.js} +4 -4
- package/dist/lib/{shadow-claw-git-BeQ1ElUd.js.map → shadow-claw-git-D54Z85Bj.js.map} +1 -1
- package/dist/lib/{shadow-claw-integrations-Bbdolk3w.js → shadow-claw-integrations-BTubMH9d.js} +2 -2
- package/dist/lib/{shadow-claw-integrations-Bbdolk3w.js.map → shadow-claw-integrations-BTubMH9d.js.map} +1 -1
- package/dist/lib/{shadow-claw-llm-DPda4L3C.js → shadow-claw-llm-8koGTNYs.js} +3 -3
- package/dist/lib/{shadow-claw-llm-DPda4L3C.js.map → shadow-claw-llm-8koGTNYs.js.map} +1 -1
- package/dist/lib/{shadow-claw-mcp-remote-Dn9c30WI.js → shadow-claw-mcp-remote-C2jwBsQt.js} +2 -2
- package/dist/lib/{shadow-claw-mcp-remote-Dn9c30WI.js.map → shadow-claw-mcp-remote-C2jwBsQt.js.map} +1 -1
- package/dist/lib/{shadow-claw-networking-zqNuyn3-.js → shadow-claw-networking-BV-rna16.js} +2 -2
- package/dist/lib/{shadow-claw-networking-zqNuyn3-.js.map → shadow-claw-networking-BV-rna16.js.map} +1 -1
- package/dist/lib/{shadow-claw-notifications-DFgdo33v.js → shadow-claw-notifications-Dku7VBLk.js} +2 -2
- package/dist/lib/{shadow-claw-notifications-DFgdo33v.js.map → shadow-claw-notifications-Dku7VBLk.js.map} +1 -1
- package/dist/lib/{shadow-claw-page-header-B7LFGQRf.js → shadow-claw-page-header-VPjYWfsT.js} +2 -2
- package/dist/lib/{shadow-claw-page-header-B7LFGQRf.js.map → shadow-claw-page-header-VPjYWfsT.js.map} +1 -1
- package/dist/lib/{shadow-claw-pages-DLspFqdK.js → shadow-claw-pages-DXrM6hgZ.js} +29 -19
- package/dist/lib/shadow-claw-pages-DXrM6hgZ.js.map +1 -0
- package/dist/lib/{shadow-claw-peerjs-D8xWwuWR.js → shadow-claw-peerjs-D3xonez5.js} +3 -3
- package/dist/lib/{shadow-claw-peerjs-D8xWwuWR.js.map → shadow-claw-peerjs-D3xonez5.js.map} +1 -1
- package/dist/lib/{shadow-claw-settings-NbvzXASD.js → shadow-claw-settings-DMTx6OS9.js} +5 -5
- package/dist/lib/{shadow-claw-settings-NbvzXASD.js.map → shadow-claw-settings-DMTx6OS9.js.map} +1 -1
- package/dist/lib/{shadow-claw-storage-B_NAoZmd.js → shadow-claw-storage-BJLnukxa.js} +3 -3
- package/dist/lib/{shadow-claw-storage-B_NAoZmd.js.map → shadow-claw-storage-BJLnukxa.js.map} +1 -1
- package/dist/lib/{shadow-claw-task-server-BaQJXhYJ.js → shadow-claw-task-server-DcMj20hD.js} +2 -2
- package/dist/lib/{shadow-claw-task-server-BaQJXhYJ.js.map → shadow-claw-task-server-DcMj20hD.js.map} +1 -1
- package/dist/lib/{shadow-claw-tasks-CAZua0-j.js → shadow-claw-tasks-BQBe4lVi.js} +7 -7
- package/dist/lib/{shadow-claw-tasks-CAZua0-j.js.map → shadow-claw-tasks-BQBe4lVi.js.map} +1 -1
- package/dist/lib/{shadow-claw-terminal-B2YJhkJL.js → shadow-claw-terminal-DPEzTxXv.js} +2 -2
- package/dist/lib/{shadow-claw-terminal-B2YJhkJL.js.map → shadow-claw-terminal-DPEzTxXv.js.map} +1 -1
- package/dist/lib/{shadow-claw-tools-CkZWxxTm.js → shadow-claw-tools-BCnU8FaK.js} +6 -6
- package/dist/lib/{shadow-claw-tools-CkZWxxTm.js.map → shadow-claw-tools-BCnU8FaK.js.map} +1 -1
- package/dist/lib/{shadow-claw-webvm-BL9cgrP9.js → shadow-claw-webvm-CnW-hoJ8.js} +2 -2
- package/dist/lib/{shadow-claw-webvm-BL9cgrP9.js.map → shadow-claw-webvm-CnW-hoJ8.js.map} +1 -1
- package/dist/lib/subsystems/mcp/webmcp.d.ts +15 -2
- package/dist/lib/{sync-web-mcp-registration-dW2MVCj4.js → sync-web-mcp-registration-DwpGjVdo.js} +10 -4
- package/dist/lib/sync-web-mcp-registration-DwpGjVdo.js.map +1 -0
- package/dist/lib/{tools-D7whby3H.js → tools-CP6G0HF7.js} +5 -6
- package/dist/lib/tools-CP6G0HF7.js.map +1 -0
- package/dist/lib/{trusted-types-d0cdkut_.js → trusted-types-0cu5Dm6M.js} +29 -4
- package/dist/lib/{trusted-types-d0cdkut_.js.map → trusted-types-0cu5Dm6M.js.map} +1 -1
- package/dist/lib/utils/index.d.ts +1 -0
- package/dist/lib/utils/index.js +4 -2
- package/dist/lib/utils/index.js.map +1 -1
- package/dist/lib/utils/resolve-page-script-dependencies.d.ts +19 -0
- package/dist/lib/utils/resolve-page-script-dependencies.js +98 -0
- package/dist/lib/utils/resolve-page-script-dependencies.js.map +1 -0
- package/dist/lib/utils/utils.js +1 -1
- package/dist/lib/webmcp-Bf9rT7uu.js +2001 -0
- package/dist/lib/webmcp-Bf9rT7uu.js.map +1 -0
- 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 +3 -3
- package/dist/public/README.md +1 -1
- package/dist/public/agent.worker.js +2 -2
- 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-conversations/shadow-claw-conversations.css +1 -1
- package/dist/public/components/shadow-claw-conversations/shadow-claw-conversations.html +1 -1
- package/dist/public/{configure-peer-js-WLRM7Qa7.js → configure-peer-js-OYl3V8sW.js} +1 -1
- package/dist/public/{custom-element-security-Cl991z-x.js → custom-element-security-BR4V40j4.js} +1 -1
- package/dist/public/docs/example/article/index.html +3 -3
- package/dist/public/docs/example/article.html +3 -3
- package/dist/public/docs/publishing/index.html +3 -3
- package/dist/public/docs/publishing.html +3 -3
- package/dist/public/docs/skill-creator/index.html +3 -3
- package/dist/public/docs/skill-creator.html +3 -3
- package/dist/public/docs/subsystems/custom-element-security.md +19 -5
- package/dist/public/docs/subsystems/pages.md +10 -2
- package/dist/public/docs/subsystems/tools.md +1 -2
- package/dist/public/docs/subsystems/webmcp.md +41 -6
- package/dist/public/{download-group-file-fFjoIIp4.js → download-group-file-BNmK8wac.js} +1 -1
- package/dist/public/e2e/README.md +2 -2
- package/dist/public/{e2e-bridge-CiSfBRT4.js → e2e-bridge-4phD1JUQ.js} +1 -1
- package/dist/public/{file-viewer-DFC3kfeO.js → file-viewer-Dbh3K9nL.js} +1 -1
- package/dist/public/index.html +3 -3
- package/dist/public/index.js +1 -1
- package/dist/public/{init-control-plane-BEbcwmmv.js → init-control-plane-DGOY_RNS.js} +1 -1
- package/dist/public/llms.txt +1 -1
- package/dist/public/main/index.html +3 -3
- package/dist/public/main/memory/index.html +3 -3
- package/dist/public/main/memory.html +3 -3
- package/dist/public/main.html +3 -3
- package/dist/public/{markdown-BeglYzw9.js → markdown-BPZYpfGm.js} +1 -1
- package/dist/public/{orchestrator-BlvEG3PO.js → orchestrator-OoUK7CF9.js} +1 -1
- package/dist/public/{orchestrator-DTNrntd4.js → orchestrator-a9047bGu.js} +1 -1
- package/dist/public/{peerjs-CnBdK94R.js → peerjs-Cbn310Tz.js} +1 -1
- package/dist/public/{push-client-DOHbdCyj.js → push-client-Dy4LGJy9.js} +1 -1
- package/dist/public/service-worker.js +1 -1
- package/dist/public/shadow-claw-B-HWC1uN.js +1180 -0
- package/dist/public/{shadow-claw-accounts-C6FXVw2K.js → shadow-claw-accounts-Di-anCZ1.js} +1 -1
- package/dist/public/{shadow-claw-channels-tr_r60Kq.js → shadow-claw-channels-RVwCE8pE.js} +1 -1
- package/dist/public/{shadow-claw-chat-BAAPhAOs.js → shadow-claw-chat-DI1q8UnX.js} +1 -1
- package/dist/public/{shadow-claw-control-plane-C_5VIx8E.js → shadow-claw-control-plane-KXEdLOGl.js} +2 -2
- package/dist/public/{shadow-claw-conversations-DGYZdDa3.js → shadow-claw-conversations-BCBGtS30.js} +40 -6
- package/dist/public/{shadow-claw-file-viewer-5j2-Z3fN.js → shadow-claw-file-viewer-CW3t6j-w.js} +1 -1
- package/dist/public/{shadow-claw-files-DKF4Yy0m.js → shadow-claw-files-JQ-o0ImX.js} +1 -1
- package/dist/public/{shadow-claw-git-CtUTJXKT.js → shadow-claw-git-D2M8VixW.js} +2 -2
- package/dist/public/{shadow-claw-integrations-CuBy9D3z.js → shadow-claw-integrations-Cgw6v9_1.js} +1 -1
- package/dist/public/{shadow-claw-llm-BIfNNjGL.js → shadow-claw-llm-74ieXp7i.js} +1 -1
- package/dist/public/{shadow-claw-mcp-remote-C17FXvrb.js → shadow-claw-mcp-remote-BX0BkSmy.js} +1 -1
- package/dist/public/{shadow-claw-networking-CjxQ1CLI.js → shadow-claw-networking-DNX8vaIQ.js} +1 -1
- package/dist/public/{shadow-claw-notifications-Brn2O3Ps.js → shadow-claw-notifications-BLTaGAny.js} +1 -1
- package/dist/public/{shadow-claw-page-header-Bn1P7Cxb.js → shadow-claw-page-header-CjFOdo9v.js} +1 -1
- package/dist/public/shadow-claw-pages-DOQqMm0_.js +645 -0
- package/dist/public/{shadow-claw-settings-CfDm0hVA.js → shadow-claw-settings-DFtl0Fy8.js} +2 -2
- package/dist/public/{shadow-claw-storage-DOOesRzw.js → shadow-claw-storage-gQGExZRq.js} +1 -1
- package/dist/public/{shadow-claw-task-server-H36iDDp2.js → shadow-claw-task-server-Ca45uY7S.js} +1 -1
- package/dist/public/{shadow-claw-tasks-4JsjSGkN.js → shadow-claw-tasks-CCTaaSdi.js} +1 -1
- package/dist/public/{shadow-claw-terminal-CTRTcYz-.js → shadow-claw-terminal-BfgulLkl.js} +1 -1
- package/dist/public/{shadow-claw-tools-Dm1LxNf4.js → shadow-claw-tools-V8NA4n18.js} +1 -1
- package/dist/public/{shadow-claw-webvm-JzuPe9Nr.js → shadow-claw-webvm-CxxI2bnC.js} +1 -1
- package/dist/public/sync-web-mcp-registration-CkCA8UFm.js +1 -0
- package/dist/public/{tools-FiTtOlIt.js → tools-CwQq5tJH.js} +2 -2
- package/dist/public/webmcp-CmtWOAFm.js +6 -0
- package/dist/server.js +2 -2
- package/package.json +3 -3
- package/src/cli/prerender/dsd-shell/prerender-dsd-shell.test.ts +16 -0
- package/src/cli/prerender/dsd-shell/prerender-dsd-shell.ts +62 -1
- package/src/cli/prerender/pretty-paths/prerender-pretty-paths.test.ts +277 -0
- package/src/cli/prerender/pretty-paths/prerender-pretty-paths.ts +28 -1
- package/src/cli/site-config/custom-elements/build-custom-element-script-tags.ts +13 -1
- package/src/components/shadow-claw/shadow-claw.css +12 -0
- package/src/components/shadow-claw/shadow-claw.html +12 -2
- package/src/components/shadow-claw/utils/bind-event-listeners.test.ts +18 -0
- package/src/components/shadow-claw/utils/bind-event-listeners.ts +14 -0
- package/src/components/shadow-claw/utils/get-route.test.ts +35 -0
- package/src/components/shadow-claw/utils/get-route.ts +18 -0
- package/src/components/shadow-claw/utils/sync-slotted-sidebar-active-links.test.ts +152 -1
- package/src/components/shadow-claw/utils/sync-slotted-sidebar-active-links.ts +139 -8
- package/src/components/shadow-claw-conversations/shadow-claw-conversations.css +11 -0
- package/src/components/shadow-claw-conversations/shadow-claw-conversations.html +27 -4
- package/src/components/shadow-claw-conversations/shadow-claw-conversations.ts +32 -4
- package/src/components/shadow-claw-pages/shadow-claw-pages-scripts.test.ts +266 -0
- package/src/components/shadow-claw-pages/shadow-claw-pages.ts +41 -17
- package/src/core/orchestrator/utils/sync-web-mcp-registration.test.ts +18 -1
- package/src/core/orchestrator/utils/sync-web-mcp-registration.ts +8 -0
- package/src/core/utils/init-control-plane.test.ts +9 -4
- package/src/security/custom-element-security.test.ts +65 -0
- package/src/security/custom-element-security.ts +67 -4
- package/src/stores/tools.test.ts +5 -3
- package/src/stores/tools.ts +5 -10
- package/src/subsystems/mcp/webmcp.test.ts +84 -13
- package/src/subsystems/mcp/webmcp.ts +73 -10
- package/src/utils/index.ts +1 -0
- package/src/utils/resolve-page-script-dependencies.test.ts +245 -0
- package/src/utils/resolve-page-script-dependencies.ts +198 -0
- package/dist/cli/chunk-B1hufJeO.js +0 -1
- package/dist/cli/chunk-BZpn8npn.js +0 -1
- package/dist/cli/chunk-Bw5aOTFr.js +0 -1
- package/dist/cli/chunk-C8nH01Gw.js +0 -32
- package/dist/cli/chunk-CK1ZoyoE.js +0 -17
- package/dist/cli/chunk-CVkhDr-7.js +0 -1
- package/dist/cli/chunk-Cum07Vlh.js +0 -1
- package/dist/cli/chunk-D3UhDDmV.js +0 -2
- package/dist/cli/chunk-D8GI6qj6.js +0 -1
- package/dist/cli/chunk-DEH-FvmP.js +0 -1
- package/dist/cli/chunk-DksvJ_kf.js +0 -1
- package/dist/cli/chunk-RGb9wM4R.js +0 -1
- package/dist/lib/shadow-claw-PdOpgTxH.js.map +0 -1
- package/dist/lib/shadow-claw-pages-DLspFqdK.js.map +0 -1
- package/dist/lib/sync-web-mcp-registration-dW2MVCj4.js.map +0 -1
- package/dist/lib/tools-D7whby3H.js.map +0 -1
- package/dist/lib/webmcp-CYTNZfkn.js +0 -1687
- package/dist/lib/webmcp-CYTNZfkn.js.map +0 -1
- package/dist/public/shadow-claw-CnNX-WCh.js +0 -1158
- package/dist/public/shadow-claw-pages-BwOOqRWW.js +0 -645
- package/dist/public/sync-web-mcp-registration-BnHVUjat.js +0 -1
- package/dist/public/webmcp-_TBqXlVW.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shadow-claw",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.55.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "AGPL-3.0",
|
|
6
6
|
"description": "ShadowClaw - multi-runtime AI assistant.",
|
|
@@ -144,8 +144,7 @@
|
|
|
144
144
|
"writer-rewriter-polyfills": "^1.0.1"
|
|
145
145
|
},
|
|
146
146
|
"devDependencies": {
|
|
147
|
-
"@mcp-b/webmcp-polyfill": "^
|
|
148
|
-
"@mcp-b/webmcp-types": "^5.1.0",
|
|
147
|
+
"@mcp-b/webmcp-polyfill": "^6.0.3",
|
|
149
148
|
"@playwright/test": "^1.64.0",
|
|
150
149
|
"@storybook/addon-docs": "^10.6.1",
|
|
151
150
|
"@storybook/web-components-vite": "^10.6.1",
|
|
@@ -192,6 +191,7 @@
|
|
|
192
191
|
"util": "^0.12.5",
|
|
193
192
|
"v86": "^0.5.470",
|
|
194
193
|
"vite": "^6.4.4",
|
|
194
|
+
"webmcp-types": "^0.1.10",
|
|
195
195
|
"workbox-cli": "^7.4.1",
|
|
196
196
|
"workbox-window": "^7.4.0"
|
|
197
197
|
},
|
|
@@ -139,6 +139,22 @@ describe("renderPageHtml frontmatter", () => {
|
|
|
139
139
|
expect(rendered).toContain("<h1>Heading</h1>");
|
|
140
140
|
expect(rendered).not.toContain('slug: "on-developing-loops"');
|
|
141
141
|
});
|
|
142
|
+
|
|
143
|
+
it("preserves custom element blocks containing blank lines without wrapping in <p> or splitting <pre>", async () => {
|
|
144
|
+
const markdown = [
|
|
145
|
+
'<x-postpress-code type="javascript"><pre>(async () => {',
|
|
146
|
+
" const a = 1;",
|
|
147
|
+
"",
|
|
148
|
+
" const b = 2;",
|
|
149
|
+
"})();</pre></x-postpress-code>",
|
|
150
|
+
].join("\n");
|
|
151
|
+
|
|
152
|
+
const rendered = await renderPageHtml(markdown, "page.md");
|
|
153
|
+
expect(rendered).not.toContain("<p><x-postpress-code");
|
|
154
|
+
expect(rendered).toContain(
|
|
155
|
+
'<x-postpress-code type="javascript"><pre>(async () => {\n const a = 1;\n\n const b = 2;\n})();</pre></x-postpress-code>',
|
|
156
|
+
);
|
|
157
|
+
});
|
|
142
158
|
});
|
|
143
159
|
|
|
144
160
|
describe("pages DSD prerender parity", () => {
|
|
@@ -15,6 +15,37 @@ import { DOMImplementation, XMLSerializer } from "@xmldom/xmldom";
|
|
|
15
15
|
import matter from "gray-matter";
|
|
16
16
|
import { marked } from "marked";
|
|
17
17
|
|
|
18
|
+
// Configure marked with a custom tokenizer for custom elements
|
|
19
|
+
marked.use({
|
|
20
|
+
tokenizer: {
|
|
21
|
+
html(src: string) {
|
|
22
|
+
// Treat custom elements (tags with a hyphen like <x-postpress-code>, <x-hook-component>)
|
|
23
|
+
// as block-level HTML so marked does not wrap them in <p> tags or split them on blank lines.
|
|
24
|
+
// Wrapping in <p> causes the browser's HTML parser to eject <pre> or other block children
|
|
25
|
+
// out of the custom element into sibling position, breaking web component light DOM slots.
|
|
26
|
+
const match =
|
|
27
|
+
src.match(
|
|
28
|
+
/^ {0,3}<([a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9_-]*)(?:\s+[^>]*)?>[\s\S]*?<\/\1>(?:[ \t]*(?:\n+|$))?/i,
|
|
29
|
+
) ||
|
|
30
|
+
src.match(
|
|
31
|
+
/^ {0,3}<([a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9_-]*)(?:\s+[^>]*)?\s*\/>(?:[ \t]*(?:\n+|$))?/i,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
if (match) {
|
|
35
|
+
return {
|
|
36
|
+
type: "html",
|
|
37
|
+
block: true,
|
|
38
|
+
raw: match[0],
|
|
39
|
+
text: match[0],
|
|
40
|
+
pre: false,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return false;
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
18
49
|
import {
|
|
19
50
|
createFrontmatterDetailsElement,
|
|
20
51
|
renderFrontmatterMarkup,
|
|
@@ -29,6 +60,8 @@ import { normalizePrerenderPagesOption } from "../utils/normalize-prerender-page
|
|
|
29
60
|
import { insertBeforeClosingHead } from "../utils/insert-before-closing-head.js";
|
|
30
61
|
import { injectStaticManifestScript } from "../utils/inject-static-manifest-script.js";
|
|
31
62
|
import { isPagePathAllowed } from "../../../utils/is-page-path-allowed.js";
|
|
63
|
+
import { resolvePageScriptDependencies } from "../../../utils/resolve-page-script-dependencies.js";
|
|
64
|
+
import { buildCustomElementScriptTags } from "../../site-config/custom-elements/build-custom-element-script-tags.js";
|
|
32
65
|
|
|
33
66
|
export { escapeHtml };
|
|
34
67
|
export { sanitizeRenderedHtml };
|
|
@@ -1316,7 +1349,35 @@ export async function prerenderDsdShell(
|
|
|
1316
1349
|
const embeddedManifestJson = JSON.stringify(embeddedManifest);
|
|
1317
1350
|
|
|
1318
1351
|
const nextHtml = injectStaticManifestScript(markedHtml, embeddedManifestJson);
|
|
1319
|
-
|
|
1352
|
+
|
|
1353
|
+
const rawScripts = siteConfig?.customElements?.scripts || [];
|
|
1354
|
+
const defaultPageParsed = filteredPageSources[0]?.content
|
|
1355
|
+
? splitFrontmatterWithGrayMatter(filteredPageSources[0].content)
|
|
1356
|
+
: { data: {} };
|
|
1357
|
+
const resolvedScripts = resolvePageScriptDependencies(
|
|
1358
|
+
rawScripts,
|
|
1359
|
+
defaultPageParsed.data,
|
|
1360
|
+
filteredPageSources[0]?.content,
|
|
1361
|
+
);
|
|
1362
|
+
let htmlWithScripts = nextHtml;
|
|
1363
|
+
if (resolvedScripts.length > 0) {
|
|
1364
|
+
const headMatch = htmlWithScripts.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
|
|
1365
|
+
const headContent = headMatch ? headMatch[1] : "";
|
|
1366
|
+
const scriptsToInject = resolvedScripts.filter(
|
|
1367
|
+
(s) =>
|
|
1368
|
+
!headContent.includes(`src="${s.src}"`) &&
|
|
1369
|
+
!headContent.includes(`src='${s.src}'`),
|
|
1370
|
+
);
|
|
1371
|
+
if (scriptsToInject.length > 0) {
|
|
1372
|
+
const scriptTags = buildCustomElementScriptTags(scriptsToInject);
|
|
1373
|
+
htmlWithScripts = insertBeforeClosingHead(
|
|
1374
|
+
htmlWithScripts,
|
|
1375
|
+
` ${scriptTags.trim()}`,
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
const minifiedHtml = minifyDsdTemplateHtml(htmlWithScripts);
|
|
1320
1381
|
const finalHtml = await inlineCriticalAssets(minifiedHtml, publicDir);
|
|
1321
1382
|
await writeFile(indexPath, finalHtml, "utf8");
|
|
1322
1383
|
const isSilent = options.silent ?? process.env.NODE_ENV === "test";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { jest } from "@jest/globals";
|
|
1
2
|
import {
|
|
2
3
|
injectStaticRoutingScript,
|
|
3
4
|
prerenderPrettyPaths,
|
|
@@ -958,4 +959,280 @@ Body content paragraph for auto description.`;
|
|
|
958
959
|
'<link rel="canonical" href="https://xt-ml.github.io/shadow-claw/custom-url/" />',
|
|
959
960
|
);
|
|
960
961
|
});
|
|
962
|
+
|
|
963
|
+
it("injects global scripts and page frontmatter script dependencies into head of pretty path pages", async () => {
|
|
964
|
+
const publicDir = path.join(tmpDir, "dist/public-deps");
|
|
965
|
+
const indexPath = path.join(publicDir, "index.html");
|
|
966
|
+
const sourcePath = path.join(tmpDir, "pages/main-deps");
|
|
967
|
+
const routesPath = path.join(tmpDir, "pages/routes-deps.json");
|
|
968
|
+
const siteConfigPath = path.join(tmpDir, "shadow-claw.config.json");
|
|
969
|
+
|
|
970
|
+
await mkdir(path.join(publicDir, "components/shadow-claw"), {
|
|
971
|
+
recursive: true,
|
|
972
|
+
});
|
|
973
|
+
await mkdir(path.join(publicDir, "components/shadow-claw-pages"), {
|
|
974
|
+
recursive: true,
|
|
975
|
+
});
|
|
976
|
+
await mkdir(path.join(publicDir, "components/shadow-claw-page-header"), {
|
|
977
|
+
recursive: true,
|
|
978
|
+
});
|
|
979
|
+
await mkdir(sourcePath, { recursive: true });
|
|
980
|
+
await mkdir(path.dirname(routesPath), { recursive: true });
|
|
981
|
+
|
|
982
|
+
await writeFile(
|
|
983
|
+
indexPath,
|
|
984
|
+
'<!doctype html><html><head><base href="/"><title>ShadowClaw</title></head><body><shadow-claw></shadow-claw></body></html>',
|
|
985
|
+
"utf8",
|
|
986
|
+
);
|
|
987
|
+
await writeFile(
|
|
988
|
+
path.join(publicDir, "components/shadow-claw/shadow-claw.html"),
|
|
989
|
+
'<template><div class="app"><shadow-claw-pages></shadow-claw-pages></div></template>',
|
|
990
|
+
"utf8",
|
|
991
|
+
);
|
|
992
|
+
await writeFile(
|
|
993
|
+
path.join(
|
|
994
|
+
publicDir,
|
|
995
|
+
"components/shadow-claw-pages/shadow-claw-pages.html",
|
|
996
|
+
),
|
|
997
|
+
'<template><div class="pages__list" data-pages-list role="list"></div><div class="pages__rendered" data-pages-rendered hidden></div><div class="pages__empty" data-pages-empty></div><shadow-claw-page-header title="Pages"></shadow-claw-page-header></template>',
|
|
998
|
+
"utf8",
|
|
999
|
+
);
|
|
1000
|
+
await writeFile(
|
|
1001
|
+
path.join(
|
|
1002
|
+
publicDir,
|
|
1003
|
+
"components/shadow-claw-page-header/shadow-claw-page-header.html",
|
|
1004
|
+
),
|
|
1005
|
+
'<template><header class="header"><h2 class="header__title"></h2><details class="header__actions-disclosure"></details><div class="header__actions" id="header-actions-panel"></div></header></template>',
|
|
1006
|
+
"utf8",
|
|
1007
|
+
);
|
|
1008
|
+
|
|
1009
|
+
const siteConfigJson = {
|
|
1010
|
+
site: { title: "ShadowClaw" },
|
|
1011
|
+
customElements: {
|
|
1012
|
+
scripts: [
|
|
1013
|
+
{
|
|
1014
|
+
id: "feed-scroller",
|
|
1015
|
+
src: "/pages/main/assets/feed-scroller.js",
|
|
1016
|
+
global: true,
|
|
1017
|
+
hasInit: true,
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
id: "x-hook-component",
|
|
1021
|
+
src: "/pages/main/assets/x-hook-component.js",
|
|
1022
|
+
hasInit: true,
|
|
1023
|
+
},
|
|
1024
|
+
{
|
|
1025
|
+
name: "x-postpress-code",
|
|
1026
|
+
src: "/pages/main/assets/x-postpress-code.js",
|
|
1027
|
+
hasInit: true,
|
|
1028
|
+
},
|
|
1029
|
+
],
|
|
1030
|
+
},
|
|
1031
|
+
};
|
|
1032
|
+
await writeFile(
|
|
1033
|
+
siteConfigPath,
|
|
1034
|
+
JSON.stringify(siteConfigJson, null, 2),
|
|
1035
|
+
"utf8",
|
|
1036
|
+
);
|
|
1037
|
+
|
|
1038
|
+
const page1Content = [
|
|
1039
|
+
"---",
|
|
1040
|
+
'title: "The Web Is Dynamic"',
|
|
1041
|
+
'slug: "the-web-is-dynamic"',
|
|
1042
|
+
"dependencies:",
|
|
1043
|
+
' - "x-hook-component"',
|
|
1044
|
+
"---",
|
|
1045
|
+
"# The Web Is Dynamic",
|
|
1046
|
+
"",
|
|
1047
|
+
"Content using hook component.",
|
|
1048
|
+
'<script type="module" src="/pages/main/assets/x-hook-component.js"></script>',
|
|
1049
|
+
].join("\n");
|
|
1050
|
+
|
|
1051
|
+
const page2Content = [
|
|
1052
|
+
"---",
|
|
1053
|
+
'title: "Unknown Script Page"',
|
|
1054
|
+
'slug: "unknown-script-page"',
|
|
1055
|
+
"dependencies:",
|
|
1056
|
+
' - "missing-non-existent-script"',
|
|
1057
|
+
"---",
|
|
1058
|
+
"# Unknown Script Page",
|
|
1059
|
+
"",
|
|
1060
|
+
"Content with unresolvable script.",
|
|
1061
|
+
].join("\n");
|
|
1062
|
+
|
|
1063
|
+
await writeFile(
|
|
1064
|
+
path.join(sourcePath, "2021-02-27-the-web-is-dynamic.md"),
|
|
1065
|
+
page1Content,
|
|
1066
|
+
"utf8",
|
|
1067
|
+
);
|
|
1068
|
+
await writeFile(path.join(sourcePath, "unknown.md"), page2Content, "utf8");
|
|
1069
|
+
|
|
1070
|
+
const routesJson = {
|
|
1071
|
+
routes: {
|
|
1072
|
+
"/pages/main-deps/2021-02-27-the-web-is-dynamic.md": {
|
|
1073
|
+
prettyPath: "/2021/02/27/the-web-is-dynamic/",
|
|
1074
|
+
},
|
|
1075
|
+
"/pages/main-deps/unknown.md": {
|
|
1076
|
+
prettyPath: "/unknown-page/",
|
|
1077
|
+
},
|
|
1078
|
+
},
|
|
1079
|
+
};
|
|
1080
|
+
await writeFile(routesPath, JSON.stringify(routesJson, null, 2), "utf8");
|
|
1081
|
+
|
|
1082
|
+
const result = await prerenderPrettyPaths({
|
|
1083
|
+
publicDir,
|
|
1084
|
+
routesPath,
|
|
1085
|
+
sourcePath,
|
|
1086
|
+
siteConfigPath,
|
|
1087
|
+
indexPath,
|
|
1088
|
+
prerenderPages: 1,
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
expect(result.count).toBe(2);
|
|
1092
|
+
|
|
1093
|
+
const page1Html = await readFile(
|
|
1094
|
+
path.join(publicDir, "2021/02/27/the-web-is-dynamic/index.html"),
|
|
1095
|
+
"utf8",
|
|
1096
|
+
);
|
|
1097
|
+
|
|
1098
|
+
// Should contain both the global script and the frontmatter-requested dependency in <head>
|
|
1099
|
+
expect(page1Html).toMatch(
|
|
1100
|
+
/<head>[\s\S]*<script type="module" src="\/pages\/main\/assets\/feed-scroller\.js"><\/script>[\s\S]*<\/head>/,
|
|
1101
|
+
);
|
|
1102
|
+
expect(page1Html).toMatch(
|
|
1103
|
+
/<head>[\s\S]*<script type="module" src="\/pages\/main\/assets\/x-hook-component\.js"><\/script>[\s\S]*<\/head>/,
|
|
1104
|
+
);
|
|
1105
|
+
// Should NOT contain the unrequested x-postpress-code
|
|
1106
|
+
expect(page1Html).not.toContain("/pages/main/assets/x-postpress-code.js");
|
|
1107
|
+
|
|
1108
|
+
const page2Html = await readFile(
|
|
1109
|
+
path.join(publicDir, "unknown-page/index.html"),
|
|
1110
|
+
"utf8",
|
|
1111
|
+
);
|
|
1112
|
+
// Should still have the global script and render cleanly despite missing dependency
|
|
1113
|
+
expect(page2Html).toMatch(
|
|
1114
|
+
/<head>[\s\S]*<script type="module" src="\/pages\/main\/assets\/feed-scroller\.js"><\/script>[\s\S]*<\/head>/,
|
|
1115
|
+
);
|
|
1116
|
+
expect(page2Html).not.toMatch(/<script\b[^>]*missing-non-existent-script/);
|
|
1117
|
+
});
|
|
1118
|
+
|
|
1119
|
+
it("injects dependencies when existing config does not specify an id and fails gracefully", async () => {
|
|
1120
|
+
const publicDir = path.join(tmpDir, "dist/public");
|
|
1121
|
+
const indexPath = path.join(publicDir, "index.html");
|
|
1122
|
+
const sourcePath = path.join(tmpDir, "pages/main-legacy");
|
|
1123
|
+
const routesPath = path.join(tmpDir, "pages/routes-legacy.json");
|
|
1124
|
+
const siteConfigPath = path.join(tmpDir, "shadow-claw.config.json");
|
|
1125
|
+
|
|
1126
|
+
await mkdir(path.join(publicDir, "components/shadow-claw"), {
|
|
1127
|
+
recursive: true,
|
|
1128
|
+
});
|
|
1129
|
+
await mkdir(path.join(publicDir, "components/shadow-claw-pages"), {
|
|
1130
|
+
recursive: true,
|
|
1131
|
+
});
|
|
1132
|
+
await mkdir(path.join(publicDir, "components/shadow-claw-page-header"), {
|
|
1133
|
+
recursive: true,
|
|
1134
|
+
});
|
|
1135
|
+
await mkdir(sourcePath, { recursive: true });
|
|
1136
|
+
|
|
1137
|
+
await mkdir(path.dirname(routesPath), { recursive: true });
|
|
1138
|
+
|
|
1139
|
+
await writeFile(
|
|
1140
|
+
indexPath,
|
|
1141
|
+
'<!doctype html><html><head><base href="/"><title>Legacy Config Site</title></head><body><shadow-claw></shadow-claw></body></html>',
|
|
1142
|
+
"utf8",
|
|
1143
|
+
);
|
|
1144
|
+
await writeFile(
|
|
1145
|
+
path.join(publicDir, "components/shadow-claw/shadow-claw.html"),
|
|
1146
|
+
'<template><div class="app"><shadow-claw-pages></shadow-claw-pages></div></template>',
|
|
1147
|
+
"utf8",
|
|
1148
|
+
);
|
|
1149
|
+
await writeFile(
|
|
1150
|
+
path.join(
|
|
1151
|
+
publicDir,
|
|
1152
|
+
"components/shadow-claw-pages/shadow-claw-pages.html",
|
|
1153
|
+
),
|
|
1154
|
+
'<template><div class="pages__list" data-pages-list role="list"></div><div class="pages__rendered" data-pages-rendered hidden></div><div class="pages__empty" data-pages-empty></div><shadow-claw-page-header title="Pages"></shadow-claw-page-header></template>',
|
|
1155
|
+
"utf8",
|
|
1156
|
+
);
|
|
1157
|
+
await writeFile(
|
|
1158
|
+
path.join(
|
|
1159
|
+
publicDir,
|
|
1160
|
+
"components/shadow-claw-page-header/shadow-claw-page-header.html",
|
|
1161
|
+
),
|
|
1162
|
+
'<template><header class="header"><h2 class="header__title"></h2><details class="header__actions-disclosure"></details><div class="header__actions" id="header-actions-panel"></div></header></template>',
|
|
1163
|
+
"utf8",
|
|
1164
|
+
);
|
|
1165
|
+
|
|
1166
|
+
// Existing legacy config without 'id' fields
|
|
1167
|
+
const legacySiteConfig = {
|
|
1168
|
+
site: { title: "Legacy Config Site" },
|
|
1169
|
+
customElements: {
|
|
1170
|
+
scripts: [
|
|
1171
|
+
{ src: "/pages/main/assets/feed-scroller.js", global: true },
|
|
1172
|
+
{ src: "/pages/main/assets/x-hook-component.js" },
|
|
1173
|
+
],
|
|
1174
|
+
},
|
|
1175
|
+
};
|
|
1176
|
+
await writeFile(
|
|
1177
|
+
siteConfigPath,
|
|
1178
|
+
JSON.stringify(legacySiteConfig, null, 2),
|
|
1179
|
+
"utf8",
|
|
1180
|
+
);
|
|
1181
|
+
|
|
1182
|
+
const postContent = [
|
|
1183
|
+
"---",
|
|
1184
|
+
'title: "Legacy Config Page"',
|
|
1185
|
+
"dependencies:",
|
|
1186
|
+
' - "x-hook-component"',
|
|
1187
|
+
' - "unrecognized-missing-id"',
|
|
1188
|
+
"---",
|
|
1189
|
+
"# Legacy Config Page",
|
|
1190
|
+
"",
|
|
1191
|
+
"Content rendered best effort.",
|
|
1192
|
+
].join("\n");
|
|
1193
|
+
|
|
1194
|
+
await writeFile(
|
|
1195
|
+
path.join(sourcePath, "legacy-page.md"),
|
|
1196
|
+
postContent,
|
|
1197
|
+
"utf8",
|
|
1198
|
+
);
|
|
1199
|
+
|
|
1200
|
+
const routesJson = {
|
|
1201
|
+
routes: {
|
|
1202
|
+
"/pages/main-legacy/legacy-page.md": {
|
|
1203
|
+
prettyPath: "/legacy-page/",
|
|
1204
|
+
},
|
|
1205
|
+
},
|
|
1206
|
+
};
|
|
1207
|
+
await writeFile(routesPath, JSON.stringify(routesJson, null, 2), "utf8");
|
|
1208
|
+
|
|
1209
|
+
const warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
|
|
1210
|
+
const result = await prerenderPrettyPaths({
|
|
1211
|
+
publicDir,
|
|
1212
|
+
routesPath,
|
|
1213
|
+
sourcePath,
|
|
1214
|
+
siteConfigPath,
|
|
1215
|
+
indexPath,
|
|
1216
|
+
prerenderPages: 1,
|
|
1217
|
+
});
|
|
1218
|
+
warnSpy.mockRestore();
|
|
1219
|
+
|
|
1220
|
+
expect(result.count).toBe(1);
|
|
1221
|
+
|
|
1222
|
+
const pageHtml = await readFile(
|
|
1223
|
+
path.join(publicDir, "legacy-page/index.html"),
|
|
1224
|
+
"utf8",
|
|
1225
|
+
);
|
|
1226
|
+
|
|
1227
|
+
// Global script injected
|
|
1228
|
+
expect(pageHtml).toMatch(
|
|
1229
|
+
/<head>[\s\S]*<script type="module" src="\/pages\/main\/assets\/feed-scroller\.js"><\/script>[\s\S]*<\/head>/,
|
|
1230
|
+
);
|
|
1231
|
+
// Matched by stem even without id in config
|
|
1232
|
+
expect(pageHtml).toMatch(
|
|
1233
|
+
/<head>[\s\S]*<script type="module" src="\/pages\/main\/assets\/x-hook-component\.js"><\/script>[\s\S]*<\/head>/,
|
|
1234
|
+
);
|
|
1235
|
+
// Unrecognized id has no script tag injected and does not cause a failure
|
|
1236
|
+
expect(pageHtml).not.toMatch(/<script\b[^>]*unrecognized-missing-id/);
|
|
1237
|
+
});
|
|
961
1238
|
});
|
|
@@ -32,6 +32,8 @@ import { injectStaticRoutingScript } from "../utils/inject-static-routing-script
|
|
|
32
32
|
import { insertBeforeClosingHead } from "../utils/insert-before-closing-head.js";
|
|
33
33
|
import { trimSlashes } from "../../../utils/normalize-workspace-path.js";
|
|
34
34
|
import { isPagePathAllowed } from "../../../utils/is-page-path-allowed.js";
|
|
35
|
+
import { resolvePageScriptDependencies } from "../../../utils/resolve-page-script-dependencies.js";
|
|
36
|
+
import { buildCustomElementScriptTags } from "../../site-config/custom-elements/build-custom-element-script-tags.js";
|
|
35
37
|
import {
|
|
36
38
|
extractMarkdownDescription,
|
|
37
39
|
formatSeoTitle,
|
|
@@ -544,8 +546,33 @@ export async function prerenderPrettyPaths(
|
|
|
544
546
|
type: isHome ? "website" : "article",
|
|
545
547
|
});
|
|
546
548
|
|
|
549
|
+
const rawScripts = siteConfig?.customElements?.scripts || [];
|
|
550
|
+
const resolvedScripts = resolvePageScriptDependencies(
|
|
551
|
+
rawScripts,
|
|
552
|
+
parsed.data,
|
|
553
|
+
matchedPage.content,
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
let htmlWithScripts = htmlWithSeo;
|
|
557
|
+
if (resolvedScripts.length > 0) {
|
|
558
|
+
const headMatch = htmlWithScripts.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
|
|
559
|
+
const headContent = headMatch ? headMatch[1] : "";
|
|
560
|
+
const scriptsToInject = resolvedScripts.filter(
|
|
561
|
+
(s) =>
|
|
562
|
+
!headContent.includes(`src="${s.src}"`) &&
|
|
563
|
+
!headContent.includes(`src='${s.src}'`),
|
|
564
|
+
);
|
|
565
|
+
if (scriptsToInject.length > 0) {
|
|
566
|
+
const scriptTags = buildCustomElementScriptTags(scriptsToInject);
|
|
567
|
+
htmlWithScripts = insertBeforeClosingHead(
|
|
568
|
+
htmlWithScripts,
|
|
569
|
+
` ${scriptTags.trim()}`,
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
547
574
|
const minifiedHtml = minifyDsdTemplateHtml(
|
|
548
|
-
injectStaticRoutingScript(
|
|
575
|
+
injectStaticRoutingScript(htmlWithScripts, embeddedRoutingJson),
|
|
549
576
|
);
|
|
550
577
|
const finalHtml = await inlineCriticalAssets(minifiedHtml, publicDir);
|
|
551
578
|
|
|
@@ -2,6 +2,10 @@ import { normalizeCustomElementScriptSrc } from "./normalize-custom-element-scri
|
|
|
2
2
|
|
|
3
3
|
export interface CustomElementScriptDescriptor {
|
|
4
4
|
src: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
global?: boolean;
|
|
8
|
+
autoload?: boolean;
|
|
5
9
|
type?: string;
|
|
6
10
|
async?: boolean;
|
|
7
11
|
defer?: boolean;
|
|
@@ -10,9 +14,17 @@ export interface CustomElementScriptDescriptor {
|
|
|
10
14
|
|
|
11
15
|
export type CustomElementScriptEntry = string | CustomElementScriptDescriptor;
|
|
12
16
|
|
|
17
|
+
function defaultEscapeHtml(str: string): string {
|
|
18
|
+
return str
|
|
19
|
+
.replace(/&/g, "&")
|
|
20
|
+
.replace(/"/g, """)
|
|
21
|
+
.replace(/</g, "<")
|
|
22
|
+
.replace(/>/g, ">");
|
|
23
|
+
}
|
|
24
|
+
|
|
13
25
|
export function buildCustomElementScriptTags(
|
|
14
26
|
approvedEntries: CustomElementScriptEntry[] | any,
|
|
15
|
-
escapeHtml: (str: string) => string,
|
|
27
|
+
escapeHtml: (str: string) => string = defaultEscapeHtml,
|
|
16
28
|
): string {
|
|
17
29
|
if (!Array.isArray(approvedEntries) || approvedEntries.length === 0) {
|
|
18
30
|
return "";
|
|
@@ -632,6 +632,18 @@ shadow-claw-conversations {
|
|
|
632
632
|
margin-top: 0.5rem;
|
|
633
633
|
}
|
|
634
634
|
|
|
635
|
+
form:tool-form-active,
|
|
636
|
+
.app-confirm-dialog__form:tool-form-active,
|
|
637
|
+
.app-prompt-dialog__form:tool-form-active {
|
|
638
|
+
outline: 2px dashed var(--shadow-claw-accent-primary, #3b82f6);
|
|
639
|
+
outline-offset: 4px;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
button:tool-submit-active {
|
|
643
|
+
outline: 2px dashed var(--shadow-claw-warning, #f59e0b);
|
|
644
|
+
outline-offset: 2px;
|
|
645
|
+
}
|
|
646
|
+
|
|
635
647
|
.chat-page {
|
|
636
648
|
flex-direction: column;
|
|
637
649
|
}
|
|
@@ -254,7 +254,12 @@
|
|
|
254
254
|
dialog-class="app-dialog"
|
|
255
255
|
dialog-aria-labelledby="appDialogTitle"
|
|
256
256
|
>
|
|
257
|
-
<form
|
|
257
|
+
<form
|
|
258
|
+
method="dialog"
|
|
259
|
+
class="app-confirm-dialog__form"
|
|
260
|
+
toolname="app_dialog_confirm"
|
|
261
|
+
tooldescription="Confirm or cancel an application modal dialog prompt"
|
|
262
|
+
>
|
|
258
263
|
<h2 id="appDialogTitle" class="app-dialog__title">Confirm</h2>
|
|
259
264
|
<p class="app-dialog__message"></p>
|
|
260
265
|
<ul class="app-dialog__details" hidden></ul>
|
|
@@ -289,7 +294,12 @@
|
|
|
289
294
|
dialog-class="app-dialog app-prompt-dialog"
|
|
290
295
|
dialog-aria-labelledby="appPromptTitle"
|
|
291
296
|
>
|
|
292
|
-
<form
|
|
297
|
+
<form
|
|
298
|
+
method="dialog"
|
|
299
|
+
class="app-prompt-dialog__form"
|
|
300
|
+
toolname="app_dialog_prompt"
|
|
301
|
+
tooldescription="Submit user response or selection to an interactive dialog prompt"
|
|
302
|
+
>
|
|
293
303
|
<h2 id="appPromptTitle" class="app-prompt-dialog__title">
|
|
294
304
|
Agent Question
|
|
295
305
|
</h2>
|
|
@@ -778,6 +778,24 @@ describe("bindEventListeners", () => {
|
|
|
778
778
|
"popstate",
|
|
779
779
|
expect.any(Function),
|
|
780
780
|
);
|
|
781
|
+
|
|
782
|
+
// Verify win.history.replaceState was hooked
|
|
783
|
+
const origReplace = jest.fn();
|
|
784
|
+
(win as any).history = { replaceState: origReplace };
|
|
785
|
+
(win as any).history.__scReplaceStateTracked = false;
|
|
786
|
+
bindEventListeners(
|
|
787
|
+
win,
|
|
788
|
+
doc,
|
|
789
|
+
shadow,
|
|
790
|
+
shadowClaw,
|
|
791
|
+
db,
|
|
792
|
+
oStore,
|
|
793
|
+
fStore,
|
|
794
|
+
tStore,
|
|
795
|
+
url,
|
|
796
|
+
);
|
|
797
|
+
(win as any).history.replaceState({ inFeedScroll: true }, "", "/");
|
|
798
|
+
expect(origReplace).toHaveBeenCalledWith({ inFeedScroll: true }, "", "/");
|
|
781
799
|
});
|
|
782
800
|
|
|
783
801
|
it("should attach popstate and click listeners when navigation API not supported", () => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Themes } from "../../../stores/theme.js";
|
|
2
2
|
import { applyRouteFromCurrentLocation } from "./apply-route-from-current-location.js";
|
|
3
|
+
import { recordHistoryReplaceState } from "./get-route.js";
|
|
3
4
|
import { getDefaultSidebarPage } from "./get-default-sidebar-page.js";
|
|
4
5
|
import { initSidebarResize } from "./init-sidebar-resize.js";
|
|
5
6
|
import { requestDialog } from "./request-dialog.js";
|
|
@@ -269,6 +270,19 @@ export function bindEventListeners(
|
|
|
269
270
|
doc.addEventListener("shadow-claw-navigate", shadowClaw.shadowClawNav);
|
|
270
271
|
|
|
271
272
|
if (supportsNavigationApi()) {
|
|
273
|
+
if (win.history && !(win.history as any).__scReplaceStateTracked) {
|
|
274
|
+
const origReplaceState = win.history.replaceState;
|
|
275
|
+
win.history.replaceState = function (
|
|
276
|
+
data: any,
|
|
277
|
+
unused: string,
|
|
278
|
+
url?: string | URL | null,
|
|
279
|
+
) {
|
|
280
|
+
recordHistoryReplaceState(data);
|
|
281
|
+
return origReplaceState.call(this, data, unused, url);
|
|
282
|
+
};
|
|
283
|
+
(win.history as any).__scReplaceStateTracked = true;
|
|
284
|
+
}
|
|
285
|
+
|
|
272
286
|
const nav = (win as any).navigation;
|
|
273
287
|
nav.addEventListener("navigate", shadowClaw.handleNavigationApiNavigate);
|
|
274
288
|
|
|
@@ -126,6 +126,41 @@ describe("getRoute", () => {
|
|
|
126
126
|
}
|
|
127
127
|
});
|
|
128
128
|
|
|
129
|
+
it("returns undefined if navigateEvent.info indicates an in-feed scroll", () => {
|
|
130
|
+
const navigateEvent = new Event("navigate") as any;
|
|
131
|
+
navigateEvent.navigationType = "replace";
|
|
132
|
+
navigateEvent.info = { inFeedScroll: true };
|
|
133
|
+
navigateEvent.destination = {
|
|
134
|
+
url: `${window.location.origin}/test`,
|
|
135
|
+
getState: () => undefined,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const result = getRoute(db, navigateEvent);
|
|
139
|
+
expect(result).toBeUndefined();
|
|
140
|
+
expect(isPossibleAppRouteMock).not.toHaveBeenCalled();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("returns undefined if recorded history replaceState indicates inFeedScroll even when getState() is undefined and history.state is null", async () => {
|
|
144
|
+
const { recordHistoryReplaceState, clearLastHistoryReplaceState } =
|
|
145
|
+
await import("./get-route.js");
|
|
146
|
+
recordHistoryReplaceState({ inFeedScroll: true });
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
const navigateEvent = new Event("navigate") as any;
|
|
150
|
+
navigateEvent.navigationType = "replace";
|
|
151
|
+
navigateEvent.destination = {
|
|
152
|
+
url: `${window.location.origin}/test`,
|
|
153
|
+
getState: () => undefined,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const result = getRoute(db, navigateEvent);
|
|
157
|
+
expect(result).toBeUndefined();
|
|
158
|
+
expect(isPossibleAppRouteMock).not.toHaveBeenCalled();
|
|
159
|
+
} finally {
|
|
160
|
+
clearLastHistoryReplaceState();
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
129
164
|
it("does not ignore push navigation even if window.history.state has inFeedScroll: true", () => {
|
|
130
165
|
const origState = window.history.state;
|
|
131
166
|
try {
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { isPossibleAppRoute } from "../../../core/app-routes.js";
|
|
2
2
|
import type { ShadowClawDatabase } from "../../../db/types.js";
|
|
3
3
|
|
|
4
|
+
let lastHistoryReplaceState: any = null;
|
|
5
|
+
|
|
6
|
+
export function recordHistoryReplaceState(state: any): void {
|
|
7
|
+
lastHistoryReplaceState = state;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getLastHistoryReplaceState(): any {
|
|
11
|
+
return lastHistoryReplaceState;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function clearLastHistoryReplaceState(): void {
|
|
15
|
+
lastHistoryReplaceState = null;
|
|
16
|
+
}
|
|
17
|
+
|
|
4
18
|
export function getRoute(db: ShadowClawDatabase, ev: Event) {
|
|
5
19
|
if (!db) {
|
|
6
20
|
return;
|
|
@@ -15,8 +29,12 @@ export function getRoute(db: ShadowClawDatabase, ev: Event) {
|
|
|
15
29
|
typeof navigateEvent?.destination?.getState === "function"
|
|
16
30
|
? navigateEvent.destination.getState()
|
|
17
31
|
: null;
|
|
32
|
+
const recordedState =
|
|
33
|
+
navigateEvent.navigationType === "replace" ? lastHistoryReplaceState : null;
|
|
18
34
|
const navState =
|
|
19
35
|
destinationState ||
|
|
36
|
+
navigateEvent?.info ||
|
|
37
|
+
recordedState ||
|
|
20
38
|
(navigateEvent.navigationType === "replace" &&
|
|
21
39
|
typeof history !== "undefined"
|
|
22
40
|
? history.state
|