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.
Files changed (286) hide show
  1. package/.well-known/mcp/server-card.json +1 -1
  2. package/.well-known/mcp.json +1 -1
  3. package/README.md +1 -1
  4. package/dist/cli/build/build.js +1 -1
  5. package/dist/cli/{chunk-DO2t9bUI.js → chunk--IuVyWfT.js} +24 -23
  6. package/dist/cli/{chunk-2ZYd9gYC.js → chunk--JpdI-Ht.js} +1 -1
  7. package/dist/cli/{chunk-m4Ineemy.js → chunk-4O8yrQuN.js} +1 -1
  8. package/dist/cli/{chunk-BiH9IXnQ.js → chunk-7S9Ywlfy.js} +1 -1
  9. package/dist/cli/{chunk-BmMOdYvk.js → chunk-B0SqqDSK.js} +1 -1
  10. package/dist/cli/chunk-BNaWaEm-.js +1 -0
  11. package/dist/cli/chunk-BXCsxO9e.js +1 -0
  12. package/dist/cli/chunk-Bq37qDoZ.js +18 -0
  13. package/dist/cli/{chunk-C1htf-nO.js → chunk-BrEeCKIo.js} +2 -2
  14. package/dist/cli/{chunk-BI1SOTM1.js → chunk-Bu3ylrhT.js} +8 -8
  15. package/dist/cli/{chunk-3smiGQoQ.js → chunk-C1v_s0Kb.js} +1 -1
  16. package/dist/cli/{chunk-DGeysxz3.js → chunk-C44G533y.js} +1 -1
  17. package/dist/cli/{chunk-9KiBalKu.js → chunk-C7hJLmsL.js} +1 -1
  18. package/dist/cli/{chunk-BFv9XSNd.js → chunk-CAaQWd6t.js} +1 -1
  19. package/dist/cli/chunk-CIkgn5Fh.js +1 -0
  20. package/dist/cli/chunk-CWEIN2kc.js +1 -0
  21. package/dist/cli/{chunk-BDeDZ-0L.js → chunk-CYg1lO1a.js} +1 -1
  22. package/dist/cli/{chunk-DXLmEQ3i.js → chunk-Ce09lwXT.js} +1 -1
  23. package/dist/cli/{chunk-XsfHeN4m.js → chunk-CpdqRSO-.js} +1 -1
  24. package/dist/cli/chunk-DB4x5L-B.js +1 -0
  25. package/dist/cli/{chunk-DaNyMqrk.js → chunk-DBvObsBQ.js} +1 -1
  26. package/dist/cli/chunk-DGPpt7Ka.js +1 -0
  27. package/dist/cli/chunk-DGagHluH.js +1 -0
  28. package/dist/cli/chunk-DUIs23D9.js +1 -0
  29. package/dist/cli/{chunk-CyvfQV16.js → chunk-DaurYOqg.js} +1 -1
  30. package/dist/cli/{chunk-DSFrcSyA.js → chunk-DfwRL0Ue.js} +1 -1
  31. package/dist/cli/{chunk-M2tZrzY5.js → chunk-DudYQk0p.js} +1 -1
  32. package/dist/cli/chunk-DvKo50Tp.js +2 -0
  33. package/dist/cli/{chunk-H_Mw5ypp.js → chunk-Dvrqte5Q.js} +2 -2
  34. package/dist/cli/{chunk-BtNO-m9T.js → chunk-DzhSExU0.js} +1 -1
  35. package/dist/cli/{chunk-IOMO88kZ.js → chunk-ENKlt3i9.js} +1 -1
  36. package/dist/cli/{chunk-Bspgzwsm.js → chunk-FWRwAX75.js} +8 -8
  37. package/dist/cli/chunk-Lf-Z-h48.js +32 -0
  38. package/dist/cli/{chunk-BucXnZ4Z.js → chunk-VRfkSLrD.js} +1 -1
  39. package/dist/cli/chunk-uaTxD024.js +1 -0
  40. package/dist/cli/cli.js +1 -1
  41. package/dist/cli/prerender/dsd-shell/prerender-dsd-shell.js +1 -1
  42. package/dist/headless-agent.js +2 -2
  43. package/dist/lib/components/index.js +25 -25
  44. package/dist/lib/components/settings/shadow-claw-accounts.js +1 -1
  45. package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
  46. package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
  47. package/dist/lib/components/settings/shadow-claw-git.js +1 -1
  48. package/dist/lib/components/settings/shadow-claw-integrations.js +1 -1
  49. package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
  50. package/dist/lib/components/settings/shadow-claw-mcp-remote.js +1 -1
  51. package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
  52. package/dist/lib/components/settings/shadow-claw-notifications.js +1 -1
  53. package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
  54. package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
  55. package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
  56. package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
  57. package/dist/lib/components/shadow-claw/utils/get-route.d.ts +3 -0
  58. package/dist/lib/components/shadow-claw/utils/sync-slotted-sidebar-active-links.d.ts +1 -1
  59. package/dist/lib/components/shadow-claw-accounts.js +1 -1
  60. package/dist/lib/components/shadow-claw-channel-config.js +1 -1
  61. package/dist/lib/components/shadow-claw-channels.js +1 -1
  62. package/dist/lib/components/shadow-claw-chat.js +1 -1
  63. package/dist/lib/components/shadow-claw-control-plane.js +1 -1
  64. package/dist/lib/components/shadow-claw-conversations.js +1 -1
  65. package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
  66. package/dist/lib/components/shadow-claw-files.js +1 -1
  67. package/dist/lib/components/shadow-claw-git.js +1 -1
  68. package/dist/lib/components/shadow-claw-integrations.js +1 -1
  69. package/dist/lib/components/shadow-claw-llm.js +1 -1
  70. package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
  71. package/dist/lib/components/shadow-claw-networking.js +1 -1
  72. package/dist/lib/components/shadow-claw-notifications.js +1 -1
  73. package/dist/lib/components/shadow-claw-page-header.js +1 -1
  74. package/dist/lib/components/shadow-claw-pages.js +1 -1
  75. package/dist/lib/components/shadow-claw-peerjs.js +1 -1
  76. package/dist/lib/components/shadow-claw-settings.js +1 -1
  77. package/dist/lib/components/shadow-claw-storage.js +1 -1
  78. package/dist/lib/components/shadow-claw-task-server.js +1 -1
  79. package/dist/lib/components/shadow-claw-tasks.js +1 -1
  80. package/dist/lib/components/shadow-claw-terminal.js +1 -1
  81. package/dist/lib/components/shadow-claw-tools.js +1 -1
  82. package/dist/lib/components/shadow-claw-webvm.js +1 -1
  83. package/dist/lib/components/shadow-claw.js +1 -1
  84. package/dist/lib/{configure-peer-js-D5jDCtLx.js → configure-peer-js-C9554Slv.js} +2 -2
  85. package/dist/lib/{configure-peer-js-D5jDCtLx.js.map → configure-peer-js-C9554Slv.js.map} +1 -1
  86. package/dist/lib/{file-viewer-B4CL4e0i.js → file-viewer-DBc5dxNy.js} +2 -2
  87. package/dist/lib/{file-viewer-B4CL4e0i.js.map → file-viewer-DBc5dxNy.js.map} +1 -1
  88. package/dist/lib/index.js +28 -27
  89. package/dist/lib/{init-control-plane-l2uFnhGV.js → init-control-plane-D-41Fm5q.js} +12 -12
  90. package/dist/lib/{init-control-plane-l2uFnhGV.js.map → init-control-plane-D-41Fm5q.js.map} +1 -1
  91. package/dist/lib/{markdown-0_p_zfxL.js → markdown-KnDWzWJJ.js} +2 -2
  92. package/dist/lib/{markdown-0_p_zfxL.js.map → markdown-KnDWzWJJ.js.map} +1 -1
  93. package/dist/lib/{orchestrator-D6wm8Sec.js → orchestrator-BEZcqgR5.js} +9 -9
  94. package/dist/lib/{orchestrator-D6wm8Sec.js.map → orchestrator-BEZcqgR5.js.map} +1 -1
  95. package/dist/lib/{orchestrator-Dh-hnIpK.js → orchestrator-Cda13e5U.js} +4 -4
  96. package/dist/lib/{orchestrator-Dh-hnIpK.js.map → orchestrator-Cda13e5U.js.map} +1 -1
  97. package/dist/lib/{peerjs-BWZnsD0B.js → peerjs-DYkUTcee.js} +5 -5
  98. package/dist/lib/{peerjs-BWZnsD0B.js.map → peerjs-DYkUTcee.js.map} +1 -1
  99. package/dist/lib/{push-client-MybDfOdi.js → push-client-CQtCFDaD.js} +3 -3
  100. package/dist/lib/{push-client-MybDfOdi.js.map → push-client-CQtCFDaD.js.map} +1 -1
  101. package/dist/lib/security/custom-element-security.d.ts +8 -4
  102. package/dist/lib/{shadow-claw-PdOpgTxH.js → shadow-claw-DYe9u6Tp.js} +142 -33
  103. package/dist/lib/shadow-claw-DYe9u6Tp.js.map +1 -0
  104. package/dist/lib/{shadow-claw-accounts-3bR76EOb.js → shadow-claw-accounts-D2URoHys.js} +2 -2
  105. package/dist/lib/{shadow-claw-accounts-3bR76EOb.js.map → shadow-claw-accounts-D2URoHys.js.map} +1 -1
  106. package/dist/lib/{shadow-claw-channel-config-ChdZ1iB8.js → shadow-claw-channel-config-buXoz2xv.js} +3 -3
  107. package/dist/lib/{shadow-claw-channel-config-ChdZ1iB8.js.map → shadow-claw-channel-config-buXoz2xv.js.map} +1 -1
  108. package/dist/lib/{shadow-claw-channels-CK9sc7h_.js → shadow-claw-channels-5yVJ1gLk.js} +3 -3
  109. package/dist/lib/{shadow-claw-channels-CK9sc7h_.js.map → shadow-claw-channels-5yVJ1gLk.js.map} +1 -1
  110. package/dist/lib/{shadow-claw-chat-B6uuZnJ7.js → shadow-claw-chat-CVc-7ycM.js} +7 -7
  111. package/dist/lib/{shadow-claw-chat-B6uuZnJ7.js.map → shadow-claw-chat-CVc-7ycM.js.map} +1 -1
  112. package/dist/lib/{shadow-claw-control-plane-BpRcl312.js → shadow-claw-control-plane-B5vsF91B.js} +6 -6
  113. package/dist/lib/{shadow-claw-control-plane-BpRcl312.js.map → shadow-claw-control-plane-B5vsF91B.js.map} +1 -1
  114. package/dist/lib/{shadow-claw-conversations-Dc_Xk2mB.js → shadow-claw-conversations-PGK5zqn3.js} +54 -12
  115. package/dist/lib/{shadow-claw-conversations-Dc_Xk2mB.js.map → shadow-claw-conversations-PGK5zqn3.js.map} +1 -1
  116. package/dist/lib/{shadow-claw-file-viewer-C4x1PtB2.js → shadow-claw-file-viewer-DSqn0hgx.js} +6 -6
  117. package/dist/lib/{shadow-claw-file-viewer-C4x1PtB2.js.map → shadow-claw-file-viewer-DSqn0hgx.js.map} +1 -1
  118. package/dist/lib/{shadow-claw-files-DhnHbXKf.js → shadow-claw-files-vOa9ZWbr.js} +6 -6
  119. package/dist/lib/{shadow-claw-files-DhnHbXKf.js.map → shadow-claw-files-vOa9ZWbr.js.map} +1 -1
  120. package/dist/lib/{shadow-claw-git-BeQ1ElUd.js → shadow-claw-git-D54Z85Bj.js} +4 -4
  121. package/dist/lib/{shadow-claw-git-BeQ1ElUd.js.map → shadow-claw-git-D54Z85Bj.js.map} +1 -1
  122. package/dist/lib/{shadow-claw-integrations-Bbdolk3w.js → shadow-claw-integrations-BTubMH9d.js} +2 -2
  123. package/dist/lib/{shadow-claw-integrations-Bbdolk3w.js.map → shadow-claw-integrations-BTubMH9d.js.map} +1 -1
  124. package/dist/lib/{shadow-claw-llm-DPda4L3C.js → shadow-claw-llm-8koGTNYs.js} +3 -3
  125. package/dist/lib/{shadow-claw-llm-DPda4L3C.js.map → shadow-claw-llm-8koGTNYs.js.map} +1 -1
  126. package/dist/lib/{shadow-claw-mcp-remote-Dn9c30WI.js → shadow-claw-mcp-remote-C2jwBsQt.js} +2 -2
  127. package/dist/lib/{shadow-claw-mcp-remote-Dn9c30WI.js.map → shadow-claw-mcp-remote-C2jwBsQt.js.map} +1 -1
  128. package/dist/lib/{shadow-claw-networking-zqNuyn3-.js → shadow-claw-networking-BV-rna16.js} +2 -2
  129. package/dist/lib/{shadow-claw-networking-zqNuyn3-.js.map → shadow-claw-networking-BV-rna16.js.map} +1 -1
  130. package/dist/lib/{shadow-claw-notifications-DFgdo33v.js → shadow-claw-notifications-Dku7VBLk.js} +2 -2
  131. package/dist/lib/{shadow-claw-notifications-DFgdo33v.js.map → shadow-claw-notifications-Dku7VBLk.js.map} +1 -1
  132. package/dist/lib/{shadow-claw-page-header-B7LFGQRf.js → shadow-claw-page-header-VPjYWfsT.js} +2 -2
  133. package/dist/lib/{shadow-claw-page-header-B7LFGQRf.js.map → shadow-claw-page-header-VPjYWfsT.js.map} +1 -1
  134. package/dist/lib/{shadow-claw-pages-DLspFqdK.js → shadow-claw-pages-DXrM6hgZ.js} +29 -19
  135. package/dist/lib/shadow-claw-pages-DXrM6hgZ.js.map +1 -0
  136. package/dist/lib/{shadow-claw-peerjs-D8xWwuWR.js → shadow-claw-peerjs-D3xonez5.js} +3 -3
  137. package/dist/lib/{shadow-claw-peerjs-D8xWwuWR.js.map → shadow-claw-peerjs-D3xonez5.js.map} +1 -1
  138. package/dist/lib/{shadow-claw-settings-NbvzXASD.js → shadow-claw-settings-DMTx6OS9.js} +5 -5
  139. package/dist/lib/{shadow-claw-settings-NbvzXASD.js.map → shadow-claw-settings-DMTx6OS9.js.map} +1 -1
  140. package/dist/lib/{shadow-claw-storage-B_NAoZmd.js → shadow-claw-storage-BJLnukxa.js} +3 -3
  141. package/dist/lib/{shadow-claw-storage-B_NAoZmd.js.map → shadow-claw-storage-BJLnukxa.js.map} +1 -1
  142. package/dist/lib/{shadow-claw-task-server-BaQJXhYJ.js → shadow-claw-task-server-DcMj20hD.js} +2 -2
  143. package/dist/lib/{shadow-claw-task-server-BaQJXhYJ.js.map → shadow-claw-task-server-DcMj20hD.js.map} +1 -1
  144. package/dist/lib/{shadow-claw-tasks-CAZua0-j.js → shadow-claw-tasks-BQBe4lVi.js} +7 -7
  145. package/dist/lib/{shadow-claw-tasks-CAZua0-j.js.map → shadow-claw-tasks-BQBe4lVi.js.map} +1 -1
  146. package/dist/lib/{shadow-claw-terminal-B2YJhkJL.js → shadow-claw-terminal-DPEzTxXv.js} +2 -2
  147. package/dist/lib/{shadow-claw-terminal-B2YJhkJL.js.map → shadow-claw-terminal-DPEzTxXv.js.map} +1 -1
  148. package/dist/lib/{shadow-claw-tools-CkZWxxTm.js → shadow-claw-tools-BCnU8FaK.js} +6 -6
  149. package/dist/lib/{shadow-claw-tools-CkZWxxTm.js.map → shadow-claw-tools-BCnU8FaK.js.map} +1 -1
  150. package/dist/lib/{shadow-claw-webvm-BL9cgrP9.js → shadow-claw-webvm-CnW-hoJ8.js} +2 -2
  151. package/dist/lib/{shadow-claw-webvm-BL9cgrP9.js.map → shadow-claw-webvm-CnW-hoJ8.js.map} +1 -1
  152. package/dist/lib/subsystems/mcp/webmcp.d.ts +15 -2
  153. package/dist/lib/{sync-web-mcp-registration-dW2MVCj4.js → sync-web-mcp-registration-DwpGjVdo.js} +10 -4
  154. package/dist/lib/sync-web-mcp-registration-DwpGjVdo.js.map +1 -0
  155. package/dist/lib/{tools-D7whby3H.js → tools-CP6G0HF7.js} +5 -6
  156. package/dist/lib/tools-CP6G0HF7.js.map +1 -0
  157. package/dist/lib/{trusted-types-d0cdkut_.js → trusted-types-0cu5Dm6M.js} +29 -4
  158. package/dist/lib/{trusted-types-d0cdkut_.js.map → trusted-types-0cu5Dm6M.js.map} +1 -1
  159. package/dist/lib/utils/index.d.ts +1 -0
  160. package/dist/lib/utils/index.js +4 -2
  161. package/dist/lib/utils/index.js.map +1 -1
  162. package/dist/lib/utils/resolve-page-script-dependencies.d.ts +19 -0
  163. package/dist/lib/utils/resolve-page-script-dependencies.js +98 -0
  164. package/dist/lib/utils/resolve-page-script-dependencies.js.map +1 -0
  165. package/dist/lib/utils/utils.js +1 -1
  166. package/dist/lib/webmcp-Bf9rT7uu.js +2001 -0
  167. package/dist/lib/webmcp-Bf9rT7uu.js.map +1 -0
  168. package/dist/public/.well-known/mcp/server-card.json +1 -1
  169. package/dist/public/.well-known/mcp.json +1 -1
  170. package/dist/public/AGENTS.md +3 -3
  171. package/dist/public/README.md +1 -1
  172. package/dist/public/agent.worker.js +2 -2
  173. package/dist/public/components/shadow-claw/shadow-claw.css +1 -1
  174. package/dist/public/components/shadow-claw/shadow-claw.html +1 -1
  175. package/dist/public/components/shadow-claw-conversations/shadow-claw-conversations.css +1 -1
  176. package/dist/public/components/shadow-claw-conversations/shadow-claw-conversations.html +1 -1
  177. package/dist/public/{configure-peer-js-WLRM7Qa7.js → configure-peer-js-OYl3V8sW.js} +1 -1
  178. package/dist/public/{custom-element-security-Cl991z-x.js → custom-element-security-BR4V40j4.js} +1 -1
  179. package/dist/public/docs/example/article/index.html +3 -3
  180. package/dist/public/docs/example/article.html +3 -3
  181. package/dist/public/docs/publishing/index.html +3 -3
  182. package/dist/public/docs/publishing.html +3 -3
  183. package/dist/public/docs/skill-creator/index.html +3 -3
  184. package/dist/public/docs/skill-creator.html +3 -3
  185. package/dist/public/docs/subsystems/custom-element-security.md +19 -5
  186. package/dist/public/docs/subsystems/pages.md +10 -2
  187. package/dist/public/docs/subsystems/tools.md +1 -2
  188. package/dist/public/docs/subsystems/webmcp.md +41 -6
  189. package/dist/public/{download-group-file-fFjoIIp4.js → download-group-file-BNmK8wac.js} +1 -1
  190. package/dist/public/e2e/README.md +2 -2
  191. package/dist/public/{e2e-bridge-CiSfBRT4.js → e2e-bridge-4phD1JUQ.js} +1 -1
  192. package/dist/public/{file-viewer-DFC3kfeO.js → file-viewer-Dbh3K9nL.js} +1 -1
  193. package/dist/public/index.html +3 -3
  194. package/dist/public/index.js +1 -1
  195. package/dist/public/{init-control-plane-BEbcwmmv.js → init-control-plane-DGOY_RNS.js} +1 -1
  196. package/dist/public/llms.txt +1 -1
  197. package/dist/public/main/index.html +3 -3
  198. package/dist/public/main/memory/index.html +3 -3
  199. package/dist/public/main/memory.html +3 -3
  200. package/dist/public/main.html +3 -3
  201. package/dist/public/{markdown-BeglYzw9.js → markdown-BPZYpfGm.js} +1 -1
  202. package/dist/public/{orchestrator-BlvEG3PO.js → orchestrator-OoUK7CF9.js} +1 -1
  203. package/dist/public/{orchestrator-DTNrntd4.js → orchestrator-a9047bGu.js} +1 -1
  204. package/dist/public/{peerjs-CnBdK94R.js → peerjs-Cbn310Tz.js} +1 -1
  205. package/dist/public/{push-client-DOHbdCyj.js → push-client-Dy4LGJy9.js} +1 -1
  206. package/dist/public/service-worker.js +1 -1
  207. package/dist/public/shadow-claw-B-HWC1uN.js +1180 -0
  208. package/dist/public/{shadow-claw-accounts-C6FXVw2K.js → shadow-claw-accounts-Di-anCZ1.js} +1 -1
  209. package/dist/public/{shadow-claw-channels-tr_r60Kq.js → shadow-claw-channels-RVwCE8pE.js} +1 -1
  210. package/dist/public/{shadow-claw-chat-BAAPhAOs.js → shadow-claw-chat-DI1q8UnX.js} +1 -1
  211. package/dist/public/{shadow-claw-control-plane-C_5VIx8E.js → shadow-claw-control-plane-KXEdLOGl.js} +2 -2
  212. package/dist/public/{shadow-claw-conversations-DGYZdDa3.js → shadow-claw-conversations-BCBGtS30.js} +40 -6
  213. package/dist/public/{shadow-claw-file-viewer-5j2-Z3fN.js → shadow-claw-file-viewer-CW3t6j-w.js} +1 -1
  214. package/dist/public/{shadow-claw-files-DKF4Yy0m.js → shadow-claw-files-JQ-o0ImX.js} +1 -1
  215. package/dist/public/{shadow-claw-git-CtUTJXKT.js → shadow-claw-git-D2M8VixW.js} +2 -2
  216. package/dist/public/{shadow-claw-integrations-CuBy9D3z.js → shadow-claw-integrations-Cgw6v9_1.js} +1 -1
  217. package/dist/public/{shadow-claw-llm-BIfNNjGL.js → shadow-claw-llm-74ieXp7i.js} +1 -1
  218. package/dist/public/{shadow-claw-mcp-remote-C17FXvrb.js → shadow-claw-mcp-remote-BX0BkSmy.js} +1 -1
  219. package/dist/public/{shadow-claw-networking-CjxQ1CLI.js → shadow-claw-networking-DNX8vaIQ.js} +1 -1
  220. package/dist/public/{shadow-claw-notifications-Brn2O3Ps.js → shadow-claw-notifications-BLTaGAny.js} +1 -1
  221. package/dist/public/{shadow-claw-page-header-Bn1P7Cxb.js → shadow-claw-page-header-CjFOdo9v.js} +1 -1
  222. package/dist/public/shadow-claw-pages-DOQqMm0_.js +645 -0
  223. package/dist/public/{shadow-claw-settings-CfDm0hVA.js → shadow-claw-settings-DFtl0Fy8.js} +2 -2
  224. package/dist/public/{shadow-claw-storage-DOOesRzw.js → shadow-claw-storage-gQGExZRq.js} +1 -1
  225. package/dist/public/{shadow-claw-task-server-H36iDDp2.js → shadow-claw-task-server-Ca45uY7S.js} +1 -1
  226. package/dist/public/{shadow-claw-tasks-4JsjSGkN.js → shadow-claw-tasks-CCTaaSdi.js} +1 -1
  227. package/dist/public/{shadow-claw-terminal-CTRTcYz-.js → shadow-claw-terminal-BfgulLkl.js} +1 -1
  228. package/dist/public/{shadow-claw-tools-Dm1LxNf4.js → shadow-claw-tools-V8NA4n18.js} +1 -1
  229. package/dist/public/{shadow-claw-webvm-JzuPe9Nr.js → shadow-claw-webvm-CxxI2bnC.js} +1 -1
  230. package/dist/public/sync-web-mcp-registration-CkCA8UFm.js +1 -0
  231. package/dist/public/{tools-FiTtOlIt.js → tools-CwQq5tJH.js} +2 -2
  232. package/dist/public/webmcp-CmtWOAFm.js +6 -0
  233. package/dist/server.js +2 -2
  234. package/package.json +3 -3
  235. package/src/cli/prerender/dsd-shell/prerender-dsd-shell.test.ts +16 -0
  236. package/src/cli/prerender/dsd-shell/prerender-dsd-shell.ts +62 -1
  237. package/src/cli/prerender/pretty-paths/prerender-pretty-paths.test.ts +277 -0
  238. package/src/cli/prerender/pretty-paths/prerender-pretty-paths.ts +28 -1
  239. package/src/cli/site-config/custom-elements/build-custom-element-script-tags.ts +13 -1
  240. package/src/components/shadow-claw/shadow-claw.css +12 -0
  241. package/src/components/shadow-claw/shadow-claw.html +12 -2
  242. package/src/components/shadow-claw/utils/bind-event-listeners.test.ts +18 -0
  243. package/src/components/shadow-claw/utils/bind-event-listeners.ts +14 -0
  244. package/src/components/shadow-claw/utils/get-route.test.ts +35 -0
  245. package/src/components/shadow-claw/utils/get-route.ts +18 -0
  246. package/src/components/shadow-claw/utils/sync-slotted-sidebar-active-links.test.ts +152 -1
  247. package/src/components/shadow-claw/utils/sync-slotted-sidebar-active-links.ts +139 -8
  248. package/src/components/shadow-claw-conversations/shadow-claw-conversations.css +11 -0
  249. package/src/components/shadow-claw-conversations/shadow-claw-conversations.html +27 -4
  250. package/src/components/shadow-claw-conversations/shadow-claw-conversations.ts +32 -4
  251. package/src/components/shadow-claw-pages/shadow-claw-pages-scripts.test.ts +266 -0
  252. package/src/components/shadow-claw-pages/shadow-claw-pages.ts +41 -17
  253. package/src/core/orchestrator/utils/sync-web-mcp-registration.test.ts +18 -1
  254. package/src/core/orchestrator/utils/sync-web-mcp-registration.ts +8 -0
  255. package/src/core/utils/init-control-plane.test.ts +9 -4
  256. package/src/security/custom-element-security.test.ts +65 -0
  257. package/src/security/custom-element-security.ts +67 -4
  258. package/src/stores/tools.test.ts +5 -3
  259. package/src/stores/tools.ts +5 -10
  260. package/src/subsystems/mcp/webmcp.test.ts +84 -13
  261. package/src/subsystems/mcp/webmcp.ts +73 -10
  262. package/src/utils/index.ts +1 -0
  263. package/src/utils/resolve-page-script-dependencies.test.ts +245 -0
  264. package/src/utils/resolve-page-script-dependencies.ts +198 -0
  265. package/dist/cli/chunk-B1hufJeO.js +0 -1
  266. package/dist/cli/chunk-BZpn8npn.js +0 -1
  267. package/dist/cli/chunk-Bw5aOTFr.js +0 -1
  268. package/dist/cli/chunk-C8nH01Gw.js +0 -32
  269. package/dist/cli/chunk-CK1ZoyoE.js +0 -17
  270. package/dist/cli/chunk-CVkhDr-7.js +0 -1
  271. package/dist/cli/chunk-Cum07Vlh.js +0 -1
  272. package/dist/cli/chunk-D3UhDDmV.js +0 -2
  273. package/dist/cli/chunk-D8GI6qj6.js +0 -1
  274. package/dist/cli/chunk-DEH-FvmP.js +0 -1
  275. package/dist/cli/chunk-DksvJ_kf.js +0 -1
  276. package/dist/cli/chunk-RGb9wM4R.js +0 -1
  277. package/dist/lib/shadow-claw-PdOpgTxH.js.map +0 -1
  278. package/dist/lib/shadow-claw-pages-DLspFqdK.js.map +0 -1
  279. package/dist/lib/sync-web-mcp-registration-dW2MVCj4.js.map +0 -1
  280. package/dist/lib/tools-D7whby3H.js.map +0 -1
  281. package/dist/lib/webmcp-CYTNZfkn.js +0 -1687
  282. package/dist/lib/webmcp-CYTNZfkn.js.map +0 -1
  283. package/dist/public/shadow-claw-CnNX-WCh.js +0 -1158
  284. package/dist/public/shadow-claw-pages-BwOOqRWW.js +0 -645
  285. package/dist/public/sync-web-mcp-registration-BnHVUjat.js +0 -1
  286. 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.54.0",
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": "^5.1.0",
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
- const minifiedHtml = minifyDsdTemplateHtml(nextHtml);
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(htmlWithSeo, embeddedRoutingJson),
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, "&amp;")
20
+ .replace(/"/g, "&quot;")
21
+ .replace(/</g, "&lt;")
22
+ .replace(/>/g, "&gt;");
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 method="dialog" class="app-confirm-dialog__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 method="dialog" class="app-prompt-dialog__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