shadow-claw 1.26.0 → 1.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/main/skill-creator/SKILL.md +39 -0
- package/.agents/skills/main/skill-creator/references/declarative-pipelines.md +44 -0
- package/.agents/skills/main/skill-creator/references/declarative-tools.md +35 -0
- package/.agents/skills/main/skill-creator/references/frontmatter-spec.md +50 -0
- package/.well-known/agent-skills/index.json +14 -0
- package/README.md +5 -3
- package/bin/build/build.mjs +148 -15
- package/bin/build/build.test.mjs +128 -0
- package/bin/cli.mjs +35 -0
- package/bin/commands/mcp.mjs +277 -55
- package/bin/commands/mcp.test.mjs +275 -1
- package/bin/commands/skills-index.mjs +447 -0
- package/bin/commands/skills-index.test.mjs +243 -0
- package/bin/site-config/utils/custom-elements/get-approved-custom-element-scripts.test.mjs +2 -0
- package/bin/site-config/utils/custom-elements/sanitize-embedded-custom-element-scripts.test.mjs +10 -1
- 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-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-a2ui.js +1 -1
- package/dist/lib/components/shadow-claw-accounts.js +1 -1
- package/dist/lib/components/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/shadow-claw-channels.js +1 -1
- package/dist/lib/components/shadow-claw-chat.js +1 -1
- package/dist/lib/components/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/shadow-claw-conversations.js +1 -1
- package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
- package/dist/lib/components/shadow-claw-files.js +1 -1
- package/dist/lib/components/shadow-claw-git.js +1 -1
- package/dist/lib/components/shadow-claw-integrations.js +1 -1
- package/dist/lib/components/shadow-claw-llm.js +1 -1
- package/dist/lib/components/shadow-claw-mcp-remote.js +1 -1
- package/dist/lib/components/shadow-claw-networking.js +1 -1
- package/dist/lib/components/shadow-claw-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/{configurePeerJs-CrlGan0m.js → configurePeerJs-oODzltaC.js} +2 -2
- package/dist/lib/{configurePeerJs-CrlGan0m.js.map → configurePeerJs-oODzltaC.js.map} +1 -1
- package/dist/lib/core/control-plane-client.d.ts +1 -0
- package/dist/lib/{downloadGroupFile-DboUjmp2.js → downloadGroupFile-DmcBQU1n.js} +2 -2
- package/dist/lib/{downloadGroupFile-DboUjmp2.js.map → downloadGroupFile-DmcBQU1n.js.map} +1 -1
- package/dist/lib/{file-viewer-BrK2Wxgh.js → file-viewer-C3YKnq_-.js} +4 -3
- package/dist/lib/{file-viewer-BrK2Wxgh.js.map → file-viewer-C3YKnq_-.js.map} +1 -1
- package/dist/lib/index.js +26 -26
- package/dist/lib/{initControlPlane-CsO4UR6_.js → initControlPlane-C2zURVIS.js} +86 -13
- package/dist/lib/initControlPlane-C2zURVIS.js.map +1 -0
- package/dist/lib/{markdown-eeSTFnMA.js → markdown-C6EHl9zs.js} +3 -3
- package/dist/lib/{markdown-eeSTFnMA.js.map → markdown-C6EHl9zs.js.map} +1 -1
- package/dist/lib/{orchestrator-CJvoC2Uu.js → orchestrator-CACLa_Ro.js} +7 -6
- package/dist/lib/{orchestrator-CJvoC2Uu.js.map → orchestrator-CACLa_Ro.js.map} +1 -1
- package/dist/lib/{orchestrator-DCfomsn9.js → orchestrator-KRjx0eba.js} +6 -534
- package/dist/lib/{orchestrator-DCfomsn9.js.map → orchestrator-KRjx0eba.js.map} +1 -1
- package/dist/lib/parsePath-DwC_YZjw.js +16 -0
- package/dist/lib/parsePath-DwC_YZjw.js.map +1 -0
- package/dist/lib/{peerjs-Dp02bXcG.js → peerjs-DFWOBcXf.js} +4 -4
- package/dist/lib/{peerjs-Dp02bXcG.js.map → peerjs-DFWOBcXf.js.map} +1 -1
- package/dist/lib/{readGroupFileBytes-Bve-e5e_.js → readGroupFileBytes-C8oOe8Iu.js} +3 -16
- package/dist/lib/readGroupFileBytes-C8oOe8Iu.js.map +1 -0
- package/dist/lib/security/custom-element-security.d.ts +8 -0
- package/dist/lib/server/control-plane-types.d.ts +1 -1
- package/dist/lib/{shadow-claw-D8xINM3c.js → shadow-claw-6UHdiy4a.js} +5 -5
- package/dist/lib/{shadow-claw-D8xINM3c.js.map → shadow-claw-6UHdiy4a.js.map} +1 -1
- package/dist/lib/{shadow-claw-a2ui-7rJqG4Ke.js → shadow-claw-a2ui-CpZUTzlh.js} +5 -4
- package/dist/lib/{shadow-claw-a2ui-7rJqG4Ke.js.map → shadow-claw-a2ui-CpZUTzlh.js.map} +1 -1
- package/dist/lib/{shadow-claw-accounts-CdruwN8A.js → shadow-claw-accounts-03oJ__XC.js} +2 -2
- package/dist/lib/{shadow-claw-accounts-CdruwN8A.js.map → shadow-claw-accounts-03oJ__XC.js.map} +1 -1
- package/dist/lib/{shadow-claw-channel-config-Bj0-Nk3t.js → shadow-claw-channel-config-DmfwJc6G.js} +3 -3
- package/dist/lib/{shadow-claw-channel-config-Bj0-Nk3t.js.map → shadow-claw-channel-config-DmfwJc6G.js.map} +1 -1
- package/dist/lib/{shadow-claw-channels-C_jI4KhP.js → shadow-claw-channels-1N6Jl-By.js} +3 -3
- package/dist/lib/{shadow-claw-channels-C_jI4KhP.js.map → shadow-claw-channels-1N6Jl-By.js.map} +1 -1
- package/dist/lib/{shadow-claw-chat-B16MspoP.js → shadow-claw-chat-BMoqQJRK.js} +10 -10
- package/dist/lib/{shadow-claw-chat-B16MspoP.js.map → shadow-claw-chat-BMoqQJRK.js.map} +1 -1
- package/dist/lib/{shadow-claw-control-plane-x8Ldid_h.js → shadow-claw-control-plane-UG0o7pCz.js} +6 -6
- package/dist/lib/{shadow-claw-control-plane-x8Ldid_h.js.map → shadow-claw-control-plane-UG0o7pCz.js.map} +1 -1
- package/dist/lib/{shadow-claw-conversations-Ct1kAYdB.js → shadow-claw-conversations-BwXep3iu.js} +4 -3
- package/dist/lib/{shadow-claw-conversations-Ct1kAYdB.js.map → shadow-claw-conversations-BwXep3iu.js.map} +1 -1
- package/dist/lib/{shadow-claw-file-viewer-BfDHHgpA.js → shadow-claw-file-viewer-DUxzVxDT.js} +14 -10
- package/dist/lib/shadow-claw-file-viewer-DUxzVxDT.js.map +1 -0
- package/dist/lib/{shadow-claw-files-EYhOPYIH.js → shadow-claw-files-DIREEnT2.js} +7 -7
- package/dist/lib/{shadow-claw-files-EYhOPYIH.js.map → shadow-claw-files-DIREEnT2.js.map} +1 -1
- package/dist/lib/{shadow-claw-git-tcSpT-P0.js → shadow-claw-git-Bg1SWgsF.js} +4 -4
- package/dist/lib/{shadow-claw-git-tcSpT-P0.js.map → shadow-claw-git-Bg1SWgsF.js.map} +1 -1
- package/dist/lib/{shadow-claw-integrations-NbcCx_ZI.js → shadow-claw-integrations-Ds-CLPhj.js} +2 -2
- package/dist/lib/{shadow-claw-integrations-NbcCx_ZI.js.map → shadow-claw-integrations-Ds-CLPhj.js.map} +1 -1
- package/dist/lib/{shadow-claw-llm-BazJdD5f.js → shadow-claw-llm-CazBrVpM.js} +3 -3
- package/dist/lib/{shadow-claw-llm-BazJdD5f.js.map → shadow-claw-llm-CazBrVpM.js.map} +1 -1
- package/dist/lib/{shadow-claw-mcp-remote-CYmhpg7a.js → shadow-claw-mcp-remote-CT5Q-54E.js} +2 -2
- package/dist/lib/{shadow-claw-mcp-remote-CYmhpg7a.js.map → shadow-claw-mcp-remote-CT5Q-54E.js.map} +1 -1
- package/dist/lib/{shadow-claw-networking-DImPxe0H.js → shadow-claw-networking-Df85tCbO.js} +2 -2
- package/dist/lib/{shadow-claw-networking-DImPxe0H.js.map → shadow-claw-networking-Df85tCbO.js.map} +1 -1
- package/dist/lib/{shadow-claw-page-header-CcHUfFUx.js → shadow-claw-page-header-Cti2fzf-.js} +2 -2
- package/dist/lib/{shadow-claw-page-header-CcHUfFUx.js.map → shadow-claw-page-header-Cti2fzf-.js.map} +1 -1
- package/dist/lib/{shadow-claw-pages-D54jF1Qq.js → shadow-claw-pages-BgPyIEZO.js} +15 -11
- package/dist/lib/shadow-claw-pages-BgPyIEZO.js.map +1 -0
- package/dist/lib/{shadow-claw-peerjs-B9-T8Nlx.js → shadow-claw-peerjs-xkBXILed.js} +3 -3
- package/dist/lib/{shadow-claw-peerjs-B9-T8Nlx.js.map → shadow-claw-peerjs-xkBXILed.js.map} +1 -1
- package/dist/lib/{shadow-claw-settings-Bt1VAe-1.js → shadow-claw-settings-CN89xRVU.js} +4 -4
- package/dist/lib/{shadow-claw-settings-Bt1VAe-1.js.map → shadow-claw-settings-CN89xRVU.js.map} +1 -1
- package/dist/lib/{shadow-claw-storage-CFOjGf1d.js → shadow-claw-storage-VnhcObCe.js} +3 -3
- package/dist/lib/{shadow-claw-storage-CFOjGf1d.js.map → shadow-claw-storage-VnhcObCe.js.map} +1 -1
- package/dist/lib/{shadow-claw-task-server-BiKa2GOm.js → shadow-claw-task-server-jgEC2hHB.js} +2 -2
- package/dist/lib/{shadow-claw-task-server-BiKa2GOm.js.map → shadow-claw-task-server-jgEC2hHB.js.map} +1 -1
- package/dist/lib/{shadow-claw-tasks-DDHd8W4d.js → shadow-claw-tasks-i_evIufy.js} +6 -6
- package/dist/lib/{shadow-claw-tasks-DDHd8W4d.js.map → shadow-claw-tasks-i_evIufy.js.map} +1 -1
- package/dist/lib/{shadow-claw-terminal-kB6_tWKz.js → shadow-claw-terminal-CwScROlu.js} +2 -2
- package/dist/lib/{shadow-claw-terminal-kB6_tWKz.js.map → shadow-claw-terminal-CwScROlu.js.map} +1 -1
- package/dist/lib/{shadow-claw-tools-DxXIm0ku.js → shadow-claw-tools-DD3fyXP4.js} +5 -4
- package/dist/lib/{shadow-claw-tools-DxXIm0ku.js.map → shadow-claw-tools-DD3fyXP4.js.map} +1 -1
- package/dist/lib/{shadow-claw-webvm-Dc8oo7ao.js → shadow-claw-webvm-DbJq4I3-.js} +2 -2
- package/dist/lib/{shadow-claw-webvm-Dc8oo7ao.js.map → shadow-claw-webvm-DbJq4I3-.js.map} +1 -1
- package/dist/lib/{syncWebMcpRegistration-jyRGbC9w.js → syncWebMcpRegistration-DNLnQ-jz.js} +3 -2
- package/dist/lib/{syncWebMcpRegistration-jyRGbC9w.js.map → syncWebMcpRegistration-DNLnQ-jz.js.map} +1 -1
- package/dist/lib/tools-DwwB9RBa.js +546 -0
- package/dist/lib/tools-DwwB9RBa.js.map +1 -0
- package/dist/lib/{trusted-types-CkLDpLiZ.js → trusted-types-Dx0RZlrd.js} +19 -8
- package/dist/lib/trusted-types-Dx0RZlrd.js.map +1 -0
- package/dist/lib/utils/index.js +1 -1
- package/dist/lib/utils/utils.js +1 -1
- package/dist/public/.well-known/agent-skills/index.json +14 -0
- package/dist/public/AGENTS.md +5 -3
- package/dist/public/README.md +5 -3
- package/dist/public/agent.worker.js +1 -1
- package/dist/public/{configurePeerJs-COcwE0E7.js → configurePeerJs-BqgeBjP7.js} +1 -1
- package/dist/public/custom-element-security-FU04Cq05.js +1 -0
- package/dist/public/dist-B9m1QM9v.js +58 -0
- package/dist/public/docs/README.md +31 -31
- package/dist/public/docs/example/article/index.html +1 -1
- package/dist/public/docs/publishing/index.html +1 -1
- package/dist/public/docs/skill-creator/index.html +1 -1
- package/dist/public/docs/subsystems/a2ui.md +11 -1
- package/dist/public/docs/subsystems/cli.md +32 -0
- package/dist/public/docs/subsystems/control-plane.md +8 -2
- package/dist/public/docs/subsystems/custom-element-security.md +19 -9
- package/dist/public/docs/subsystems/mcp-server.md +39 -15
- package/dist/public/docs/subsystems/skills.md +30 -0
- package/dist/public/docs/subsystems/webmcp.md +9 -0
- package/dist/public/downloadGroupFile-D8KRJGGL.js +1 -0
- package/dist/public/e2e/README.md +7 -4
- package/dist/public/{e2e-bridge-CHARpbpW.js → e2e-bridge-Ceqr5kGc.js} +1 -1
- package/dist/public/effect-BJCrpFdp.js +1 -0
- package/dist/public/file-viewer-C-6Jc_tb.js +1 -0
- package/dist/public/index.html +1 -1
- package/dist/public/index.js +1 -1
- package/dist/public/initControlPlane-BN9cWyO0.js +1 -0
- package/dist/public/main/index.html +1 -1
- package/dist/public/main/memory/index.html +1 -1
- package/dist/public/{markdown-1I3O6Mmd.js → markdown-C3M4OW_A.js} +1 -1
- package/dist/public/{orchestrator-Cl95w2vb.js → orchestrator-CMbCTjBf.js} +7 -7
- package/dist/public/{orchestrator-D-xlXG92.js → orchestrator-DHjdLtqa.js} +663 -663
- package/dist/public/peerjs-DUCKH-m9.js +1 -0
- package/dist/public/service-worker.js +1 -1
- package/dist/public/{shadow-claw-CaoKmIIB.js → shadow-claw-EAt2ml5Y.js} +3 -3
- package/dist/public/{shadow-claw-accounts-CJvYC4li.js → shadow-claw-accounts-xUOLBsQZ.js} +1 -1
- package/dist/public/{shadow-claw-channels-3K62sU5f.js → shadow-claw-channels-XsfuWFF8.js} +4 -4
- package/dist/public/{shadow-claw-chat-Cu2keU2I.js → shadow-claw-chat-CbSaOZ4q.js} +7 -7
- package/dist/public/{shadow-claw-control-plane-D1OwlQI_.js → shadow-claw-control-plane-DHvN3Ukg.js} +2 -2
- package/dist/public/{shadow-claw-conversations-DDtg3BEZ.js → shadow-claw-conversations-BWs5VVfs.js} +2 -2
- package/dist/public/{shadow-claw-file-viewer-BR__1z9S.js → shadow-claw-file-viewer-BWsoW5QS.js} +5 -4
- package/dist/public/{shadow-claw-files-BJSyZ-Bl.js → shadow-claw-files-CG7MqWiV.js} +8 -8
- package/dist/public/{shadow-claw-git-MAjhXRLc.js → shadow-claw-git-DBRPZNav.js} +6 -6
- package/dist/public/{shadow-claw-integrations-82UoFuDR.js → shadow-claw-integrations-BBVnO0Fc.js} +8 -8
- package/dist/public/{shadow-claw-llm-R8j0lwPP.js → shadow-claw-llm-DMvLgKXo.js} +2 -2
- package/dist/public/{shadow-claw-mcp-remote-BzZoz4LX.js → shadow-claw-mcp-remote-Bkx0gsmF.js} +2 -2
- package/dist/public/{shadow-claw-networking-DLEd9cNm.js → shadow-claw-networking-Dd8Rw31D.js} +2 -2
- package/dist/public/{shadow-claw-notifications-1vwR7TbT.js → shadow-claw-notifications-Dbevj-lq.js} +2 -2
- package/dist/public/{shadow-claw-page-header-DMKbkv3s.js → shadow-claw-page-header-BccSHItx.js} +1 -1
- package/dist/public/{shadow-claw-pages-CjyeIV__.js → shadow-claw-pages-3_lQAv0t.js} +4 -3
- package/dist/public/{shadow-claw-settings-BfbT4dBU.js → shadow-claw-settings-t8TIlgrM.js} +5 -5
- package/dist/public/{shadow-claw-storage-C-mWQQML.js → shadow-claw-storage-CfEXoSIE.js} +2 -2
- package/dist/public/{shadow-claw-task-server-D3lHp0Nc.js → shadow-claw-task-server-DxQSsgRZ.js} +2 -2
- package/dist/public/{shadow-claw-tasks-DVVWEm-c.js → shadow-claw-tasks-DNpicQwz.js} +14 -14
- package/dist/public/{shadow-claw-terminal-BwuTRp-O.js → shadow-claw-terminal-DpY6zU_r.js} +1 -1
- package/dist/public/{shadow-claw-toast-ClCwgzFG.js → shadow-claw-toast-BkrQIP-3.js} +1 -1
- package/dist/public/{shadow-claw-tools-zFLk2nbV.js → shadow-claw-tools-WSwWohnk.js} +2 -2
- package/dist/public/{shadow-claw-webvm-qR9X7fg7.js → shadow-claw-webvm-CP6oFjg5.js} +2 -2
- package/dist/public/syncWebMcpRegistration-DOn9gLnD.js +1 -0
- package/dist/public/toast-BXgUfbyh.js +1 -0
- package/dist/public/tools-DvckJZG2.js +1 -0
- package/dist/server.js +188 -188
- package/package.json +3 -1
- package/src/components/shadow-claw-a2ui/shadow-claw-a2ui.stories.ts +1380 -93
- package/src/components/shadow-claw-a2ui/shadow-claw-a2ui.ts +11 -6
- package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.test.ts +8 -1
- package/src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.ts +13 -5
- package/src/components/shadow-claw-pages/utils/buildHtmlPageSrcdoc.ts +13 -5
- package/src/core/control-plane-client.ts +15 -0
- package/src/core/utils/initControlPlane.test.ts +187 -0
- package/src/core/utils/initControlPlane.ts +194 -20
- package/src/security/custom-element-security.test.ts +51 -0
- package/src/security/custom-element-security.ts +33 -15
- package/src/server/control-plane-types.ts +1 -0
- package/src/server/control-plane.test.ts +69 -0
- package/src/server/control-plane.ts +45 -3
- package/src/server/mcp/tools/built-in-tools.ts +80 -5
- package/src/server/mcp/tools/client-tool-relay.ts +183 -26
- package/src/server/mcp/tools/mcp-tools.test.ts +140 -0
- package/src/server/middleware/static-files.test.ts +142 -0
- package/src/server/middleware/static-files.ts +66 -8
- package/src/testing/jest-setup.ts +14 -0
- package/src/worker/utils/handleMessage.ts +4 -1
- package/dist/lib/initControlPlane-CsO4UR6_.js.map +0 -1
- package/dist/lib/readGroupFileBytes-Bve-e5e_.js.map +0 -1
- package/dist/lib/shadow-claw-file-viewer-BfDHHgpA.js.map +0 -1
- package/dist/lib/shadow-claw-pages-D54jF1Qq.js.map +0 -1
- package/dist/lib/trusted-types-CkLDpLiZ.js.map +0 -1
- package/dist/public/custom-element-security-NCqQ5lmC.js +0 -1
- package/dist/public/downloadGroupFile-G0BZQgQg.js +0 -1
- package/dist/public/effect-rHYr4nfu.js +0 -1
- package/dist/public/file-viewer-8PdCURDD.js +0 -1
- package/dist/public/initControlPlane-CcGXax0A.js +0 -1
- package/dist/public/peerjs-BZdxWQFv.js +0 -1
- package/dist/public/syncWebMcpRegistration-DD42YsYV.js +0 -1
- package/dist/public/toast-HAq8XWFj.js +0 -58
|
@@ -20,17 +20,18 @@ function isSpaShellRequest(req: Request, pathname: string): boolean {
|
|
|
20
20
|
return false;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const
|
|
23
|
+
const headers = req.headers || {};
|
|
24
|
+
const fetchDest = String(headers["sec-fetch-dest"] || "").toLowerCase();
|
|
24
25
|
if (fetchDest && fetchDest !== "document") {
|
|
25
26
|
return false;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
const fetchMode = String(
|
|
29
|
-
const fetchUser = String(
|
|
29
|
+
const fetchMode = String(headers["sec-fetch-mode"] || "").toLowerCase();
|
|
30
|
+
const fetchUser = String(headers["sec-fetch-user"] || "").toLowerCase();
|
|
30
31
|
const isNavigationFetch =
|
|
31
32
|
fetchDest === "document" || fetchMode === "navigate" || fetchUser === "?1";
|
|
32
33
|
|
|
33
|
-
const accept = String(
|
|
34
|
+
const accept = String(headers.accept || "");
|
|
34
35
|
if (!isNavigationFetch && !accept.includes("text/html")) {
|
|
35
36
|
return false;
|
|
36
37
|
}
|
|
@@ -45,6 +46,38 @@ function isSpaShellRequest(req: Request, pathname: string): boolean {
|
|
|
45
46
|
return SPA_ROUTE_PREFIXES.has(firstSegment);
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
const ALLOWED_ROOT_DOT_DIRS = new Set([".well-known", ".agents"]);
|
|
50
|
+
|
|
51
|
+
function isAllowedDotFileRequest(pathname: string): boolean {
|
|
52
|
+
const segments = pathname.split("/").filter(Boolean);
|
|
53
|
+
const dotSegments = segments.filter(
|
|
54
|
+
(segment) => segment.length > 0 && segment.startsWith("."),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
if (dotSegments.length === 0) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (dotSegments.length !== 1) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const singleDot = dotSegments[0];
|
|
66
|
+
if (!ALLOWED_ROOT_DOT_DIRS.has(singleDot)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return segments[0] === singleDot || segments[1] === singleDot;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function hasAllowedDotSegment(pathname: string): boolean {
|
|
74
|
+
const segments = pathname.split("/").filter(Boolean);
|
|
75
|
+
return (
|
|
76
|
+
(segments.length > 0 && ALLOWED_ROOT_DOT_DIRS.has(segments[0])) ||
|
|
77
|
+
(segments.length > 1 && ALLOWED_ROOT_DOT_DIRS.has(segments[1]))
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
48
81
|
export function registerStaticFilesMiddleware(app: Express, rootPath: string) {
|
|
49
82
|
app.use(expressUrlrewrite(/^(.+)\/index\.html$/, "$1/"));
|
|
50
83
|
|
|
@@ -53,6 +86,15 @@ export function registerStaticFilesMiddleware(app: Express, rootPath: string) {
|
|
|
53
86
|
res.setHeader("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS");
|
|
54
87
|
|
|
55
88
|
const requestPath = new URL(req.originalUrl, "http://localhost").pathname;
|
|
89
|
+
if (!isAllowedDotFileRequest(requestPath)) {
|
|
90
|
+
next();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const sendFileOptions = hasAllowedDotSegment(requestPath)
|
|
95
|
+
? { dotfiles: "allow" as const }
|
|
96
|
+
: undefined;
|
|
97
|
+
|
|
56
98
|
const isWebVMAsset =
|
|
57
99
|
requestPath.startsWith("/assets/v86.9pfs/") ||
|
|
58
100
|
requestPath.startsWith("/assets/v86.ext2/");
|
|
@@ -63,7 +105,8 @@ export function registerStaticFilesMiddleware(app: Express, rootPath: string) {
|
|
|
63
105
|
res.setHeader("Cache-Control", "no-cache");
|
|
64
106
|
}
|
|
65
107
|
|
|
66
|
-
const
|
|
108
|
+
const urlPathname = new URL(req.url || "/", "http://localhost").pathname;
|
|
109
|
+
const filePath = path.join(rootPath, urlPathname);
|
|
67
110
|
fs.stat(filePath, (err, stats) => {
|
|
68
111
|
if (err || !stats) {
|
|
69
112
|
if (isSpaShellRequest(req, requestPath)) {
|
|
@@ -81,7 +124,14 @@ export function registerStaticFilesMiddleware(app: Express, rootPath: string) {
|
|
|
81
124
|
fs.existsSync(strippedFilePath) &&
|
|
82
125
|
fs.statSync(strippedFilePath).isFile()
|
|
83
126
|
) {
|
|
84
|
-
|
|
127
|
+
const strippedOptions = hasAllowedDotSegment(strippedSegmentPath)
|
|
128
|
+
? { dotfiles: "allow" as const }
|
|
129
|
+
: undefined;
|
|
130
|
+
if (strippedOptions) {
|
|
131
|
+
res.sendFile(strippedFilePath, strippedOptions);
|
|
132
|
+
} else {
|
|
133
|
+
res.sendFile(strippedFilePath);
|
|
134
|
+
}
|
|
85
135
|
|
|
86
136
|
return;
|
|
87
137
|
}
|
|
@@ -151,13 +201,21 @@ export function registerStaticFilesMiddleware(app: Express, rootPath: string) {
|
|
|
151
201
|
const indexPath = path.join(filePath, "index.html");
|
|
152
202
|
fs.access(indexPath, fs.constants.F_OK, (err2) => {
|
|
153
203
|
if (!err2) {
|
|
154
|
-
|
|
204
|
+
if (sendFileOptions) {
|
|
205
|
+
res.sendFile(indexPath, sendFileOptions);
|
|
206
|
+
} else {
|
|
207
|
+
res.sendFile(indexPath);
|
|
208
|
+
}
|
|
155
209
|
} else {
|
|
156
210
|
next();
|
|
157
211
|
}
|
|
158
212
|
});
|
|
159
213
|
} else {
|
|
160
|
-
|
|
214
|
+
if (sendFileOptions) {
|
|
215
|
+
res.sendFile(filePath, sendFileOptions);
|
|
216
|
+
} else {
|
|
217
|
+
res.sendFile(filePath);
|
|
218
|
+
}
|
|
161
219
|
}
|
|
162
220
|
});
|
|
163
221
|
});
|
|
@@ -565,6 +565,9 @@ const expectedLogs = [
|
|
|
565
565
|
"Ollama models discovery error:",
|
|
566
566
|
"Failed to check Prompt API onboarding:",
|
|
567
567
|
"[webrtc-listen]",
|
|
568
|
+
"[ShadowClaw MCP]",
|
|
569
|
+
"fatal: not a git repository",
|
|
570
|
+
"Stopping at filesystem boundary",
|
|
568
571
|
];
|
|
569
572
|
|
|
570
573
|
function isExpectedLog(...args: any[]) {
|
|
@@ -576,6 +579,17 @@ function isExpectedLog(...args: any[]) {
|
|
|
576
579
|
return expectedLogs.some((expected) => str.includes(expected));
|
|
577
580
|
}
|
|
578
581
|
|
|
582
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
583
|
+
(process.stderr as any).write = (chunk: any, ...args: any[]): boolean => {
|
|
584
|
+
const str = typeof chunk === "string" ? chunk : (chunk?.toString?.() ?? "");
|
|
585
|
+
if (isExpectedLog(str)) {
|
|
586
|
+
const cb = args.find((a) => typeof a === "function");
|
|
587
|
+
if (cb) cb();
|
|
588
|
+
return true;
|
|
589
|
+
}
|
|
590
|
+
return (originalStderrWrite as any)(chunk, ...args);
|
|
591
|
+
};
|
|
592
|
+
|
|
579
593
|
console.error = (...args: any[]) => {
|
|
580
594
|
if (isExpectedLog(...args)) return;
|
|
581
595
|
originalConsoleError(...args);
|
|
@@ -23,7 +23,7 @@ import { handleCompact } from "./handleCompact.js";
|
|
|
23
23
|
import { handleInvoke } from "./handleInvoke.js";
|
|
24
24
|
import { pendingTasks } from "./pendingTasks.js";
|
|
25
25
|
import { post } from "./post.js";
|
|
26
|
-
import { setToolState } from "./tool-state.js";
|
|
26
|
+
import { getToolState, setToolState } from "./tool-state.js";
|
|
27
27
|
import { resolveMcpReauth } from "../tools/remote-mcp/utils/resolveMcpReauth.js";
|
|
28
28
|
|
|
29
29
|
/** In-flight abort controllers for group tasks */
|
|
@@ -570,11 +570,14 @@ export async function handleMessage(event: MessageEvent): Promise<void> {
|
|
|
570
570
|
|
|
571
571
|
case "execute-tool":
|
|
572
572
|
try {
|
|
573
|
+
const toolState = getToolState(payload.groupId);
|
|
574
|
+
const allowedTools = toolState?.enabledTools;
|
|
573
575
|
const result = await executeTool(
|
|
574
576
|
db,
|
|
575
577
|
payload.name,
|
|
576
578
|
payload.input,
|
|
577
579
|
payload.groupId,
|
|
580
|
+
{ allowedTools },
|
|
578
581
|
);
|
|
579
582
|
(self as any).postMessage({
|
|
580
583
|
type: "execute-tool-result",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"initControlPlane-CsO4UR6_.js","names":["process"],"sources":["../../src/core/control-plane-client.ts","../../src/core/utils/initControlPlane.ts"],"sourcesContent":["/**\n * ShadowClaw — Browser Control Plane Client\n *\n * Supports dual transport:\n * 1. \"sse\" (default): HTTP Server-Sent Events (GET /api/control/events) for\n * server-to-client commands + HTTP POST (/api/control/messages) for client-to-server.\n * Highly proxy-, CDN-, and firewall-compatible.\n * 2. \"websocket\": Full-duplex WebSocket connection to `/ws/control`.\n */\n\nimport type {\n ControlMessage,\n ClientRegisterPayload,\n HeartbeatPayload,\n CommandExecutePayload,\n CommandResultPayload,\n ControlPlaneTransport,\n} from \"../server/control-plane-types.js\";\nimport { ulid } from \"../utils/ulid.js\";\n\nexport type CommandHandler = (args: any) => Promise<any> | any;\n\nexport interface ControlPlaneClientOptions {\n transport?: ControlPlaneTransport;\n url?: string;\n httpUrl?: string;\n token?: string;\n clientId: string;\n deviceLabel?: string;\n capabilities?: string[];\n version?: string;\n peerId?: string;\n heartbeatIntervalMs?: number;\n reconnectDelayMs?: number;\n maxReconnectDelayMs?: number;\n handlers?: Record<string, CommandHandler>;\n WebSocketClass?: any;\n EventSourceClass?: any;\n fetchFn?: typeof fetch;\n}\n\nexport class ControlPlaneClient {\n private _transport: ControlPlaneTransport;\n private _url: string;\n private _httpUrl: string;\n private _token?: string;\n private _clientId: string;\n private _peerId?: string;\n private _deviceLabel: string;\n private _capabilities: string[];\n private _version: string;\n private _heartbeatIntervalMs: number;\n private _reconnectDelayMs: number;\n private _maxReconnectDelayMs: number;\n private _handlers: Map<string, CommandHandler>;\n private _WebSocketClass: any;\n private _EventSourceClass: any;\n private _fetchFn: typeof fetch;\n\n private _ws: WebSocket | null = null;\n private _es: any = null;\n private _heartbeatTimer: any = null;\n private _reconnectTimer: any = null;\n private _currentReconnectDelay: number;\n private _isDestroyed: boolean = false;\n private _state: \"disconnected\" | \"connecting\" | \"connected\" = \"disconnected\";\n\n constructor(options: ControlPlaneClientOptions) {\n this._transport = options.transport || \"sse\";\n this._clientId = options.clientId;\n this._peerId = options.peerId;\n this._deviceLabel = options.deviceLabel || \"ShadowClaw Browser Client\";\n this._capabilities = options.capabilities || [\"webmcp\", \"opfs\", \"push\"];\n this._version = options.version || \"1.23.4\";\n this._token = options.token;\n this._heartbeatIntervalMs = options.heartbeatIntervalMs || 10000;\n this._reconnectDelayMs = options.reconnectDelayMs || 1000;\n this._maxReconnectDelayMs = options.maxReconnectDelayMs || 30000;\n this._currentReconnectDelay = this._reconnectDelayMs;\n this._handlers = new Map();\n\n this._WebSocketClass =\n options.WebSocketClass ||\n (typeof WebSocket !== \"undefined\" ? WebSocket : null);\n this._EventSourceClass =\n options.EventSourceClass ||\n (typeof EventSource !== \"undefined\" ? EventSource : null);\n this._fetchFn =\n options.fetchFn ||\n (typeof fetch !== \"undefined\"\n ? fetch.bind(globalThis)\n : ((() => Promise.reject(new Error(\"fetch not available\"))) as any));\n\n if (options.handlers) {\n for (const [action, handler] of Object.entries(options.handlers)) {\n this.registerHandler(action, handler);\n }\n }\n\n const loc = typeof location !== \"undefined\" ? location : null;\n const origin = loc\n ? `${loc.protocol}//${loc.host}`\n : \"http://127.0.0.1:8888\";\n const wsOrigin = loc\n ? `${loc.protocol === \"https:\" ? \"wss:\" : \"ws:\"}//${loc.host}`\n : \"ws://127.0.0.1:8888\";\n\n this._url = options.url || `${wsOrigin}/ws/control`;\n this._httpUrl = options.httpUrl || origin;\n }\n\n public get transport(): ControlPlaneTransport {\n return this._transport;\n }\n\n public registerHandler(action: string, handler: CommandHandler): void {\n this._handlers.set(action, handler);\n }\n\n public unregisterHandler(action: string): void {\n this._handlers.delete(action);\n }\n\n public getState(): \"disconnected\" | \"connecting\" | \"connected\" {\n return this._state;\n }\n\n public connect(): void {\n if (\n this._isDestroyed ||\n this._state === \"connected\" ||\n this._state === \"connecting\"\n ) {\n return;\n }\n\n if (this._transport === \"websocket\") {\n this._connectWebSocket();\n } else {\n this._connectSse();\n }\n }\n\n private _connectWebSocket(): void {\n if (!this._WebSocketClass) {\n console.warn(\n \"[ControlPlaneClient] WebSocket not supported in this environment\",\n );\n return;\n }\n\n this._state = \"connecting\";\n const wsUrl = new URL(this._url, \"ws://127.0.0.1:8888\");\n if (this._token) {\n wsUrl.searchParams.set(\"token\", this._token);\n }\n\n try {\n const ws = new this._WebSocketClass(wsUrl.toString());\n this._ws = ws;\n\n ws.onopen = () => {\n this._state = \"connected\";\n this._currentReconnectDelay = this._reconnectDelayMs;\n this._sendRegister();\n this._startHeartbeat();\n };\n\n ws.onmessage = (event: MessageEvent) => {\n this._handleMessage(event.data);\n };\n\n ws.onclose = () => {\n this._cleanupConnection();\n if (!this._isDestroyed) {\n this._scheduleReconnect();\n }\n };\n\n ws.onerror = (err: any) => {\n console.warn(\"[ControlPlaneClient] WebSocket error:\", err);\n };\n } catch (err) {\n console.warn(\n \"[ControlPlaneClient] Failed to establish WebSocket connection:\",\n err,\n );\n this._cleanupConnection();\n this._scheduleReconnect();\n }\n }\n\n private _connectSse(): void {\n if (!this._EventSourceClass) {\n if (typeof process === \"undefined\" || !process.env?.JEST_WORKER_ID) {\n console.warn(\n \"[ControlPlaneClient] EventSource not supported in this environment\",\n );\n }\n return;\n }\n\n this._state = \"connecting\";\n const sseUrl = new URL(\"/api/control/events\", this._httpUrl);\n sseUrl.searchParams.set(\"clientId\", this._clientId);\n if (this._token) {\n sseUrl.searchParams.set(\"token\", this._token);\n }\n\n try {\n const es = new this._EventSourceClass(sseUrl.toString());\n this._es = es;\n\n es.onopen = () => {\n this._state = \"connected\";\n this._currentReconnectDelay = this._reconnectDelayMs;\n this._sendRegister();\n this._startHeartbeat();\n };\n\n if (typeof es.addEventListener === \"function\") {\n es.addEventListener(\"command:execute\", (event: MessageEvent) => {\n this._handleMessage(event.data);\n });\n }\n\n es.onmessage = (event: MessageEvent) => {\n this._handleMessage(event.data);\n };\n\n es.onerror = (err: any) => {\n console.warn(\"[ControlPlaneClient] SSE connection error:\", err);\n this._cleanupConnection();\n if (!this._isDestroyed) {\n this._scheduleReconnect();\n }\n };\n } catch (err) {\n console.warn(\n \"[ControlPlaneClient] Failed to establish SSE connection:\",\n err,\n );\n this._cleanupConnection();\n this._scheduleReconnect();\n }\n }\n\n public disconnect(): void {\n this._isDestroyed = true;\n this._cleanupConnection();\n if (this._reconnectTimer) {\n clearTimeout(this._reconnectTimer);\n this._reconnectTimer = null;\n }\n }\n\n private _cleanupConnection(): void {\n this._state = \"disconnected\";\n this._stopHeartbeat();\n if (this._ws) {\n try {\n this._ws.close();\n } catch (_) {}\n this._ws = null;\n }\n if (this._es) {\n try {\n this._es.close();\n } catch (_) {}\n this._es = null;\n }\n }\n\n private _scheduleReconnect(): void {\n if (this._reconnectTimer || this._isDestroyed) {\n return;\n }\n\n this._reconnectTimer = setTimeout(() => {\n this._reconnectTimer = null;\n if (!this._isDestroyed) {\n this.connect();\n }\n }, this._currentReconnectDelay);\n\n this._currentReconnectDelay = Math.min(\n this._currentReconnectDelay * 1.5,\n this._maxReconnectDelayMs,\n );\n }\n\n private _startHeartbeat(): void {\n this._stopHeartbeat();\n this._heartbeatTimer = setInterval(() => {\n this._sendHeartbeat();\n }, this._heartbeatIntervalMs);\n }\n\n private _stopHeartbeat(): void {\n if (this._heartbeatTimer) {\n clearInterval(this._heartbeatTimer);\n this._heartbeatTimer = null;\n }\n }\n\n private _sendRegister(): void {\n const payload: ClientRegisterPayload = {\n clientId: this._clientId,\n deviceLabel: this._deviceLabel,\n capabilities: this._capabilities,\n version: this._version,\n transport: this._transport,\n peerId: this._peerId,\n };\n this._sendMessage({\n id: ulid(),\n type: \"client:register\",\n payload,\n });\n }\n\n private _sendHeartbeat(): void {\n const payload: HeartbeatPayload = {\n clientId: this._clientId,\n timestamp: Date.now(),\n };\n this._sendMessage({\n id: ulid(),\n type: \"client:heartbeat\",\n payload,\n });\n }\n\n private _sendMessage(msg: ControlMessage): void {\n if (this._transport === \"websocket\") {\n if (\n this._ws &&\n (this._ws.readyState === 1 ||\n this._ws.readyState === (this._WebSocketClass as any)?.OPEN)\n ) {\n this._ws.send(JSON.stringify(msg));\n }\n return;\n }\n\n // SSE Mode: send messages to server via HTTP POST /api/control/messages\n const messagesUrl = new URL(\"/api/control/messages\", this._httpUrl);\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (this._token) {\n headers[\"x-control-token\"] = this._token;\n headers[\"Authorization\"] = `Bearer ${this._token}`;\n }\n\n const fetchOptions: any = {\n method: \"POST\",\n headers,\n body: JSON.stringify(msg),\n };\n\n const host = messagesUrl.hostname.toLowerCase();\n const isLoopback =\n host === \"localhost\" ||\n host === \"127.0.0.1\" ||\n host === \"::1\" ||\n host === \"[::1]\";\n const isPrivate = /^(10\\.|172\\.(1[6-9]|2\\d|3[01])\\.|192\\.168\\.)/.test(host);\n\n if (isLoopback) {\n fetchOptions.targetAddressSpace = \"loopback\";\n } else if (isPrivate) {\n fetchOptions.targetAddressSpace = \"private\";\n }\n\n this._fetchFn(messagesUrl.toString(), fetchOptions).catch((err) => {\n console.warn(\n \"[ControlPlaneClient] Failed to send message via HTTP POST:\",\n err,\n );\n });\n }\n\n private async _handleMessage(dataStr: string): Promise<void> {\n if (!dataStr || typeof dataStr !== \"string\") {\n return;\n }\n\n let msg: ControlMessage;\n try {\n msg = JSON.parse(dataStr);\n } catch {\n return;\n }\n\n if (msg.type === \"command:execute\") {\n const payload = msg.payload as CommandExecutePayload;\n const { commandId, action, args } = payload;\n\n const handler = this._handlers.get(action);\n if (!handler) {\n this._sendMessage({\n id: ulid(),\n type: \"command:result\",\n replyTo: msg.id,\n payload: {\n commandId,\n success: false,\n error: `Unknown action: ${action}`,\n } as CommandResultPayload,\n });\n return;\n }\n\n try {\n const result = await handler(args);\n this._sendMessage({\n id: ulid(),\n type: \"command:result\",\n replyTo: msg.id,\n payload: {\n commandId,\n success: true,\n data: result,\n } as CommandResultPayload,\n });\n } catch (err: any) {\n this._sendMessage({\n id: ulid(),\n type: \"command:result\",\n replyTo: msg.id,\n payload: {\n commandId,\n success: false,\n error: err.message || String(err),\n } as CommandResultPayload,\n });\n }\n }\n }\n}\n","/**\n * ShadowClaw — Control Plane Browser Initialization Helper\n */\n\nimport { ControlPlaneClient } from \"../control-plane-client.js\";\nimport { getDeploymentNamespace } from \"../app-routes.js\";\nimport { getDb } from \"../../db/db.js\";\nimport { getAllTasks } from \"../../db/getAllTasks.js\";\nimport { ulid } from \"../../utils/ulid.js\";\nimport {\n CONFIG_KEYS,\n DEFAULT_CONTROL_PLANE_ENABLED,\n DEFAULT_CONTROL_PLANE_TRANSPORT,\n} from \"../../config/config.js\";\nimport type { ControlPlaneTransport } from \"../../server/control-plane-types.js\";\n\nexport function getOrCreateControlPlaneClientId(): string {\n if (typeof localStorage !== \"undefined\") {\n try {\n const stored = localStorage.getItem(CONFIG_KEYS.CONTROL_PLANE_CLIENT_ID);\n if (stored && stored.trim()) {\n return stored.trim();\n }\n } catch (_) {}\n }\n\n const namespace = getDeploymentNamespace();\n const generated = namespace\n ? `${namespace}-${ulid().toLowerCase()}`\n : `client-${ulid().toLowerCase()}`;\n\n if (typeof localStorage !== \"undefined\") {\n try {\n localStorage.setItem(CONFIG_KEYS.CONTROL_PLANE_CLIENT_ID, generated);\n } catch (_) {}\n }\n\n return generated;\n}\n\nexport function isControlPlaneEnabledSync(): boolean {\n if (typeof localStorage !== \"undefined\") {\n try {\n const val = localStorage.getItem(CONFIG_KEYS.CONTROL_PLANE_ENABLED);\n if (val !== null) {\n return val === \"true\" || val === \"1\";\n }\n } catch (_) {}\n }\n return DEFAULT_CONTROL_PLANE_ENABLED;\n}\n\nexport async function isControlPlaneEnabled(db?: any): Promise<boolean> {\n if (typeof localStorage !== \"undefined\") {\n try {\n const val = localStorage.getItem(CONFIG_KEYS.CONTROL_PLANE_ENABLED);\n if (val !== null) {\n return val === \"true\" || val === \"1\";\n }\n } catch (_) {}\n }\n\n if (db) {\n try {\n const { getConfig } = await import(\"../../db/getConfig.js\");\n const val = await getConfig(db, CONFIG_KEYS.CONTROL_PLANE_ENABLED);\n if (val !== null && val !== undefined) {\n return val === \"true\" || val === \"1\";\n }\n } catch (_) {}\n }\n\n return DEFAULT_CONTROL_PLANE_ENABLED;\n}\n\nexport function shouldConnectControlPlane(loc?: {\n protocol?: string;\n hostname?: string;\n}): boolean {\n if (typeof EventSource === \"undefined\" && typeof WebSocket === \"undefined\") {\n return false;\n }\n\n const currentLoc = loc || (typeof location !== \"undefined\" ? location : null);\n if (!currentLoc) {\n return false;\n }\n\n if (currentLoc.protocol === \"file:\") {\n return false;\n }\n\n if (\n typeof document !== \"undefined\" &&\n document.querySelector('meta[name=\"shadowclaw-static-only\"]')\n ) {\n return false;\n }\n\n return true;\n}\n\nexport function getControlPlaneServerUrl(loc?: {\n protocol?: string;\n host?: string;\n hostname?: string;\n}): { httpUrl: string; wsUrl: string } {\n let customUrl = \"\";\n if (typeof localStorage !== \"undefined\") {\n try {\n customUrl = (\n localStorage.getItem(CONFIG_KEYS.CONTROL_PLANE_URL) || \"\"\n ).trim();\n } catch (_) {}\n }\n\n const currentLoc = loc || (typeof location !== \"undefined\" ? location : null);\n const isStaticHost =\n currentLoc &&\n (currentLoc.protocol === \"file:\" ||\n (currentLoc.hostname &&\n (currentLoc.hostname.endsWith(\".github.io\") ||\n currentLoc.hostname.endsWith(\".pages.dev\"))));\n\n let baseHttp = customUrl;\n if (!baseHttp) {\n if (isStaticHost) {\n baseHttp = \"http://127.0.0.1:8888\";\n } else if (currentLoc && currentLoc.host) {\n baseHttp = `${currentLoc.protocol}//${currentLoc.host}`;\n } else {\n baseHttp = \"http://127.0.0.1:8888\";\n }\n }\n\n baseHttp = baseHttp.replace(/\\/+$/, \"\");\n\n const baseWs = baseHttp.replace(/^https?:/, (proto) =>\n proto === \"https:\" ? \"wss:\" : \"ws:\",\n );\n\n return {\n httpUrl: baseHttp,\n wsUrl: `${baseWs}/ws/control`,\n };\n}\n\nexport function detectCapabilities(): string[] {\n const caps: string[] = [];\n\n if (typeof navigator !== \"undefined\") {\n if (\n navigator.storage &&\n typeof navigator.storage.getDirectory === \"function\"\n ) {\n caps.push(\"opfs\");\n }\n\n if (\n \"serviceWorker\" in navigator &&\n typeof window !== \"undefined\" &&\n \"PushManager\" in window\n ) {\n caps.push(\"push\");\n }\n\n if (\n (typeof document !== \"undefined\" && (document as any).modelContext) ||\n ((navigator as any) && (navigator as any).modelContext)\n ) {\n caps.push(\"webmcp\");\n }\n }\n\n if (typeof RTCPeerConnection !== \"undefined\") {\n caps.push(\"peerjs\");\n }\n\n return caps;\n}\n\nexport function detectDeviceLabel(): string {\n if (typeof navigator === \"undefined\") {\n return \"ShadowClaw Node\";\n }\n\n const ua = navigator.userAgent;\n let device = \"Desktop\";\n if (/iPad/i.test(ua)) device = \"iPad\";\n else if (/iPhone/i.test(ua)) device = \"iPhone\";\n else if (/Android/i.test(ua)) device = \"Android\";\n else if (/Macintosh/i.test(ua)) device = \"Mac\";\n else if (/Windows/i.test(ua)) device = \"Windows\";\n else if (/Linux/i.test(ua)) device = \"Linux\";\n\n let browser = \"Browser\";\n if (/Chrome/i.test(ua) && !/Edg/i.test(ua)) browser = \"Chrome\";\n else if (/Safari/i.test(ua) && !/Chrome/i.test(ua)) browser = \"Safari\";\n else if (/Firefox/i.test(ua)) browser = \"Firefox\";\n else if (/Edg/i.test(ua)) browser = \"Edge\";\n\n return `${device} ${browser}`;\n}\n\nexport interface InitControlPlaneOptions {\n orchestrator?: any;\n clientId?: string;\n transport?: ControlPlaneTransport;\n autoConnect?: boolean;\n}\n\nlet activeClient: ControlPlaneClient | null = null;\n\nexport async function executeClientControlCommand(\n action: string,\n args: any = {},\n options: InitControlPlaneOptions = {},\n): Promise<any> {\n const clientId = getOrCreateControlPlaneClientId();\n const deviceLabel = detectDeviceLabel();\n const capabilities = detectCapabilities();\n\n switch (action) {\n case \"send-message\": {\n if (!args.text) {\n throw new Error(\"Missing text parameter\");\n }\n const { orchestratorStore } =\n await import(\"../../stores/orchestrator.js\");\n const orch = options.orchestrator || orchestratorStore.orchestrator;\n const targetGroupId =\n args.groupId || orchestratorStore.activeGroupId || \"br:main\";\n\n if (orch?.browserChat?.submit) {\n orch.browserChat.submit(args.text, targetGroupId);\n return { queued: true, groupId: targetGroupId };\n }\n if (orch?.submitMessage) {\n orch.submitMessage(args.text, targetGroupId);\n return { queued: true, groupId: targetGroupId };\n }\n if (orchestratorStore.sendMessage) {\n orchestratorStore.sendMessage(args.text);\n return { queued: true, groupId: targetGroupId };\n }\n return { queued: false, error: \"Orchestrator not ready\" };\n }\n\n case \"list-tasks\": {\n const db = await getDb();\n let tasks = await getAllTasks(db);\n if (args?.groupId) {\n tasks = tasks.filter((t) => t.groupId === args.groupId);\n }\n return { tasks };\n }\n\n case \"read-state\": {\n const { orchestratorStore } =\n await import(\"../../stores/orchestrator.js\");\n const orch = options.orchestrator || orchestratorStore.orchestrator;\n return {\n clientId,\n deviceLabel,\n capabilities,\n activeGroupId:\n options.orchestrator?.activeGroupId ||\n orchestratorStore.activeGroupId ||\n orch?.activeGroupId ||\n \"br:main\",\n state:\n options.orchestrator?.state ||\n orchestratorStore.state ||\n orch?.state ||\n \"idle\",\n };\n }\n\n case \"list-tools\": {\n try {\n const { getWebMcpTools } =\n await import(\"../../subsystems/mcp/webmcp.js\");\n const webMcpTools = await getWebMcpTools();\n if (webMcpTools && webMcpTools.length > 0) {\n return {\n tools: webMcpTools.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n annotations: t.annotations,\n })),\n };\n }\n } catch (_) {}\n\n // Fallback: list built-in TOOL_DEFINITIONS\n const { TOOL_DEFINITIONS } =\n await import(\"../../subsystems/tools/index.js\");\n const { parseWebMcpInputSchema } =\n await import(\"../../subsystems/mcp/webmcp.js\");\n return {\n tools: TOOL_DEFINITIONS.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: parseWebMcpInputSchema(t.input_schema),\n })),\n };\n }\n\n case \"invoke-tool\": {\n if (!args.toolName) {\n throw new Error(\"Missing toolName parameter\");\n }\n const ctx =\n (typeof document !== \"undefined\" && (document as any).modelContext) ||\n (typeof navigator !== \"undefined\" && (navigator as any).modelContext);\n\n if (ctx) {\n if (typeof ctx.getTools === \"function\") {\n try {\n const tools = await ctx.getTools();\n const tool = Array.isArray(tools)\n ? tools.find((t: any) => t.name === args.toolName)\n : undefined;\n if (tool && typeof tool.execute === \"function\") {\n const res = await tool.execute(args.input || {});\n return { result: res };\n }\n } catch (_) {}\n }\n if (typeof ctx.executeTool === \"function\") {\n const res = await ctx.executeTool(\n { name: args.toolName },\n typeof args.input === \"string\"\n ? args.input\n : JSON.stringify(args.input || {}),\n );\n return { result: res };\n }\n if (typeof ctx.invoke === \"function\") {\n const res = await ctx.invoke(args.toolName, args.input || {});\n return { result: res };\n }\n }\n\n // Worker fallback if agent worker is active\n const { orchestratorStore } =\n await import(\"../../stores/orchestrator.js\");\n const orch = options.orchestrator || orchestratorStore.orchestrator;\n const worker: any = orch?.agentWorker;\n if (worker && typeof worker.postMessage === \"function\") {\n const callId =\n Date.now().toString(36) + Math.random().toString(36).slice(2);\n const result = await new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n worker.removeEventListener(\"message\", handler);\n reject(new Error(\"Timeout waiting for tool execution\"));\n }, 60000);\n\n const handler = (event: MessageEvent) => {\n const data = event.data;\n if (\n data &&\n data.type === \"execute-tool-result\" &&\n data.callId === callId\n ) {\n clearTimeout(timeout);\n worker.removeEventListener(\"message\", handler);\n if (data.error) {\n reject(new Error(data.error));\n } else {\n resolve(data.result);\n }\n }\n };\n\n worker.addEventListener(\"message\", handler);\n worker.postMessage({\n type: \"execute-tool\",\n callId,\n payload: {\n name: args.toolName,\n input: args.input || {},\n groupId: args.groupId || orch.activeGroupId || \"br:main\",\n },\n });\n });\n return { result };\n }\n\n throw new Error(\n `Tool ${args.toolName} could not be executed (no context or worker available)`,\n );\n }\n\n case \"trigger-backup\": {\n const { orchestratorStore } =\n await import(\"../../stores/orchestrator.js\");\n const targetGroupId =\n args.groupId ||\n options.orchestrator?.activeGroupId ||\n orchestratorStore.activeGroupId ||\n \"br:main\";\n const db = await getDb();\n const { getGroupDir } = await import(\"../../storage/getGroupDir.js\");\n const groupDir = await getGroupDir(db, targetGroupId);\n\n async function collectFiles(\n dir: FileSystemDirectoryHandle,\n prefix = \"\",\n ): Promise<string[]> {\n const result: string[] = [];\n for await (const [name, handle] of (dir as any).entries()) {\n const relPath = prefix ? `${prefix}/${name}` : name;\n if (handle.kind === \"directory\") {\n const sub = await collectFiles(handle, relPath);\n result.push(...sub);\n } else {\n result.push(relPath);\n }\n }\n return result;\n }\n\n async function readFile(relPath: string): Promise<Uint8Array | null> {\n try {\n const parts = relPath.split(\"/\");\n let cur: FileSystemDirectoryHandle = groupDir;\n for (let i = 0; i < parts.length - 1; i++) {\n cur = await cur.getDirectoryHandle(parts[i]);\n }\n const fileHandle = await cur.getFileHandle(parts[parts.length - 1]);\n const file = await fileHandle.getFile();\n const buffer = await file.arrayBuffer();\n return new Uint8Array(buffer);\n } catch {\n return null;\n }\n }\n\n const { BackupController } = await import(\"../backup-controller.js\");\n\n const backupCtrl = new BackupController({\n clientId,\n token: args.token,\n serverBaseUrl: getControlPlaneServerUrl().httpUrl,\n fileEnumerator: () => collectFiles(groupDir),\n fileReader: (filePath) => readFile(filePath),\n });\n\n const result = await backupCtrl.initiate();\n return result;\n }\n\n default:\n throw new Error(`Unknown action '${action}'`);\n }\n}\n\nexport function createDefaultControlPlaneClient(\n options: InitControlPlaneOptions = {},\n): ControlPlaneClient {\n if (activeClient) {\n try {\n activeClient.disconnect();\n } catch (_) {}\n activeClient = null;\n }\n\n const clientId =\n (options.clientId && options.clientId.trim()) ||\n getOrCreateControlPlaneClientId();\n const capabilities = detectCapabilities();\n const deviceLabel = detectDeviceLabel();\n\n let configuredTransport: ControlPlaneTransport | null = null;\n if (typeof localStorage !== \"undefined\") {\n try {\n const stored = localStorage.getItem(CONFIG_KEYS.CONTROL_PLANE_TRANSPORT);\n if (stored === \"sse\" || stored === \"websocket\") {\n configuredTransport = stored;\n }\n } catch (_) {}\n }\n\n const transport =\n options.transport ||\n configuredTransport ||\n (DEFAULT_CONTROL_PLANE_TRANSPORT as ControlPlaneTransport);\n\n let peerId: string | undefined;\n if (typeof localStorage !== \"undefined\") {\n try {\n // CONFIG_KEYS.PEERJS_MY_PEER_ID is \"peerjs_my_peer_id\" — set by configurePeerJs via setConfig.\n // We also check the raw IndexedDB config key written by setConfig, which mirrors to localStorage\n // under the same key name in browser environments that support it.\n peerId = localStorage.getItem(CONFIG_KEYS.PEERJS_MY_PEER_ID) || undefined;\n } catch (_) {}\n }\n\n const { httpUrl, wsUrl } = getControlPlaneServerUrl();\n\n const client = new ControlPlaneClient({\n clientId,\n deviceLabel,\n capabilities,\n peerId,\n transport,\n httpUrl,\n url: wsUrl,\n handlers: {\n \"send-message\": (args: any) =>\n executeClientControlCommand(\"send-message\", args, options),\n \"list-tasks\": (args: any) =>\n executeClientControlCommand(\"list-tasks\", args, options),\n \"read-state\": (args: any) =>\n executeClientControlCommand(\"read-state\", args, options),\n \"invoke-tool\": (args: any) =>\n executeClientControlCommand(\"invoke-tool\", args, options),\n \"list-tools\": (args: any) =>\n executeClientControlCommand(\"list-tools\", args, options),\n \"trigger-backup\": (args: any) =>\n executeClientControlCommand(\"trigger-backup\", args, options),\n },\n });\n\n if (options.autoConnect !== false && shouldConnectControlPlane()) {\n client.connect();\n }\n\n activeClient = client;\n return client;\n}\n\nexport function getActiveControlPlaneClient(): ControlPlaneClient | null {\n return activeClient;\n}\n\nexport function stopControlPlaneClient(): void {\n if (activeClient) {\n try {\n activeClient.disconnect();\n } catch (_) {}\n activeClient = null;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"readGroupFileBytes-Bve-e5e_.js","names":[],"sources":["../../src/storage/parsePath.ts","../../src/storage/readGroupFileBytes.ts"],"sourcesContent":["/**\n * Parse a path into directory segments and filename.\n */\nexport function parsePath(filePath: string): {\n dirs: string[];\n filename: string;\n} {\n const normalized = filePath\n .replace(/\\\\/g, \"/\")\n .replace(/^\\/home\\/user\\//, \"/\")\n .replace(/^\\/+/, \"\");\n const parts = normalized.split(\"/\").filter(Boolean);\n\n if (parts.length === 0) {\n throw new Error(\"Empty file path\");\n }\n\n const filename = parts.pop();\n\n return { dirs: parts, filename: filename || \"\" };\n}\n","import { getGroupDir } from \"./getGroupDir.js\";\nimport { parsePath } from \"./parsePath.js\";\nimport type { ShadowClawDatabase } from \"../db/types.js\";\n\n/**\n * Read raw bytes from a file in a group's workspace.\n */\nexport async function readGroupFileBytes(\n db: ShadowClawDatabase,\n groupId: string,\n filePath: string,\n): Promise<Uint8Array> {\n const groupDir = await getGroupDir(db, groupId);\n const { dirs, filename } = parsePath(filePath);\n\n let dir = groupDir;\n for (const seg of dirs) {\n dir = await dir.getDirectoryHandle(seg);\n }\n\n const fileHandle = await dir.getFileHandle(filename);\n\n try {\n const syncHandle = await (fileHandle as any).createSyncAccessHandle();\n const size = syncHandle.getSize();\n const buf = new Uint8Array(size);\n\n syncHandle.read(buf, { at: 0 });\n syncHandle.close();\n\n return buf;\n } catch {\n const file = await fileHandle.getFile();\n const arrayBuffer = await file.arrayBuffer();\n\n return new Uint8Array(arrayBuffer);\n }\n}\n"],"mappings":";;;;;;AAGA,SAAgB,UAAU,UAGxB;CAKA,MAAM,QAJa,SAChB,QAAQ,OAAO,GAAG,CAAC,CACnB,QAAQ,mBAAmB,GAAG,CAAC,CAC/B,QAAQ,QAAQ,EACI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO;CAElD,IAAI,MAAM,WAAW,GACnB,MAAM,IAAI,MAAM,iBAAiB;CAKnC,OAAO;EAAE,MAAM;EAAO,UAFL,MAAM,IAEgB,KAAK;CAAG;AACjD;;;;;;;ACbA,eAAsB,mBACpB,IACA,SACA,UACqB;CACrB,MAAM,WAAW,MAAM,YAAY,IAAI,OAAO;CAC9C,MAAM,EAAE,MAAM,aAAa,UAAU,QAAQ;CAE7C,IAAI,MAAM;CACV,KAAK,MAAM,OAAO,MAChB,MAAM,MAAM,IAAI,mBAAmB,GAAG;CAGxC,MAAM,aAAa,MAAM,IAAI,cAAc,QAAQ;CAEnD,IAAI;EACF,MAAM,aAAa,MAAO,WAAmB,uBAAuB;EACpE,MAAM,OAAO,WAAW,QAAQ;EAChC,MAAM,MAAM,IAAI,WAAW,IAAI;EAE/B,WAAW,KAAK,KAAK,EAAE,IAAI,EAAE,CAAC;EAC9B,WAAW,MAAM;EAEjB,OAAO;CACT,QAAQ;EAEN,MAAM,cAAc,OAAM,MADP,WAAW,QAAQ,EACR,CAAC,YAAY;EAE3C,OAAO,IAAI,WAAW,WAAW;CACnC;AACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"shadow-claw-file-viewer-BfDHHgpA.js","names":["shadowClawFileViewerStyles","shadowClawFileViewerTemplate","hljs"],"sources":["../../src/components/shadow-claw-file-viewer/shadow-claw-file-viewer.ts"],"sourcesContent":["import hljs from \"highlight.js\";\n\nimport { renderMarkdown } from \"../../content/markdown.js\";\nimport { splitFrontmatter } from \"../../common/utils/frontmatter.mjs\";\n\nimport { CONFIG_KEYS } from \"../../config/config.js\";\nimport {\n applyBasePath,\n getFileRouteDirPath,\n getWorkspaceRouteRequestPath,\n isPossibleAppRoute,\n resolveHrefAgainstRoute,\n} from \"../../core/app-routes.js\";\n\nimport { effect } from \"../../core/effect.js\";\nimport { getDb } from \"../../db/db.js\";\nimport { getConfig } from \"../../db/getConfig.js\";\n\nimport {\n sanitizeSrcdocHtml,\n setSanitizedHtml,\n setTrustedSrcdoc,\n toTrustedHtmlPresanitized,\n} from \"../../security/trusted-types.js\";\n\nimport { readGroupFileBytes } from \"../../storage/readGroupFileBytes.js\";\nimport { writeGroupFile } from \"../../storage/writeGroupFile.js\";\n\nimport { fileViewerStore } from \"../../stores/file-viewer.js\";\nimport { orchestratorStore } from \"../../stores/orchestrator.js\";\nimport { toolsStore } from \"../../stores/tools.js\";\n\nimport { showError, showSuccess } from \"../../ui/toast.js\";\nimport {\n getIframeHtmlClass,\n getIframeThemeStyleHtml,\n} from \"../../ui/iframe-theme.js\";\nimport { isTruthyConfigValue } from \"../../common/utils/config-value.mjs\";\n\nimport \"../shadow-claw-dialog/shadow-claw-dialog.js\";\nimport { IframeBroadcastProxy } from \"../shadow-claw-pages/utils/iframe-broadcast-proxy.js\";\nimport {\n iframeStorageClear,\n iframeStorageDelete,\n iframeStorageGet,\n iframeStorageGetAll,\n iframeStorageSet,\n} from \"../shadow-claw-pages/utils/iframe-storage-proxy.js\";\n\nimport type { Config } from \"dompurify\";\nimport type { ShadowClawDatabase } from \"../../db/types.js\";\n\nimport {\n getApprovedCustomElementScripts,\n getIframeCsp,\n getIframeSandboxPolicy,\n isAllowedCustomElement,\n} from \"../../security/custom-element-security.js\";\nimport ShadowClawElement from \"../shadow-claw-element.js\";\nimport shadowClawFileViewerStyles from \"./shadow-claw-file-viewer.css\" with { type: \"css\" };\nimport shadowClawFileViewerTemplate from \"./shadow-claw-file-viewer.html\" with { type: \"html\" };\n\nconst elementName = \"shadow-claw-file-viewer\";\nconst highlightThemePath = `components/${elementName}/highlightjs-atom-one-dark.min.css`;\nconst highlightFontOverrideCss =\n \"pre code.hljs, code.hljs, .hljs { font-family: var(--shadow-claw-font-mono) !important; }\";\n\nconst previewSanitizeOptions: Config = {\n // Allow blob URLs for locally resolved OPFS preview assets.\n ALLOWED_URI_REGEXP:\n /^(?:(?:https?|mailto|ftp|tel|file|blob|data):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i,\n ADD_TAGS: [\"iframe\", \"figure\", \"figcaption\"],\n CUSTOM_ELEMENT_HANDLING: {\n tagNameCheck: (tagName: string) => isAllowedCustomElement(tagName),\n attributeNameCheck: () => true,\n allowCustomizedBuiltInElements: false,\n },\n ADD_ATTR: [\n \"allow\",\n \"allowfullscreen\",\n \"frameborder\",\n \"scrolling\",\n \"referrerpolicy\",\n \"loading\",\n ],\n};\n\nfunction resolveFrontmatterToggle(\n db: ShadowClawDatabase | null,\n key: string,\n): boolean | Promise<boolean> {\n if (!db || typeof (db as any).transaction !== \"function\") {\n return true;\n }\n\n return getConfig(db, key)\n .then((value) => isTruthyConfigValue(value, true))\n .catch(() => true);\n}\n\n/**\n * ShadowClawFileViewer - component for viewing and editing files\n */\nexport class ShadowClawFileViewer extends ShadowClawElement {\n static styles = shadowClawFileViewerStyles;\n static template = shadowClawFileViewerTemplate;\n broadcastProxy: IframeBroadcastProxy | null = null;\n\n currentImageObjectUrls: string[] = [];\n currentObjectUrl: string | null = null;\n\n db: ShadowClawDatabase | null = null;\n editorDraftContent: string | null = null;\n\n isEditorDirty: boolean = false;\n isFileEditMode: boolean = false;\n\n isFilePreviewMode: boolean = false;\n isFullscreenMode: boolean = false;\n\n lastOpenedFileName: string = \"\";\n previewFrameWindow: Window | null = null;\n themeObserver: MutationObserver | null = null;\n viewRenderToken: number = 0;\n\n constructor() {\n super();\n }\n\n async connectedCallback() {\n const root = this.shadowRoot;\n if (!root) {\n throw new Error(\"shadowRoot not found\");\n }\n\n this.setupEffects();\n this.bindEventListeners();\n\n this.broadcastProxy = new IframeBroadcastProxy(\n () =>\n this.previewFrameWindow ||\n (\n this.shadowRoot?.querySelector(\n \".file-content-iframe\",\n ) as HTMLIFrameElement\n )?.contentWindow ||\n null,\n );\n\n window.addEventListener(\"message\", this.handleIframeMessage);\n document.addEventListener(\"fullscreenchange\", this.handleFullscreenChange);\n\n this.themeObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n if (m.type === \"attributes\" && m.attributeName === \"class\") {\n this.syncIframeTheme();\n }\n }\n });\n this.themeObserver.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n\n this.db = await getDb();\n\n // Apply highlight.js theme to markdown preview output in this shadow root.\n try {\n const hjsCss = await fetch(highlightThemePath).then((r) => r.text());\n this.applyHighlightStyles(hjsCss);\n } catch (err) {\n console.warn(\"Failed to load highlight.js styles:\", err);\n }\n }\n\n disconnectedCallback() {\n this.broadcastProxy?.dispose();\n this.broadcastProxy = null;\n window.removeEventListener(\"message\", this.handleIframeMessage);\n document.removeEventListener(\n \"fullscreenchange\",\n this.handleFullscreenChange,\n );\n if (this.themeObserver) {\n this.themeObserver.disconnect();\n this.themeObserver = null;\n }\n this.revokeObjectUrl();\n }\n\n applyFullscreenMode(modal: Element) {\n const modalContent = modal.querySelector(\".modal-content\");\n if (modalContent instanceof HTMLElement) {\n modalContent.classList.toggle(\n \"modal-content--fullscreen\",\n this.isFullscreenMode,\n );\n }\n\n const fullscreenBtn = modal.querySelector(\".modal-fullscreen-btn\");\n if (fullscreenBtn instanceof HTMLButtonElement) {\n fullscreenBtn.setAttribute(\"aria-pressed\", String(this.isFullscreenMode));\n fullscreenBtn.setAttribute(\n \"aria-label\",\n this.isFullscreenMode ? \"Exit fullscreen\" : \"Enter fullscreen\",\n );\n fullscreenBtn.title = this.isFullscreenMode\n ? \"Exit fullscreen\"\n : \"Fullscreen\";\n }\n }\n\n applyHighlightStyles(hjsCss: string) {\n const root = this.shadowRoot;\n if (!root) {\n return;\n }\n\n const supportsConstructedSheet =\n typeof CSSStyleSheet !== \"undefined\" &&\n typeof CSSStyleSheet.prototype.replaceSync === \"function\";\n\n if (supportsConstructedSheet && \"adoptedStyleSheets\" in root) {\n try {\n const themeSheet = new CSSStyleSheet();\n themeSheet.replaceSync(hjsCss);\n\n const fontSheet = new CSSStyleSheet();\n fontSheet.replaceSync(highlightFontOverrideCss);\n\n const existingSheets = root.adoptedStyleSheets\n ? Array.from(root.adoptedStyleSheets)\n : [];\n root.adoptedStyleSheets = [...existingSheets, themeSheet, fontSheet];\n\n return;\n } catch {\n // Some engines expose pieces of the API but fail at runtime.\n }\n }\n\n const style = document.createElement(\"style\");\n style.setAttribute(\"data-shadow-claw-highlight-theme\", \"true\");\n style.textContent = `${hjsCss}\\n${highlightFontOverrideCss}`;\n root.appendChild(style);\n }\n\n bindEventListeners() {\n const root = this.shadowRoot;\n if (!root) {\n return;\n }\n\n const content = root.querySelector(\".file-content\");\n content?.addEventListener(\"click\", (event: Event) => {\n void this.handlePreviewLinkClick(event as MouseEvent);\n });\n\n const modal = root.querySelector(\".file-modal\");\n modal?.addEventListener(\"cancel\", (event: Event) => {\n event.preventDefault();\n void this.requestCloseViewer();\n });\n modal?.addEventListener(\"close\", () => {\n if (fileViewerStore.file) {\n fileViewerStore.closeFile();\n }\n });\n\n const closeBtn = root.querySelector(\".modal-close-btn\");\n closeBtn?.addEventListener(\"click\", () => void this.requestCloseViewer());\n\n const previewBtn = root.querySelector(\".modal-preview-btn\");\n previewBtn?.addEventListener(\"click\", async () => {\n this.isFilePreviewMode = !this.isFilePreviewMode;\n this.isFileEditMode = false;\n await this.updateView();\n });\n\n const fullscreenBtn = root.querySelector(\".modal-fullscreen-btn\");\n fullscreenBtn?.addEventListener(\"click\", () => {\n if (modal) {\n void this.toggleFullscreenMode(modal);\n }\n });\n\n const shareBtn = root.querySelector(\".modal-share-btn\");\n shareBtn?.addEventListener(\"click\", async () => {\n await this.handleShareFile();\n });\n\n const editBtn = root.querySelector(\".modal-edit-btn\");\n editBtn?.addEventListener(\"click\", async () => {\n this.isFileEditMode = !this.isFileEditMode;\n if (this.isFileEditMode) {\n this.isFilePreviewMode = false;\n }\n\n await this.updateView();\n });\n\n const saveBtn = root.querySelector(\".modal-save-btn\");\n saveBtn?.addEventListener(\"click\", () => this.handleSave());\n\n const cancelBtn = root.querySelector(\".modal-cancel-btn\");\n cancelBtn?.addEventListener(\"click\", async () => {\n this.isEditorDirty = false;\n this.editorDraftContent = null;\n this.isFileEditMode = false;\n await this.updateView();\n });\n const editor = root.querySelector(\".file-editor\");\n\n editor?.addEventListener(\"input\", () => {\n if (editor instanceof HTMLTextAreaElement) {\n this.editorDraftContent = editor.value;\n this.updateEditorHighlight(editor.value);\n }\n\n this.isEditorDirty = true;\n void this.updateView();\n });\n\n if (editor instanceof HTMLTextAreaElement) {\n const syncHighlight = () => {\n const highlightPre = root.querySelector(\".file-editor-overlay\");\n if (highlightPre) {\n highlightPre.scrollTop = editor.scrollTop;\n highlightPre.scrollLeft = editor.scrollLeft;\n }\n };\n\n editor.addEventListener(\"scroll\", syncHighlight);\n editor.addEventListener(\"focus\", syncHighlight);\n editor.addEventListener(\"click\", syncHighlight);\n editor.addEventListener(\"keyup\", syncHighlight);\n editor.addEventListener(\"mouseup\", syncHighlight);\n\n const scrollBody = root.querySelector(\".modal-body\");\n scrollBody?.addEventListener(\"scroll\", syncHighlight);\n }\n }\n\n buildWebShareFile(file: any): File | null {\n if (file?.nativeFile instanceof File) {\n return file.nativeFile;\n }\n\n const bytes = file?.binaryContent;\n if (!(bytes instanceof Uint8Array) || bytes.length === 0) {\n return null;\n }\n\n const fileBytes = new Uint8Array(bytes.byteLength);\n fileBytes.set(bytes);\n\n return new File([fileBytes], file.name || \"shared-file\", {\n type: file?.mimeType || \"application/octet-stream\",\n });\n }\n\n canShareCurrentFile(file: any) {\n if (!file || !this.isWebShareAvailable()) {\n return false;\n }\n\n if (file.kind === \"text\") {\n return true;\n }\n\n const shareFile = this.buildWebShareFile(file);\n if (!shareFile || typeof navigator.canShare !== \"function\") {\n return false;\n }\n\n try {\n return navigator.canShare({ files: [shareFile] });\n } catch {\n return false;\n }\n }\n\n canUseNativeFullscreen(target: HTMLElement): target is HTMLElement & {\n requestFullscreen: () => Promise<void>;\n } {\n return (\n document.fullscreenEnabled === true &&\n (typeof (target as any).requestFullscreen === \"function\" ||\n typeof (target as any).webkitRequestFullscreen === \"function\") &&\n (typeof document.exitFullscreen === \"function\" ||\n typeof (document as any).webkitExitFullscreen === \"function\")\n );\n }\n\n getCurrentFullscreenElement(): Element | null {\n return (\n document.fullscreenElement ||\n (document as any).webkitFullscreenElement ||\n null\n );\n }\n\n getFullscreenTarget(modal: Element): HTMLElement | null {\n const modalContent = modal.querySelector(\".modal-content\");\n if (!(modalContent instanceof HTMLElement)) {\n return null;\n }\n\n return modalContent;\n }\n\n getIframeBridgeScriptUrl() {\n return applyBasePath(\"/assets/file-viewer-preview-bridge.js\");\n }\n\n getIframeSandboxPermissions(fileName: string) {\n if (/\\.svg$/i.test(fileName)) {\n return \"allow-modals allow-popups allow-popups-to-escape-sandbox\";\n }\n\n return getIframeSandboxPolicy();\n }\n\n getLanguageFromFilename(fileName: string) {\n const extension = fileName.toLowerCase().split(\".\").pop() || \"\";\n const languageMap: Record<string, string> = {\n bash: \"bash\",\n cjs: \"javascript\",\n css: \"css\",\n html: \"xml\",\n java: \"java\",\n javascript: \"javascript\",\n js: \"javascript\",\n json: \"json\",\n jsx: \"jsx\",\n markdown: \"markdown\",\n md: \"markdown\",\n mjs: \"javascript\",\n php: \"php\",\n python: \"python\",\n py: \"python\",\n ruby: \"ruby\",\n rb: \"ruby\",\n rust: \"rust\",\n rs: \"rust\",\n sh: \"bash\",\n sql: \"sql\",\n svg: \"xml\",\n ts: \"typescript\",\n tsx: \"tsx\",\n xml: \"xml\",\n yaml: \"yaml\",\n yml: \"yaml\",\n };\n\n return languageMap[extension] || \"\";\n }\n\n getPreviewSourceFile(file: any, modal: HTMLElement) {\n return this.getWorkingSourceFile(file, modal);\n }\n\n getWorkingSourceFile(file: any, modal: HTMLElement) {\n if (!this.isEditorDirty || file?.kind !== \"text\") {\n return file;\n }\n\n if (typeof this.editorDraftContent === \"string\") {\n return {\n ...file,\n content: this.editorDraftContent,\n };\n }\n\n const editor = modal.querySelector(\".file-editor\");\n if (!(editor instanceof HTMLTextAreaElement)) {\n return file;\n }\n\n return {\n ...file,\n content: editor.value,\n };\n }\n\n getWorkspaceRouteTarget(\n value: string,\n options: { allowCrossGroup?: boolean } = {},\n ): { groupId: string; path: string } | null {\n const { allowCrossGroup = false } = options;\n\n let pathOnly = value.split(/[?#]/, 1)[0].trim();\n if (!pathOnly) {\n return null;\n }\n\n if (\n /^[a-zA-Z][a-zA-Z\\d+.-]*:/u.test(pathOnly) ||\n pathOnly.startsWith(\"//\")\n ) {\n let parsed: URL;\n try {\n parsed = new URL(pathOnly, window.location.href);\n } catch {\n return null;\n }\n\n if (parsed.origin !== window.location.origin) {\n return null;\n }\n\n pathOnly = parsed.pathname;\n }\n\n const dotPrefixedFilesPath = pathOnly.replace(/^(?:\\.\\/)+/u, \"\");\n const candidates: string[] = [];\n\n if (dotPrefixedFilesPath.startsWith(\"files/\")) {\n candidates.push(`/${dotPrefixedFilesPath}`);\n }\n\n if (pathOnly.startsWith(\"/\")) {\n const nestedFilesIndex = pathOnly.lastIndexOf(\"/files/\");\n if (nestedFilesIndex > 0) {\n candidates.push(pathOnly.slice(nestedFilesIndex));\n }\n\n candidates.push(pathOnly);\n }\n\n for (const candidate of candidates) {\n const route = getWorkspaceRouteRequestPath(candidate);\n if (!route) {\n continue;\n }\n\n const resolvedGroupId = this.resolveRouteGroupId(route.groupId);\n if (!resolvedGroupId) {\n continue;\n }\n\n if (\n !allowCrossGroup &&\n resolvedGroupId !== orchestratorStore.activeGroupId\n ) {\n continue;\n }\n\n return { groupId: resolvedGroupId, path: route.path };\n }\n\n return null;\n }\n\n handleAnchorNavigation(anchor: string): boolean {\n const root = this.shadowRoot;\n if (!root) {\n return false;\n }\n\n const content = root.querySelector(\".file-content\") as HTMLElement;\n if (!content) {\n return false;\n }\n\n // Clear any existing highlighted lines\n content.querySelectorAll(\".code-line.highlighted\").forEach((el) => {\n el.classList.remove(\"highlighted\");\n });\n\n const lineMatch = anchor.match(/^#?L(\\d+)(?:-L?(\\d+))?$/i);\n if (lineMatch) {\n const startLine = parseInt(lineMatch[1], 10);\n const endLine = lineMatch[2] ? parseInt(lineMatch[2], 10) : startLine;\n\n let firstHighlightedEl: HTMLElement | null = null;\n const codeLines = content.querySelectorAll(\".code-line\");\n codeLines.forEach((el) => {\n const lineNum = parseInt(el.getAttribute(\"data-line\") || \"0\", 10);\n if (lineNum >= startLine && lineNum <= endLine) {\n el.classList.add(\"highlighted\");\n if (!firstHighlightedEl) {\n firstHighlightedEl = el as HTMLElement;\n }\n }\n });\n\n if (firstHighlightedEl) {\n (firstHighlightedEl as HTMLElement).scrollIntoView({\n behavior: \"smooth\",\n block: \"center\",\n });\n\n return true;\n }\n\n return false;\n } else {\n const id = anchor.replace(/^#/, \"\");\n const targetEl =\n content.querySelector(`[id=\"${id}\"]`) ||\n content.querySelector(`a[name=\"${id}\"]`);\n if (targetEl) {\n targetEl.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n\n return true;\n }\n\n return false;\n }\n }\n\n handleFullscreenChange = () => {\n const root = this.shadowRoot;\n if (!root) {\n return;\n }\n\n const modal = root.querySelector(\".file-modal\");\n if (!(modal instanceof HTMLElement)) {\n return;\n }\n\n const fullscreenTarget = this.getFullscreenTarget(modal);\n this.isFullscreenMode = this.isTargetInFullscreen(fullscreenTarget);\n this.applyFullscreenMode(modal);\n };\n\n handleIframeMessage = (event: MessageEvent) => {\n if (!event.data || typeof event.data !== \"object\") {\n return;\n }\n\n const payload = event.data as {\n type?: unknown;\n href?: unknown;\n height?: unknown;\n channel?: unknown;\n payload?: unknown;\n };\n\n if (\n payload.type === \"shadow-claw-broadcast-result\" &&\n typeof payload.channel === \"string\"\n ) {\n this.broadcastProxy?.handleResultFromIframe(\n event.source as WindowProxy,\n payload.channel,\n payload.payload,\n );\n return;\n }\n\n if (\n payload.type === \"shadow-claw-iframe-resize\" &&\n typeof payload.height === \"number\"\n ) {\n const root = this.shadowRoot;\n const iframe = root?.querySelector(\".file-content-iframe\");\n if (\n iframe instanceof HTMLIFrameElement &&\n (!this.previewFrameWindow ||\n event.source === this.previewFrameWindow ||\n (iframe.contentWindow && event.source === iframe.contentWindow))\n ) {\n this.previewFrameWindow = iframe.contentWindow;\n iframe.style.setProperty(\"height\", `${payload.height}px`, \"important\");\n }\n\n return;\n }\n\n if (payload.type === \"shadow-claw-storage-proxy\") {\n if (this.previewFrameWindow && event.source !== this.previewFrameWindow) {\n return;\n }\n\n const p = payload as {\n requestId?: unknown;\n method?: unknown;\n args?: unknown;\n };\n\n this.handleStorageProxyRequest(\n event.source as WindowProxy,\n String(p.requestId || \"\"),\n String(p.method || \"\"),\n (p.args && typeof p.args === \"object\" ? p.args : {}) as Record<\n string,\n unknown\n >,\n );\n\n return;\n }\n\n if (!this.db) {\n return;\n }\n\n if (\n payload.type !== \"shadow-claw-file-viewer-link\" ||\n typeof payload.href !== \"string\"\n ) {\n return;\n }\n\n if (this.previewFrameWindow && event.source !== this.previewFrameWindow) {\n return;\n }\n\n const current = fileViewerStore.file;\n const filePath = current?.path || current?.name || \"\";\n const routeDir = applyBasePath(\n getFileRouteDirPath(orchestratorStore.activeGroupId, filePath),\n );\n const resolved = resolveHrefAgainstRoute(\n payload.href,\n routeDir,\n window.location.origin,\n );\n if (!resolved) {\n return;\n }\n\n const hasGameSave = resolved.searchParams.has(\"gameSave\");\n\n if (hasGameSave) {\n this.reloadPreviewWithSearchParams(resolved.search);\n\n return;\n }\n\n const isInternal =\n resolved.origin === window.location.origin &&\n (isPossibleAppRoute(resolved.pathname) ||\n Boolean(this.resolveWorkspaceLinkPath(payload.href, filePath)));\n\n if (!isInternal) {\n window.open(resolved.href, \"_blank\", \"noopener,noreferrer\");\n\n return;\n }\n\n const targetPath = `${resolved.pathname}${resolved.search}${resolved.hash}`;\n const nav = (window as any).navigation;\n if (nav && typeof nav.navigate === \"function\") {\n nav.navigate(targetPath);\n\n return;\n }\n\n window.history.pushState({}, \"\", targetPath);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n };\n\n hasUnsavedChanges() {\n return this.isEditorDirty;\n }\n\n isIframePreviewFile(fileName: string) {\n return /\\.(?:html?|svg)$/i.test(fileName);\n }\n\n isMarkdownLikeFile(fileName: string) {\n return /(?:^readme$|\\.mdx?$|\\.markdown$|\\.mdown$)/i.test(fileName);\n }\n\n isNodeInComposedTree(node: Node | null, ancestor: Node): boolean {\n let current: Node | null = node;\n\n while (current) {\n if (current === ancestor) {\n return true;\n }\n\n if (current.parentNode) {\n current = current.parentNode;\n\n continue;\n }\n\n const root = current.getRootNode?.();\n if (root instanceof ShadowRoot && root.host) {\n current = root.host;\n\n continue;\n }\n\n current = null;\n }\n\n return false;\n }\n\n isRenderTokenCurrent(renderToken: number) {\n return this.viewRenderToken === renderToken;\n }\n\n isTargetInFullscreen(target: HTMLElement | null): boolean {\n if (!target) {\n return false;\n }\n\n const current = this.getCurrentFullscreenElement();\n if (!current) {\n return false;\n }\n\n return (\n current === target ||\n this.isNodeInComposedTree(target, current) ||\n this.isNodeInComposedTree(current, target)\n );\n }\n\n isWebShareAvailable() {\n return (\n typeof navigator !== \"undefined\" && typeof navigator.share === \"function\"\n );\n }\n\n mimeTypeForImageExt(ext: string): string {\n const map: Record<string, string> = {\n apng: \"image/apng\",\n avif: \"image/avif\",\n gif: \"image/gif\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n png: \"image/png\",\n svg: \"image/svg+xml\",\n webp: \"image/webp\",\n };\n\n return map[ext] ?? \"image/jpeg\";\n }\n\n renderBinaryPreview(content: HTMLElement, file: any) {\n const mimeType = file.mimeType || \"application/octet-stream\";\n\n if (file.nativeFile instanceof File) {\n this.currentObjectUrl = URL.createObjectURL(file.nativeFile);\n } else {\n const bytes = file.binaryContent;\n if (!(bytes instanceof Uint8Array) || bytes.length === 0) {\n content.classList.remove(\"file-content--raw\", \"file-content--iframe\");\n content.classList.add(\"file-content--preview\");\n content.textContent = \"Binary content unavailable.\";\n\n return;\n }\n\n // Copy into a plain ArrayBuffer-backed view so BlobPart typing is stable in checkJs.\n const blobBytes = new Uint8Array(bytes.byteLength);\n blobBytes.set(bytes);\n\n const blob = new Blob([blobBytes], { type: mimeType });\n this.currentObjectUrl = URL.createObjectURL(blob);\n }\n\n content.classList.remove(\"file-content--raw\", \"file-content--preview\");\n content.classList.add(\"file-content--iframe\");\n\n if (mimeType.startsWith(\"image/\")) {\n const image = document.createElement(\"img\");\n image.className = \"file-content-iframe\";\n image.alt = `Preview: ${file.name}`;\n image.src = this.currentObjectUrl;\n image.style.objectFit = \"contain\";\n\n content.replaceChildren(image);\n\n return;\n }\n\n if (mimeType.startsWith(\"video/\")) {\n const video = document.createElement(\"video\");\n video.className = \"file-content-iframe\";\n video.controls = true;\n video.src = this.currentObjectUrl;\n video.style.backgroundColor = \"black\";\n\n content.replaceChildren(video);\n\n return;\n }\n\n if (mimeType.startsWith(\"audio/\")) {\n const audioWrap = document.createElement(\"div\");\n audioWrap.className = \"file-content file-content--preview\";\n audioWrap.style.padding = \"1rem\";\n\n const label = document.createElement(\"p\");\n label.textContent = file.name;\n\n const audio = document.createElement(\"audio\");\n audio.controls = true;\n audio.src = this.currentObjectUrl;\n audio.style.width = \"100%\";\n\n audioWrap.replaceChildren(label, audio);\n content.replaceChildren(audioWrap);\n content.classList.remove(\"file-content--iframe\");\n\n return;\n }\n\n const iframe = document.createElement(\"iframe\");\n iframe.className = \"file-content-iframe\";\n iframe.setAttribute(\"title\", `Preview: ${file.name}`);\n iframe.setAttribute(\"referrerpolicy\", \"no-referrer\");\n iframe.src = this.currentObjectUrl;\n\n content.replaceChildren(iframe);\n }\n\n resetContent() {\n const root = this.shadowRoot;\n if (!root) {\n return;\n }\n\n const modal = root.querySelector(\".file-modal\");\n if (!(modal instanceof HTMLElement)) {\n return;\n }\n\n const fullscreenTarget = this.getFullscreenTarget(modal);\n if (fullscreenTarget && this.isTargetInFullscreen(fullscreenTarget)) {\n void this.exitNativeFullscreen().catch(() => {\n // noop\n });\n }\n\n this.isFullscreenMode = false;\n this.applyFullscreenMode(modal);\n\n const content = modal.querySelector(\".file-content\");\n const previewBtn = modal.querySelector(\".modal-preview-btn\");\n\n if (previewBtn instanceof HTMLButtonElement) {\n previewBtn.setAttribute(\"aria-pressed\", \"false\");\n previewBtn.setAttribute(\"aria-label\", \"Switch to preview mode\");\n }\n\n const editBtn = modal.querySelector(\".modal-edit-btn\");\n if (editBtn instanceof HTMLButtonElement) {\n editBtn.setAttribute(\"aria-pressed\", \"false\");\n editBtn.setAttribute(\"aria-label\", \"Edit file\");\n editBtn.classList.remove(\"hidden\");\n }\n\n const closeBtn = modal.querySelector(\".modal-close-btn\");\n if (closeBtn instanceof HTMLButtonElement) {\n closeBtn.disabled = false;\n closeBtn.setAttribute(\"aria-label\", \"Close file viewer\");\n closeBtn.title = \"Close\";\n }\n\n const saveBtn = modal.querySelector(\".modal-save-btn\");\n saveBtn?.classList.add(\"hidden\");\n\n const editorContainer = modal.querySelector(\".file-editor-container\");\n editorContainer?.classList.remove(\"active\");\n\n const modalBody = modal.querySelector(\".modal-body\");\n modalBody?.classList.remove(\"modal-body--editing\");\n\n const editor = modal.querySelector(\".file-editor\");\n if (editor instanceof HTMLTextAreaElement) {\n editor.value = \"\";\n editor.removeAttribute(\"language\");\n }\n\n const highlightCode = modal.querySelector(\".file-editor-overlay code\");\n if (highlightCode) {\n highlightCode.innerHTML = \"\";\n highlightCode.className = \"hljs\";\n }\n\n this.isFileEditMode = false;\n this.editorDraftContent = null;\n\n if (!(content instanceof HTMLElement)) {\n return;\n }\n\n this.revokeObjectUrl();\n\n content.classList.remove(\"hidden\");\n content.classList.add(\"file-content--raw\");\n content.classList.remove(\"file-content--preview\", \"file-content--iframe\");\n content.textContent = \"\";\n }\n\n resolveRouteGroupId(routeGroupId: string): string | null {\n const expectedGroupId = orchestratorStore.activeGroupId;\n if (\n routeGroupId === expectedGroupId ||\n this.routeGroupMatches(routeGroupId, expectedGroupId)\n ) {\n return expectedGroupId;\n }\n\n const groups = Array.isArray(orchestratorStore.groups)\n ? orchestratorStore.groups\n : [];\n const exact = groups.find((group) => group.groupId === routeGroupId);\n if (exact) {\n return exact.groupId;\n }\n\n const alias = groups.find((group) =>\n this.routeGroupMatches(routeGroupId, group.groupId),\n );\n if (alias) {\n return alias.groupId;\n }\n\n return routeGroupId || null;\n }\n\n resolveWorkspaceLinkPath(href: string, basePath: string = \"\"): string | null {\n const trimmed = href.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) {\n return null;\n }\n\n let candidate = trimmed;\n const hasScheme = /^[a-zA-Z][a-zA-Z\\d+.-]*:/.test(trimmed);\n\n if (hasScheme || trimmed.startsWith(\"//\")) {\n let parsed: URL;\n try {\n parsed = new URL(trimmed, window.location.href);\n } catch {\n return null;\n }\n\n const isHttp =\n parsed.protocol === \"http:\" || parsed.protocol === \"https:\";\n if (!isHttp || parsed.host !== window.location.host) {\n return null;\n }\n\n candidate = `${parsed.pathname}${parsed.search}${parsed.hash}`;\n }\n\n const workspaceRouteTarget = this.getWorkspaceRouteTarget(candidate);\n if (workspaceRouteTarget) {\n return workspaceRouteTarget.path;\n }\n\n let normalized = candidate.split(/[?#]/, 1)[0].replace(/\\\\/g, \"/\");\n const isAbsolute = normalized.startsWith(\"/\");\n\n if (hasScheme || isAbsolute) {\n return null;\n }\n\n normalized = normalized.replace(/^\\/+/, \"\");\n\n if (!normalized) {\n return null;\n }\n\n const stack: string[] = [];\n\n if (!isAbsolute) {\n const baseNormalized = basePath.replace(/\\\\/g, \"/\").replace(/^\\/+/, \"\");\n const baseParts = baseNormalized.split(\"/\").filter(Boolean);\n baseParts.pop();\n stack.push(...baseParts);\n }\n\n for (const part of normalized.split(\"/\")) {\n if (!part || part === \".\") {\n continue;\n }\n\n if (part === \"..\") {\n if (stack.length === 0) {\n return null;\n }\n\n stack.pop();\n\n continue;\n }\n\n stack.push(part);\n }\n\n return stack.length > 0 ? stack.join(\"/\") : null;\n }\n\n revokeObjectUrl() {\n this.previewFrameWindow = null;\n\n if (this.currentObjectUrl) {\n URL.revokeObjectURL(this.currentObjectUrl);\n this.currentObjectUrl = null;\n }\n\n for (const url of this.currentImageObjectUrls) {\n URL.revokeObjectURL(url);\n }\n\n this.currentImageObjectUrls = [];\n }\n\n rewriteWorkspacePreviewHtml(html: string, filePath: string): string {\n if (!html) {\n return html;\n }\n\n const routeDir = applyBasePath(\n getFileRouteDirPath(orchestratorStore.activeGroupId, filePath),\n );\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n\n const rewriteUrlAttribute = (\n selector: string,\n attribute: \"href\" | \"src\",\n ) => {\n const nodes = Array.from(parsed.querySelectorAll(selector));\n for (const node of nodes) {\n const currentValue = node.getAttribute(attribute) || \"\";\n const trimmed = currentValue.trim();\n if (\n !trimmed ||\n trimmed.startsWith(\"#\") ||\n trimmed.startsWith(\"javascript:\")\n ) {\n continue;\n }\n\n const resolved = resolveHrefAgainstRoute(\n trimmed,\n routeDir,\n window.location.origin,\n );\n if (!resolved || resolved.origin !== window.location.origin) {\n continue;\n }\n\n if (attribute === \"href\") {\n const isInternal =\n isPossibleAppRoute(resolved.pathname) ||\n Boolean(this.resolveWorkspaceLinkPath(trimmed, filePath));\n if (!isInternal) {\n continue;\n }\n }\n\n node.setAttribute(\n attribute,\n `${resolved.pathname}${resolved.search}${resolved.hash}`,\n );\n }\n };\n\n rewriteUrlAttribute(\"a[href]\", \"href\");\n rewriteUrlAttribute(\"img[src]\", \"src\");\n rewriteUrlAttribute(\"audio[src]\", \"src\");\n rewriteUrlAttribute(\"video[src]\", \"src\");\n rewriteUrlAttribute(\"source[src]\", \"src\");\n\n return parsed.body.innerHTML;\n }\n\n routeGroupMatches(routeGroupId: string, expectedGroupId: string): boolean {\n if (routeGroupId === expectedGroupId) {\n return true;\n }\n\n if (\n (routeGroupId === \"main\" && expectedGroupId === \"br:main\") ||\n (routeGroupId === \"br:main\" && expectedGroupId === \"main\")\n ) {\n return true;\n }\n\n if (!routeGroupId.includes(\":\") && !expectedGroupId.includes(\":\")) {\n return false;\n }\n\n const normalize = (value: string) => value.trim().replace(/:/g, \"-\");\n\n return normalize(routeGroupId) === normalize(expectedGroupId);\n }\n\n setupEffects() {\n effect(() => {\n const declTools = toolsStore.declarativeTools;\n if (this.broadcastProxy && declTools.length > 0) {\n this.broadcastProxy.registerChannelsFromTools(declTools);\n }\n });\n\n effect(() => {\n const file = fileViewerStore.file;\n const renderToken = ++this.viewRenderToken;\n const root = this.shadowRoot;\n if (!root) {\n return;\n }\n\n const shadowDialog = root.querySelector(\"shadow-claw-dialog\") as any;\n if (shadowDialog && typeof shadowDialog.ensureDialog === \"function\") {\n shadowDialog.ensureDialog();\n }\n\n const modal = root.querySelector(\".file-modal\");\n\n if (file) {\n if (\n shadowDialog &&\n typeof shadowDialog.showModal === \"function\" &&\n !shadowDialog.open\n ) {\n shadowDialog.showModal();\n } else if (modal instanceof HTMLDialogElement && !modal.open) {\n modal.showModal();\n }\n\n const title = root.querySelector(\".modal-title\");\n if (title instanceof HTMLElement) {\n title.textContent = `File: ${file.name}`;\n }\n\n if (this.lastOpenedFileName !== file.name) {\n this.lastOpenedFileName = file.name;\n this.isFilePreviewMode = this.shouldAutoPreview(file);\n this.isFileEditMode = false;\n this.isEditorDirty = false;\n this.editorDraftContent = null;\n }\n\n // async / await\n void this.updateView(renderToken);\n } else {\n if (\n shadowDialog &&\n typeof shadowDialog.close === \"function\" &&\n shadowDialog.open\n ) {\n shadowDialog.close();\n } else if (modal instanceof HTMLDialogElement && modal.open) {\n modal.close();\n }\n\n this.lastOpenedFileName = \"\";\n this.isFilePreviewMode = false;\n this.isEditorDirty = false;\n this.editorDraftContent = null;\n\n this.resetContent();\n }\n });\n }\n\n shouldAutoPreview(file: any) {\n if (!file || typeof file !== \"object\") {\n return false;\n }\n\n if (file.kind === \"pdf\" || file.kind === \"binary\") {\n return true;\n }\n\n if (file.kind === \"text\") {\n return (\n this.isIframePreviewFile(file.name) ||\n this.isMarkdownLikeFile(file.name)\n );\n }\n\n return false;\n }\n\n stripHtmlFrontmatter(content: string): string {\n if (typeof content !== \"string\" || !content.trimStart().startsWith(\"---\")) {\n return content;\n }\n\n const parsed = splitFrontmatter(content);\n if (Object.keys(parsed.data || {}).length === 0) {\n return content;\n }\n\n return parsed.content || \"\";\n }\n\n toPreviewMarkdown(file: any) {\n if (this.isMarkdownLikeFile(file.name)) {\n return file.content;\n }\n\n const lang = this.getLanguageFromFilename(file.name);\n\n return \"```\" + lang + \"\\n\" + file.content + \"\\n```\";\n }\n\n updateEditorHighlight(value: string) {\n const root = this.shadowRoot;\n if (!root) {\n return;\n }\n\n const highlightCode = root.querySelector(\".file-editor-overlay code\");\n if (!highlightCode) {\n return;\n }\n\n const file = fileViewerStore.file;\n const language = this.getLanguageFromFilename(file?.name || \"\");\n let highlighted = \"\";\n\n try {\n if (language && hljs.getLanguage(language)) {\n highlighted = hljs.highlight(value, { language }).value;\n } else {\n highlighted = hljs.highlightAuto(value).value;\n }\n } catch {\n highlighted = value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n }\n\n highlightCode.className = language ? `hljs language-${language}` : \"hljs\";\n // hljs output is pre-sanitized: user content is entity-escaped and\n // only generated <span class=\"hljs-*\"> tags are added. Use\n // toTrustedHtmlPresanitized to satisfy Trusted Types without\n // running DOMPurify (which would strip the hljs span tokens).\n highlightCode.innerHTML = toTrustedHtmlPresanitized(\n highlighted + \"<br>\",\n ) as string;\n }\n\n wrapCodeLines(content: HTMLElement) {\n const codeBlocks = content.querySelectorAll(\"pre code\");\n codeBlocks.forEach((codeEl) => {\n const htmlContent = codeEl.innerHTML;\n const lines = htmlContent.split(/\\r?\\n/u);\n\n if (lines.length > 1 && lines[lines.length - 1] === \"\") {\n lines.pop();\n }\n\n const wrappedHtml = lines\n .map((line, idx) => {\n const lineNum = idx + 1;\n\n return `<span class=\"code-line\" data-line=\"${lineNum}\">${line || \" \"}</span>`;\n })\n .join(\"\\n\");\n setSanitizedHtml(codeEl, wrappedHtml);\n });\n }\n\n async buildIframePreviewSrcdoc(file: any, searchParams: string = \"\") {\n if (/\\.svg$/i.test(file.name)) {\n return file.content;\n }\n\n const filePath = file.path || file.name || \"\";\n const sansFrontmatter = this.stripHtmlFrontmatter(file.content || \"\");\n const resolvedHtml = this.rewriteWorkspacePreviewHtml(\n sansFrontmatter,\n filePath,\n );\n const htmlContent = await this.resolveRelativeImagesInHtml(\n resolvedHtml,\n filePath,\n );\n\n const safeContent = sanitizeSrcdocHtml(htmlContent, previewSanitizeOptions);\n\n // Nonce-gated CSP: only the bridge script and approved custom element scripts may run.\n const nonce = crypto.randomUUID().replace(/-/g, \"\");\n const bridgeScriptUrl = this.getIframeBridgeScriptUrl();\n const storageBridgeScriptUrl = applyBasePath(\n \"/assets/iframe-storage-bridge.js\",\n );\n\n const approvedScripts = getApprovedCustomElementScripts();\n const cspContent = getIframeCsp(nonce);\n\n const configScript =\n typeof document !== \"undefined\"\n ? document.getElementById(\"shadow-claw-site-config\")\n : null;\n const siteConfigHtml =\n configScript && configScript.textContent\n ? `<script id=\"shadow-claw-site-config\" type=\"application/json\">${configScript.textContent}</script>`\n : \"\";\n\n const searchScriptHtml = searchParams\n ? `<script nonce=\"${nonce}\">(function(){try{Object.defineProperty(window.location,\"search\",{get:function(){return ${JSON.stringify(searchParams)};},configurable:true});}catch(e){}})();</script>`\n : \"\";\n\n const customElementScriptsHtml = approvedScripts\n .map((src) => {\n const isExternal =\n src.startsWith(\"http://\") ||\n src.startsWith(\"https://\") ||\n src.startsWith(\"//\");\n const resolvedSrc = isExternal\n ? src\n : applyBasePath(\n src.startsWith(\"/\")\n ? src\n : `/${src.replace(/^pages\\/main\\//, \"\")}`,\n );\n return `<script type=\"module\" src=\"${resolvedSrc}\" nonce=\"${nonce}\"></script>`;\n })\n .join(\"\\n\");\n\n const themeStylesheetLink = `<link rel=\"stylesheet\" href=\"${applyBasePath(\n \"/theme.css\",\n )}\">`;\n\n return [\n \"<!doctype html>\",\n `<html class=\"${getIframeHtmlClass()}\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">`,\n `<meta http-equiv=\"Content-Security-Policy\" content=\"${cspContent}\">`,\n `<base href=\"${applyBasePath(getFileRouteDirPath(orchestratorStore.activeGroupId, filePath))}\" target=\"_blank\">`,\n searchScriptHtml,\n siteConfigHtml,\n `<script src=\"${storageBridgeScriptUrl}\" nonce=\"${nonce}\"></script>`,\n `<script src=\"${bridgeScriptUrl}\" nonce=\"${nonce}\"></script>`,\n getIframeThemeStyleHtml(),\n themeStylesheetLink,\n customElementScriptsHtml,\n \"</head><body>\",\n safeContent,\n \"</body></html>\",\n ].join(\"\");\n }\n\n async canDismissViewer() {\n if (!this.hasUnsavedChanges()) {\n return true;\n }\n\n const confirmed = await this.requestConfirmation({\n title: \"Discard Unsaved Changes\",\n message: \"You have unsaved changes. Discard them and close?\",\n confirmLabel: \"Discard\",\n cancelLabel: \"Keep Editing\",\n });\n\n if (confirmed) {\n this.isEditorDirty = false;\n this.editorDraftContent = null;\n }\n\n return confirmed;\n }\n\n async exitFullscreenIfActive(modal?: Element): Promise<void> {\n const root = this.shadowRoot;\n const activeModal = modal || root?.querySelector(\".file-modal\");\n if (!activeModal) {\n return;\n }\n\n const fullscreenTarget = this.getFullscreenTarget(activeModal);\n if (!fullscreenTarget || !this.isTargetInFullscreen(fullscreenTarget)) {\n return;\n }\n\n try {\n await this.exitNativeFullscreen();\n } catch {\n // Native fullscreen exit can fail if browser blocks it.\n }\n }\n\n async exitNativeFullscreen(): Promise<void> {\n const exit =\n document.exitFullscreen || (document as any).webkitExitFullscreen;\n if (typeof exit !== \"function\") {\n throw new Error(\"Native fullscreen exit unavailable\");\n }\n\n await Promise.resolve(exit.call(document));\n }\n\n async handlePreviewLinkClick(event: MouseEvent) {\n if (event.defaultPrevented || event.button !== 0) {\n return;\n }\n\n if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {\n return;\n }\n\n const target = event.target;\n if (!(target instanceof Element)) {\n return;\n }\n\n const link = target.closest(\"a\");\n if (!(link instanceof HTMLAnchorElement) || !this.db) {\n return;\n }\n\n const current = fileViewerStore.file;\n const basePath = current?.path || current?.name || \"\";\n const href = link.getAttribute(\"href\") || \"\";\n const routeDir = applyBasePath(\n getFileRouteDirPath(orchestratorStore.activeGroupId, basePath),\n );\n const resolved = resolveHrefAgainstRoute(\n href,\n routeDir,\n window.location.origin,\n );\n\n const isInternal =\n resolved &&\n resolved.origin === window.location.origin &&\n (isPossibleAppRoute(resolved.pathname) ||\n Boolean(this.resolveWorkspaceLinkPath(href, basePath)));\n\n if (isInternal && resolved) {\n event.preventDefault();\n const targetPath = `${resolved.pathname}${resolved.search}${resolved.hash}`;\n const nav = (window as any).navigation;\n if (nav && typeof nav.navigate === \"function\") {\n nav.navigate(targetPath);\n } else {\n window.history.pushState({}, \"\", targetPath);\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }\n\n return;\n }\n\n const trimmed = href.trim();\n if (\n trimmed &&\n !trimmed.startsWith(\"#\") &&\n !trimmed.startsWith(\"javascript:\")\n ) {\n const targetAttr = link.getAttribute(\"target\") || \"_blank\";\n const safeTarget =\n targetAttr === \"_self\" ||\n targetAttr === \"_top\" ||\n targetAttr === \"_parent\"\n ? \"_blank\"\n : targetAttr;\n\n try {\n const parsed = new URL(trimmed, window.location.href);\n const isExternal = parsed.host !== window.location.host;\n if (isExternal) {\n event.preventDefault();\n window.open(trimmed, safeTarget, \"noopener,noreferrer\");\n }\n } catch {\n if (/^[a-zA-Z][a-zA-Z\\d+.-]*:/u.test(trimmed)) {\n event.preventDefault();\n window.open(trimmed, safeTarget, \"noopener,noreferrer\");\n }\n }\n }\n }\n\n async handleSave() {\n const file = fileViewerStore.file;\n if (!file || !this.db) {\n return;\n }\n\n const root = this.shadowRoot;\n const saveBtn = root?.querySelector(\".modal-save-btn\");\n const editor = root?.querySelector(\".file-editor\");\n\n if (!(editor instanceof HTMLTextAreaElement)) {\n return;\n }\n\n try {\n if (saveBtn instanceof HTMLButtonElement) {\n saveBtn.disabled = true;\n saveBtn.textContent = \"⏳ saving...\";\n }\n\n const newContent = editor.value;\n const filePath =\n file.path ||\n (orchestratorStore.currentPath === \".\"\n ? file.name\n : `${orchestratorStore.currentPath}/${file.name}`);\n const groupId = file.groupId || orchestratorStore.activeGroupId;\n\n await writeGroupFile(this.db, groupId, filePath, newContent);\n\n showSuccess(`Saved ${file.name}`);\n\n // Notify pages (and other consumers) rendering this path so they refresh\n // without requiring the user to navigate away and back.\n document.dispatchEvent(\n new CustomEvent(\"shadow-claw-file-saved\", {\n detail: { groupId, path: filePath },\n bubbles: true,\n composed: true,\n }),\n );\n\n await orchestratorStore.loadFiles(this.db);\n\n file.content = newContent;\n this.isFileEditMode = false;\n this.isEditorDirty = false;\n this.editorDraftContent = null;\n\n await this.updateView();\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n\n showError(`Failed to save file: ${message}`);\n } finally {\n if (saveBtn instanceof HTMLButtonElement) {\n saveBtn.disabled = false;\n saveBtn.textContent = \"💾 Save\";\n }\n }\n }\n\n async handleShareFile() {\n const file = fileViewerStore.file;\n if (!file || !this.canShareCurrentFile(file)) {\n showError(\"Sharing is not supported for this file on this device.\", 4500);\n\n return;\n }\n\n try {\n if (file.kind === \"text\") {\n await navigator.share({\n title: file.name,\n text: file.content || \"\",\n });\n } else {\n const shareFile = this.buildWebShareFile(file);\n if (!shareFile || !navigator.canShare?.({ files: [shareFile] })) {\n showError(\"File sharing is not supported on this device.\", 4500);\n\n return;\n }\n\n await navigator.share({\n title: file.name,\n files: [shareFile],\n });\n }\n\n showSuccess(`Shared ${file.name}`);\n } catch (err) {\n if (err instanceof DOMException && err.name === \"AbortError\") {\n return;\n }\n\n const message = err instanceof Error ? err.message : String(err);\n showError(`Failed to share file: ${message}`, 5000);\n }\n }\n\n async openFolderInFilesView(path: string) {\n if (!this.db) {\n return;\n }\n\n const normalizedPath = path.replace(/^\\/+|\\/+$/g, \"\");\n if (!normalizedPath) {\n return;\n }\n\n try {\n await orchestratorStore.setCurrentPath(this.db, normalizedPath);\n fileViewerStore.closeFile();\n\n const maybeUi = (window as any)?.shadowclaw?.ui;\n if (maybeUi && typeof maybeUi.showPage === \"function\") {\n maybeUi.showPage(\"files\");\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n showError(`Failed to open linked folder: ${message}`, 5000);\n }\n }\n\n async openWorkspaceLink(href: string, basePath: string) {\n if (!this.db) {\n return;\n }\n\n const resolved = this.resolveWorkspaceLinkPath(href, basePath);\n if (!resolved) {\n return;\n }\n\n const lastSegment = resolved.split(\"/\").filter(Boolean).pop() || \"\";\n const hasExtension = /\\.[^./]+$/u.test(lastSegment);\n\n if (!hasExtension) {\n // Try opening the exact path first (supports extensionless files).\n try {\n await fileViewerStore.openFile(\n this.db,\n resolved,\n orchestratorStore.activeGroupId,\n );\n\n return;\n } catch (err) {\n const isNotFound =\n err instanceof DOMException && err.name === \"NotFoundError\";\n const isDirectory =\n err instanceof DOMException && err.name === \"TypeMismatchError\";\n if (!isNotFound && !isDirectory) {\n const message = err instanceof Error ? err.message : String(err);\n showError(`Failed to open linked file: ${message}`, 5000);\n\n return;\n }\n }\n\n await this.openFolderInFilesView(resolved);\n\n return;\n }\n\n try {\n await fileViewerStore.openFile(\n this.db,\n resolved,\n orchestratorStore.activeGroupId,\n );\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n showError(`Failed to open linked file: ${message}`, 5000);\n }\n }\n\n async renderPreview(\n content: HTMLElement,\n file: any,\n renderToken: number = this.viewRenderToken,\n ) {\n if (!this.isRenderTokenCurrent(renderToken)) {\n return;\n }\n\n this.revokeObjectUrl();\n this.previewFrameWindow = null;\n\n if (file.kind === \"pdf\") {\n content.classList.remove(\n \"file-content--raw\",\n \"file-content--preview\",\n \"file-content--iframe\",\n );\n\n import(\"../shadow-claw-pdf-viewer/shadow-claw-pdf-viewer.js\")\n .then(() => {\n const pdfViewer = document.createElement(\n \"shadow-claw-pdf-viewer\",\n ) as HTMLElement & {\n file: any;\n };\n pdfViewer.file = file;\n content.replaceChildren(pdfViewer);\n })\n .catch(console.error);\n\n return;\n }\n\n if (file.kind === \"binary\") {\n this.renderBinaryPreview(content, file);\n\n return;\n }\n\n if (this.isIframePreviewFile(file.name)) {\n content.classList.remove(\"file-content--raw\", \"file-content--preview\");\n content.classList.add(\"file-content--iframe\");\n\n const iframe = document.createElement(\"iframe\");\n iframe.className = \"file-content-iframe\";\n iframe.setAttribute(\"title\", `Preview: ${file.name}`);\n iframe.setAttribute(\n \"sandbox\",\n this.getIframeSandboxPermissions(file.name),\n );\n iframe.setAttribute(\"allow\", \"fullscreen\");\n\n iframe.setAttribute(\"referrerpolicy\", \"no-referrer\");\n setTrustedSrcdoc(iframe, await this.buildIframePreviewSrcdoc(file));\n iframe.addEventListener(\"load\", () => {\n this.previewFrameWindow = iframe.contentWindow;\n this.syncIframeTheme();\n });\n\n content.replaceChildren(iframe);\n\n return;\n }\n\n content.classList.remove(\"file-content--raw\");\n content.classList.add(\"file-content--preview\");\n\n const currentFile = fileViewerStore.file;\n const basePath = currentFile?.path || currentFile?.name || \"\";\n const previewMarkdown = this.toPreviewMarkdown(file);\n const renderFrontmatterValue = resolveFrontmatterToggle(\n this.db,\n CONFIG_KEYS.MARKDOWN_FRONTMATTER_FILE_VIEWER,\n );\n const renderFrontmatter =\n typeof renderFrontmatterValue === \"boolean\"\n ? renderFrontmatterValue\n : await renderFrontmatterValue;\n const previewMarkdownHtml = await renderMarkdown(previewMarkdown, {\n renderFrontmatter,\n });\n if (!this.isRenderTokenCurrent(renderToken)) {\n return;\n }\n const resolvedPreviewHtml = this.rewriteWorkspacePreviewHtml(\n previewMarkdownHtml,\n basePath,\n );\n\n if (!this.isRenderTokenCurrent(renderToken)) {\n return;\n }\n\n setSanitizedHtml(content, resolvedPreviewHtml, previewSanitizeOptions);\n this.wrapCodeLines(content);\n await this.resolveMarkdownImages(content, basePath);\n }\n\n async requestCloseViewer(): Promise<boolean> {\n if (!(await this.canDismissViewer())) {\n return false;\n }\n\n await this.exitFullscreenIfActive();\n\n fileViewerStore.closeFile();\n\n return true;\n }\n\n async requestConfirmation(options: {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n }): Promise<boolean> {\n const appShell = document.querySelector(\"shadow-claw\") as any;\n if (appShell && typeof appShell.requestDialog === \"function\") {\n return await appShell.requestDialog({ mode: \"confirm\", ...options });\n }\n\n return false;\n }\n\n async requestNativeFullscreen(target: HTMLElement): Promise<void> {\n const request =\n (target as any).requestFullscreen ||\n (target as any).webkitRequestFullscreen;\n if (typeof request !== \"function\") {\n throw new Error(\"Native fullscreen unavailable\");\n }\n\n await Promise.resolve(request.call(target));\n }\n\n /**\n * Resolves relative image src attributes in rendered markdown by loading the\n * corresponding files from OPFS and replacing the src with an object URL.\n */\n async resolveMarkdownImages(content: HTMLElement, filePath: string) {\n if (!this.db) {\n return;\n }\n\n const images = Array.from(content.querySelectorAll(\"img\"));\n if (images.length === 0) {\n return;\n }\n\n await Promise.all(\n images.map(async (img) => {\n const src = img.getAttribute(\"src\") || \"\";\n if (!src || /^(?:blob:|data:|#)/u.test(src)) {\n return;\n }\n\n const routeTarget = this.getWorkspaceRouteTarget(src, {\n allowCrossGroup: true,\n });\n const target =\n routeTarget ||\n (() => {\n const path = this.resolveWorkspaceLinkPath(src, filePath);\n if (!path) {\n return null;\n }\n\n return {\n groupId: orchestratorStore.activeGroupId,\n path,\n };\n })();\n\n if (!target) {\n return;\n }\n\n try {\n const bytes = await readGroupFileBytes(\n this.db!,\n target.groupId,\n target.path,\n );\n const ext = target.path.split(\".\").pop()?.toLowerCase() || \"\";\n const mimeType = this.mimeTypeForImageExt(ext);\n\n const blobBytes = new Uint8Array(bytes.byteLength);\n blobBytes.set(bytes);\n\n const dataUrl = await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = reject;\n reader.readAsDataURL(new Blob([blobBytes], { type: mimeType }));\n });\n\n img.src = dataUrl;\n } catch {\n // File not found or unreadable — leave src as-is.\n }\n }),\n );\n }\n\n async resolveRelativeImagesInHtml(html: string, filePath: string) {\n if (!this.db || !html) {\n return html;\n }\n\n const parsed = new DOMParser().parseFromString(html, \"text/html\");\n const images = Array.from(parsed.querySelectorAll(\"img\"));\n if (images.length === 0) {\n return html;\n }\n\n await Promise.all(\n images.map(async (img) => {\n const src = img.getAttribute(\"src\") || \"\";\n if (!src || /^(?:blob:|data:|#)/u.test(src)) {\n return;\n }\n\n const routeTarget = this.getWorkspaceRouteTarget(src, {\n allowCrossGroup: true,\n });\n const target =\n routeTarget ||\n (() => {\n const path = this.resolveWorkspaceLinkPath(src, filePath);\n if (!path) {\n return null;\n }\n\n return {\n groupId: orchestratorStore.activeGroupId,\n path,\n };\n })();\n\n if (!target) {\n return;\n }\n\n try {\n const bytes = await readGroupFileBytes(\n this.db!,\n target.groupId,\n target.path,\n );\n const ext = target.path.split(\".\").pop()?.toLowerCase() || \"\";\n const mimeType = this.mimeTypeForImageExt(ext);\n\n const blobBytes = new Uint8Array(bytes.byteLength);\n blobBytes.set(bytes);\n\n const dataUrl = await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = reject;\n reader.readAsDataURL(new Blob([blobBytes], { type: mimeType }));\n });\n\n img.setAttribute(\"src\", dataUrl);\n } catch {\n // File not found or unreadable — leave src as-is.\n }\n }),\n );\n\n return parsed.body.innerHTML;\n }\n\n async toggleFullscreenMode(modal: Element) {\n const fullscreenTarget = this.getFullscreenTarget(modal);\n if (!fullscreenTarget) {\n return;\n }\n\n if (this.canUseNativeFullscreen(fullscreenTarget)) {\n const isAlreadyFullscreen = this.isTargetInFullscreen(fullscreenTarget);\n\n try {\n if (isAlreadyFullscreen) {\n await this.exitNativeFullscreen();\n this.isFullscreenMode = false;\n } else {\n await this.requestNativeFullscreen(fullscreenTarget);\n this.isFullscreenMode = true;\n }\n } catch {\n // If native fullscreen fails (permission/user gesture), keep fallback UX.\n this.isFullscreenMode = !this.isFullscreenMode;\n }\n\n this.applyFullscreenMode(modal);\n\n return;\n }\n\n this.isFullscreenMode = !this.isFullscreenMode;\n this.applyFullscreenMode(modal);\n }\n\n async updateView(renderToken: number = this.viewRenderToken) {\n const file = fileViewerStore.file;\n const root = this.shadowRoot;\n if (!root || !file) {\n return;\n }\n\n const modal = root.querySelector(\".file-modal\");\n if (!(modal instanceof HTMLElement)) {\n return;\n }\n\n this.applyFullscreenMode(modal);\n\n const content = modal.querySelector(\".file-content\");\n const previewBtn = modal.querySelector(\".modal-preview-btn\");\n const modalBody = modal.querySelector(\".modal-body\");\n\n if (!(content instanceof HTMLElement)) {\n return;\n }\n\n content.classList.remove(\"file-content--iframe\");\n\n const workingFile = this.getWorkingSourceFile(file, modal);\n const canEdit = file.kind === \"text\";\n\n if (previewBtn instanceof HTMLButtonElement) {\n previewBtn.setAttribute(\"aria-pressed\", String(this.isFilePreviewMode));\n previewBtn.setAttribute(\n \"aria-label\",\n this.isFilePreviewMode\n ? \"Switch to raw text view\"\n : \"Switch to preview mode\",\n );\n }\n\n // Get editor elements\n const editorContainer = modal.querySelector(\".file-editor-container\");\n const editBtn = modal.querySelector(\".modal-edit-btn\");\n const saveBtn = modal.querySelector(\".modal-save-btn\");\n const shareBtn = modal.querySelector(\".modal-share-btn\");\n const closeBtn = modal.querySelector(\".modal-close-btn\");\n const cancelBtn = modal.querySelector(\".modal-cancel-btn\");\n\n if (shareBtn instanceof HTMLButtonElement) {\n const canShare = this.canShareCurrentFile(file);\n shareBtn.classList.toggle(\"hidden\", !canShare);\n shareBtn.disabled = !canShare;\n }\n\n if (closeBtn instanceof HTMLButtonElement) {\n const isDirty = this.hasUnsavedChanges();\n closeBtn.disabled = false;\n closeBtn.setAttribute(\n \"aria-label\",\n isDirty ? \"Close file viewer (unsaved changes)\" : \"Close file viewer\",\n );\n closeBtn.title = isDirty ? \"Close (you have unsaved changes)\" : \"Close\";\n }\n\n // Save and Cancel are driven purely by dirty state, independent of view mode.\n const isDirty = this.hasUnsavedChanges();\n if (saveBtn instanceof HTMLButtonElement) {\n saveBtn.classList.toggle(\"hidden\", !isDirty);\n }\n\n if (cancelBtn instanceof HTMLButtonElement) {\n cancelBtn.classList.toggle(\"hidden\", !isDirty);\n }\n\n if (this.isFilePreviewMode) {\n modalBody?.classList.remove(\"modal-body--editing\");\n\n content.classList.remove(\"hidden\");\n editorContainer?.classList.remove(\"active\");\n\n if (editBtn instanceof HTMLButtonElement) {\n editBtn.setAttribute(\"aria-pressed\", \"false\");\n editBtn.setAttribute(\"aria-label\", \"Edit file\");\n editBtn.classList.toggle(\"hidden\", !canEdit);\n }\n\n await this.renderPreview(content, workingFile, renderToken);\n\n return;\n }\n\n if (!this.isRenderTokenCurrent(renderToken)) {\n return;\n }\n\n if (this.isFileEditMode && canEdit) {\n modalBody?.classList.add(\"modal-body--editing\");\n\n content.classList.add(\"hidden\");\n editorContainer?.classList.add(\"active\");\n\n if (editBtn instanceof HTMLButtonElement) {\n editBtn.setAttribute(\"aria-pressed\", \"true\");\n editBtn.setAttribute(\"aria-label\", \"Switch to raw text view\");\n editBtn.classList.remove(\"hidden\");\n }\n\n const editor = editorContainer?.querySelector(\".file-editor\");\n if (editor instanceof HTMLTextAreaElement) {\n editor.setAttribute(\"tab-size\", \"2\");\n\n const language = this.getLanguageFromFilename(file.name);\n if (language) {\n editor.setAttribute(\"language\", language);\n } else {\n editor.removeAttribute(\"language\");\n }\n\n if (!this.isEditorDirty) {\n const targetValue = file.content || \"\";\n if (editor.value !== targetValue) {\n editor.value = targetValue;\n }\n\n this.updateEditorHighlight(editor.value);\n } else if (typeof workingFile?.content === \"string\") {\n if (editor.value !== workingFile.content) {\n editor.value = workingFile.content;\n }\n\n this.updateEditorHighlight(editor.value);\n }\n\n editor.dispatchEvent(new Event(\"scroll\"));\n }\n } else {\n modalBody?.classList.remove(\"modal-body--editing\");\n\n content.classList.remove(\"hidden\");\n editorContainer?.classList.remove(\"active\");\n\n if (editBtn instanceof HTMLButtonElement) {\n editBtn.setAttribute(\"aria-pressed\", \"false\");\n editBtn.setAttribute(\"aria-label\", \"Edit file\");\n editBtn.classList.toggle(\"hidden\", !canEdit);\n }\n\n content.classList.add(\"file-content--raw\");\n content.classList.remove(\"file-content--preview\", \"file-content--iframe\");\n\n if (file.kind === \"binary\") {\n content.textContent = `Binary file (${file.mimeType || \"application/octet-stream\"}). Switch to Preview to view.`;\n } else {\n content.textContent = workingFile.content || \"\";\n }\n }\n }\n\n private syncIframeTheme(): void {\n if (!this.previewFrameWindow) {\n return;\n }\n\n const isDark = document.documentElement.classList.contains(\"dark-mode\");\n const styles = getComputedStyle(document.documentElement);\n const customProperties: Record<string, string> = {};\n\n for (let i = 0; i < styles.length; i++) {\n const prop = styles[i];\n if (prop.startsWith(\"--\")) {\n customProperties[prop] = styles.getPropertyValue(prop);\n }\n }\n\n this.previewFrameWindow.postMessage(\n {\n type: \"shadow-claw-theme-update\",\n theme: isDark ? \"dark\" : \"light\",\n customProperties,\n },\n \"*\",\n );\n }\n\n /**\n * Handle a storage proxy request from a sandboxed iframe.\n * Performs the requested storage operation in the parent's origin context\n * using a namespaced IndexedDB store, then posts the result back.\n */\n private async handleStorageProxyRequest(\n source: WindowProxy,\n requestId: string,\n method: string,\n args: Record<string, unknown>,\n ): Promise<void> {\n if (!requestId) {\n return;\n }\n\n const currentFile = fileViewerStore.file;\n const pageKey = currentFile?.path || currentFile?.name || \"__default__\";\n\n try {\n let result: unknown;\n\n switch (method) {\n // localStorage-style operations\n case \"setItem\":\n await iframeStorageSet(\n pageKey,\n String(args.key || \"\"),\n args.value as string,\n );\n break;\n case \"removeItem\":\n await iframeStorageDelete(pageKey, String(args.key || \"\"));\n break;\n case \"clear\":\n await iframeStorageClear(pageKey);\n break;\n case \"getAllItems\":\n result = await iframeStorageGetAll(pageKey);\n break;\n\n // IndexedDB-style operations\n case \"idb-get\":\n result = await iframeStorageGet(\n `${pageKey}::idb::${args.dbName}::${args.storeName}`,\n String(args.key || \"\"),\n );\n break;\n case \"idb-getAll\":\n result = await iframeStorageGetAll(\n `${pageKey}::idb::${args.dbName}::${args.storeName}`,\n );\n break;\n case \"idb-put\": {\n const idbKey =\n args.key != null ? String(args.key) : `__auto_${Date.now()}`;\n await iframeStorageSet(\n `${pageKey}::idb::${args.dbName}::${args.storeName}`,\n idbKey,\n args.value,\n );\n result = idbKey;\n break;\n }\n case \"idb-delete\":\n await iframeStorageDelete(\n `${pageKey}::idb::${args.dbName}::${args.storeName}`,\n String(args.key || \"\"),\n );\n break;\n case \"idb-clear\":\n await iframeStorageClear(\n `${pageKey}::idb::${args.dbName}::${args.storeName}`,\n );\n break;\n case \"idb-deleteDatabase\":\n await iframeStorageClear(\n `${pageKey}::idb::${args.dbName}::__default__`,\n );\n break;\n default:\n throw new Error(`Unknown storage proxy method: ${method}`);\n }\n\n source.postMessage(\n {\n type: \"shadow-claw-storage-proxy-result\",\n requestId,\n result: result ?? null,\n },\n \"*\",\n );\n } catch (err) {\n source.postMessage(\n {\n type: \"shadow-claw-storage-proxy-result\",\n requestId,\n error: err instanceof Error ? err.message : String(err),\n },\n \"*\",\n );\n }\n }\n\n private async reloadPreviewWithSearchParams(\n searchParams: string,\n ): Promise<void> {\n const file = fileViewerStore.file;\n if (!file) {\n return;\n }\n\n const root = this.shadowRoot;\n const iframe = root?.querySelector(\n \".file-viewer__iframe\",\n ) as HTMLIFrameElement;\n if (!iframe) {\n return;\n }\n\n this.previewFrameWindow = null;\n setTrustedSrcdoc(\n iframe,\n await this.buildIframePreviewSrcdoc(file, searchParams),\n );\n }\n}\n\nif (!customElements.get(elementName)) {\n customElements.define(elementName, ShadowClawFileViewer);\n}\n"],"mappings":"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"}
|