@hienlh/ppm 0.18.13 → 0.18.15
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/.rdtest2-cf.out +0 -0
- package/CHANGELOG.md +23 -0
- package/CLAUDE.md +3 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +18 -0
- package/assets/skills/ppm/references/http-api.md +8 -1
- package/dist/web/assets/{adaptive-context-menu-CbgPYQmj.js → adaptive-context-menu-ChBZWLLq.js} +1 -1
- package/dist/web/assets/{ai-resource-editor-unM2HNmg.js → ai-resource-editor-C8aAY8Po.js} +1 -1
- package/dist/web/assets/{ai-settings-section-CdktdrwF.js → ai-settings-section-ERu1WiZc.js} +1 -1
- package/dist/web/assets/{angular-html-DcpbdcNG.js → angular-html-CXgHIQ2U.js} +1 -1
- package/dist/web/assets/{angular-ts-Bv_WIk34.js → angular-ts-C8renMV9.js} +1 -1
- package/dist/web/assets/api-client-WpZ2FDHg.js +1 -0
- package/dist/web/assets/api-settings-BgSEE6et.js +1 -0
- package/dist/web/assets/{api-settings-BdCtex9i.js → api-settings-R59c66DE.js} +1 -1
- package/dist/web/assets/{api-themes-pRRoLvgD.js → api-themes-DKxrwJda.js} +1 -1
- package/dist/web/assets/{apl-D5_lLszu.js → apl-DkGH8laI.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-CCalSKAt.js +1 -0
- package/dist/web/assets/{astro-CBHwddYL.js → astro-tHUd8Zlg.js} +1 -1
- package/dist/web/assets/{audio-preview-BD1iDovf.js → audio-preview-B_C6Dpvz.js} +1 -1
- package/dist/web/assets/{blade-DGe1d2Pq.js → blade-BbKpjIYK.js} +1 -1
- package/dist/web/assets/{bsl-2lyAzRJA.js → bsl-DA0UYto0.js} +1 -1
- package/dist/web/assets/{button-2WCAS8dI.js → button-DBSpDPS0.js} +1 -1
- package/dist/web/assets/{cairo-DjzZeJrq.js → cairo-79ayucbB.js} +1 -1
- package/dist/web/assets/chat-tab-BraiJsYG.js +15 -0
- package/dist/web/assets/{cobol-cC3XIuAJ.js → cobol-DSS2EOYo.js} +1 -1
- package/dist/web/assets/code-editor-lhmLNhXu.js +10 -0
- package/dist/web/assets/{coffee-4eGboVoU.js → coffee-DvSxq2iD.js} +1 -1
- package/dist/web/assets/{conflict-editor-DdJag4QK.js → conflict-editor-C4VCv51R.js} +1 -1
- package/dist/web/assets/{context-menu-BO1c9jKy.js → context-menu-BpwUny-o.js} +1 -1
- package/dist/web/assets/{cpp-DF9_G-OU.js → cpp-BhWZ-FSn.js} +1 -1
- package/dist/web/assets/{crystal-OavZlzcm.js → crystal-yP2OeF-f.js} +1 -1
- package/dist/web/assets/{csv-preview-DnXwouF3.js → csv-preview-D46W_icb.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-B9Gpjm3l.js → data-grid-overlay-editor-DeGkPYtA.js} +1 -1
- package/dist/web/assets/{database-viewer-Dk8oGyZx.js → database-viewer-DFI4YtrH.js} +1 -1
- package/dist/web/assets/{dialog-B-l2ZxVm.js → dialog-RIpeb87v.js} +1 -1
- package/dist/web/assets/diff-viewer-eaNOLcBL.js +4 -0
- package/dist/web/assets/{docx-preview-DAdHPlhZ.js → docx-preview-Cbj-pOK3.js} +1 -1
- package/dist/web/assets/{edge-TzYh8OlN.js → edge-D3K9cd-p.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-DlwP3UIU.js → edit-diff-preview-DDqy3KLA.js} +1 -1
- package/dist/web/assets/{elixir-Cy3RhKKH.js → elixir-D4PBmsLp.js} +1 -1
- package/dist/web/assets/{elm-BTBZdweK.js → elm-DSpXjuaH.js} +1 -1
- package/dist/web/assets/{erb-dv1mI0y4.js → erb-CaYZMTJW.js} +1 -1
- package/dist/web/assets/{erlang-DjeiDrkl.js → erlang-DX5BFqJj.js} +1 -1
- package/dist/web/assets/{esm-FRwvcesu.js → esm-Cv7HsFnk.js} +1 -1
- package/dist/web/assets/explorer-body-BxbSttfl.js +2 -0
- package/dist/web/assets/explorer-window-content-DUqQCC7A.js +1 -0
- package/dist/web/assets/{extension-store-DUaZINyC.js → extension-store-B1EClUAr.js} +1 -1
- package/dist/web/assets/{extension-webview-W0qRfaAU.js → extension-webview-BaGvDk8v.js} +1 -1
- package/dist/web/assets/{file-store-yReVbR8q.js → file-store-m9crh6uq.js} +1 -1
- package/dist/web/assets/{fortran-fixed-form-BCH9DAIJ.js → fortran-fixed-form-B0bAufUe.js} +1 -1
- package/dist/web/assets/{fsharp-C93NYKYD.js → fsharp-C2AL2b1M.js} +1 -1
- package/dist/web/assets/{gdresource-BcIEE2eX.js → gdresource-DRQsDMNI.js} +1 -1
- package/dist/web/assets/{git-commit-BVjlXEy8.js → git-commit-GtBdnrzk.js} +1 -1
- package/dist/web/assets/{git-log-panel-2_4HuP47.js → git-log-panel-hwV1flSO.js} +1 -1
- package/dist/web/assets/{git-rebase-Bj_21B1V.js → git-rebase-h_0CGA6F.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-DAUrJCqi.js +1 -0
- package/dist/web/assets/glide-data-grid-YsN-xm6x.js +138 -0
- package/dist/web/assets/{glimmer-js-C20yj4Zv.js → glimmer-js-Bxwu93bS.js} +1 -1
- package/dist/web/assets/{glimmer-ts-ipbYC7kh.js → glimmer-ts-CIUYdR4E.js} +1 -1
- package/dist/web/assets/{glsl-Dovazu3t.js → glsl-CfxLI5jn.js} +1 -1
- package/dist/web/assets/{graphql-DpMlM7hC.js → graphql-CstqDPde.js} +1 -1
- package/dist/web/assets/group-chat-tab-B7mJO1gG.js +1 -0
- package/dist/web/assets/{hack-gc7LCBuV.js → hack-Bjqnssb5.js} +1 -1
- package/dist/web/assets/{haml-vtlFm9gm.js → haml-lVc-DfbM.js} +1 -1
- package/dist/web/assets/hand-x0ejq3fS.js +1 -0
- package/dist/web/assets/{handlebars-DGKhpCji.js → handlebars-Yy6fPQI_.js} +1 -1
- package/dist/web/assets/{html-derivative-C3oTSSCN.js → html-derivative-CchzCY1z.js} +1 -1
- package/dist/web/assets/{html-DvfhQbXb.js → html-lqtcy6-2.js} +1 -1
- package/dist/web/assets/{http-SG6zLTo7.js → http-ChclRrko.js} +1 -1
- package/dist/web/assets/{hurl-BWXsYlqW.js → hurl-CoOK7sXa.js} +1 -1
- package/dist/web/assets/{hxml-DUdMzaoh.js → hxml-fZSZ7Iyt.js} +1 -1
- package/dist/web/assets/{image-preview-DxgFOV1T.js → image-preview-ClAcqDlL.js} +1 -1
- package/dist/web/assets/index-CtJbMNNI.css +2 -0
- package/dist/web/assets/index-H_gScEOk.js +52 -0
- package/dist/web/assets/info-3K5VOQVL-Cx1ZfJbp.js +1 -0
- package/dist/web/assets/{input-DuAF-Stj.js → input-DXPgUtxi.js} +1 -1
- package/dist/web/assets/{jinja-955w9RKM.js → jinja-Y0w_KBdE.js} +1 -1
- package/dist/web/assets/{jison-WWfqPo50.js → jison-BILj3F2e.js} +1 -1
- package/dist/web/assets/{julia-BFrfnaNl.js → julia-DRfOPDts.js} +1 -1
- package/dist/web/assets/{just-BrZdyR_I.js → just-n3U_oODO.js} +1 -1
- package/dist/web/assets/keybindings-store-BqctreaI.js +1 -0
- package/dist/web/assets/{keybindings-store-0Wqfa7Qp.js → keybindings-store-D-CHdq-G.js} +1 -1
- package/dist/web/assets/keyboard-DBBaoQSu.js +1 -0
- package/dist/web/assets/{latex-CwtPPASD.js → latex-D6gztEOL.js} +1 -1
- package/dist/web/assets/{liquid-CYZuvDDd.js → liquid-DPqCEVb9.js} +1 -1
- package/dist/web/assets/{lua-BV095ZyY.js → lua-I40KPUm-.js} +1 -1
- package/dist/web/assets/markdown-renderer-BwOkiZC1.js +1 -0
- package/dist/web/assets/{markdown-renderer-CnRcKK3d.js → markdown-renderer-oJ9jPdQ2.js} +3 -3
- package/dist/web/assets/{marko-CNeljZ1C.js → marko-DMjsThSW.js} +1 -1
- package/dist/web/assets/{mdc-JfGapShy.js → mdc-CN2alsbo.js} +1 -1
- package/dist/web/assets/{media-url-Bm4PsduE.js → media-url-COUvasjn.js} +1 -1
- package/dist/web/assets/mobile-bottom-sheet-Cj1YBq-c.js +1 -0
- package/dist/web/assets/mobile-explorer-sheet-D1nM0Ik1.js +1 -0
- package/dist/web/assets/{nextflow-DD5C8nqX.js → nextflow-CGa4JeZ6.js} +1 -1
- package/dist/web/assets/{nginx-Ca7B__x_.js → nginx-CmqrIj84.js} +1 -1
- package/dist/web/assets/{nim-B8FogsDw.js → nim-CqhmTeMa.js} +1 -1
- package/dist/web/assets/notification-store-n-XEQ5pH.js +1 -0
- package/dist/web/assets/{number-overlay-editor-DG9xJwEG.js → number-overlay-editor-BEzJ1YeD.js} +1 -1
- package/dist/web/assets/{overview-panel-s53bnl0q.js → overview-panel-Bf9Gn8qV.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-Bqwiy7dz.js +1 -0
- package/dist/web/assets/{panel-store-B4rijFKN.js → panel-store-UWCH6B-_.js} +1 -1
- package/dist/web/assets/{pdf-preview-DYt3aBzM.js → pdf-preview-BMHM5cR2.js} +1 -1
- package/dist/web/assets/{perl-BR78hS8R.js → perl-BOwpb6Tb.js} +1 -1
- package/dist/web/assets/{php-DXBOMC9z.js → php-wT9fVxxu.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-BXSJ2God.js +1 -0
- package/dist/web/assets/{postgres-viewer-BvoWSuoZ.js → postgres-viewer-D8rfEY5b.js} +3 -3
- package/dist/web/assets/process-table-CsQ-hDJr.js +1 -0
- package/dist/web/assets/{project-store-BuY7rxn_.js → project-store-CKAOr23O.js} +1 -1
- package/dist/web/assets/{pug-CvTwVVKV.js → pug-DdlNnj-p.js} +1 -1
- package/dist/web/assets/{qml-CPSoZ1-B.js → qml-C5zBdydf.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-D6XrM7HH.js +1 -0
- package/dist/web/assets/{razor-BUA1YKtF.js → razor-DqcJX4iq.js} +1 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-CTiipn4k.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-view-Cf5B0dKo.js +1 -0
- package/dist/web/assets/remote-desktop-stats-overlay-vhJBIW7s.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-wCJUfI6G.js +1 -0
- package/dist/web/assets/{rst-BJsq7ISz.js → rst-DiMiMYUO.js} +1 -1
- package/dist/web/assets/{ruby-DSDMeYf5.js → ruby-DK62iflA.js} +1 -1
- package/dist/web/assets/{run-in-terminal-C9xpskFn.js → run-in-terminal-DJSL6nwZ.js} +1 -1
- package/dist/web/assets/{sas-B1nJOjbN.js → sas-6QPGJRa5.js} +1 -1
- package/dist/web/assets/{scroll-area-DBcG1fQo.js → scroll-area-DXGXeiRz.js} +1 -1
- package/dist/web/assets/{scss-BZFyRiQn.js → scss-DmUqh48_.js} +1 -1
- package/dist/web/assets/{send-to-chat-BIg70MUZ.js → send-to-chat-BOony0sO.js} +1 -1
- package/dist/web/assets/settings-store-BpcY5aYE.js +2 -0
- package/dist/web/assets/settings-tab-BVqRO01j.js +1 -0
- package/dist/web/assets/settings-tab-FH581A_i.js +3 -0
- package/dist/web/assets/{shaderlab-laINRXBo.js → shaderlab-DopFR1mi.js} +1 -1
- package/dist/web/assets/{shellsession-BpOOvWVR.js → shellsession-Bp_TGuXb.js} +1 -1
- package/dist/web/assets/{soy-BW4d91Sa.js → soy-DEB9KEFb.js} +1 -1
- package/dist/web/assets/{sparql-BsvvyoHn.js → sparql-C8lEwO1p.js} +1 -1
- package/dist/web/assets/{sql-query-editor-qQce5QJ6.js → sql-query-editor-MMfk0Kbz.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-yhc0YNvu.js → sqlite-viewer-vglzrgnZ.js} +1 -1
- package/dist/web/assets/{stata-K-dZInUt.js → stata-DVep4apN.js} +1 -1
- package/dist/web/assets/{surrealql-CpNp2sgf.js → surrealql-fSlJApOA.js} +1 -1
- package/dist/web/assets/{svelte-BG6iBA8R.js → svelte-DezWBEDi.js} +1 -1
- package/dist/web/assets/{switch-_NcrktLe.js → switch-DqL_ZjB_.js} +1 -1
- package/dist/web/assets/system-monitor-body-BYUfyF8f.js +2 -0
- package/dist/web/assets/system-monitor-tab-CKGXB8lH.js +1 -0
- package/dist/web/assets/{system-monitor-window-content-CaOhD0AU.js → system-monitor-window-content-CiJ2yIsr.js} +1 -1
- package/dist/web/assets/tab-host-window-content-DYlXR0cg.js +1 -0
- package/dist/web/assets/{tab-store-tFnyPmm4.js → tab-store-D2thn4Vv.js} +1 -1
- package/dist/web/assets/team-member-sheet-Bnygu7Xw.js +2 -0
- package/dist/web/assets/{team-member-window-content-B1jkKkDi.js → team-member-window-content-qrgFTC96.js} +1 -1
- package/dist/web/assets/{templ-gxNKXmt3.js → templ-D0zB42a9.js} +1 -1
- package/dist/web/assets/{terminal-tab-UvwM0sty.js → terminal-tab-D_-R5rGm.js} +3 -3
- package/dist/web/assets/{tex-C0ON27g5.js → tex-BJiPijcH.js} +1 -1
- package/dist/web/assets/{tool-cards-jB7GT-wj.js → tool-cards-BW7Xc20J.js} +4 -4
- package/dist/web/assets/treemap-KZPCXAKY-BobWhcHN.js +1 -0
- package/dist/web/assets/{ts-tags-BX_CTVgQ.js → ts-tags-Dcr4u6y5.js} +1 -1
- package/dist/web/assets/{twig-CwL7XnU0.js → twig-B-SQU0bg.js} +1 -1
- package/dist/web/assets/{use-blob-url-DcRcjNTE.js → use-blob-url-BtPlqwLr.js} +1 -1
- package/dist/web/assets/use-monaco-theme-DQY1ZSaf.js +1 -0
- package/dist/web/assets/{use-open-team-member-1hRsHLKg.js → use-open-team-member-C5LQ_TCM.js} +1 -1
- package/dist/web/assets/use-visual-viewport-pVxLfE5B.js +1 -0
- package/dist/web/assets/{use-websocket-rxJLbFqy.js → use-websocket-l39Odhlp.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-CHTa6D69.js → vendor-mermaid-CtDsSxbM.js} +1 -1
- package/dist/web/assets/{video-preview-DMhnf2Gi.js → video-preview-C5AhkIDl.js} +1 -1
- package/dist/web/assets/{vue-Bykm6wSS.js → vue-Cw10Sfbh.js} +1 -1
- package/dist/web/assets/{vue-html-CETdK_iV.js → vue-html-Cc5C_Z_w.js} +1 -1
- package/dist/web/assets/{vue-vine-DiJb6fO5.js → vue-vine-BuNMlnvu.js} +1 -1
- package/dist/web/assets/window-pip-registry-C7oz3Dfy.js +1 -0
- package/dist/web/assets/window-store-B5ZswdYg.js +1 -0
- package/dist/web/assets/{xml-BNw8J5YW.js → xml-DqT1wkky.js} +1 -1
- package/dist/web/assets/{xsl-CsG9L31b.js → xsl-DLkge3A2.js} +1 -1
- package/dist/web/index.html +45 -42
- package/dist/web/sw.js +1 -1
- package/docs/architecture/ai-chat-and-providers.md +3 -0
- package/docs/architecture/workspace-and-ui.md +8 -0
- package/docs/design-guidelines.md +3 -2
- package/package.json +1 -1
- package/src/cli/commands/backup-cmd.ts +119 -0
- package/src/index.ts +3 -0
- package/src/providers/claude-agent-sdk.ts +29 -1
- package/src/server/index.ts +42 -15
- package/src/server/routes/accounts.ts +30 -2
- package/src/server/routes/chat.ts +8 -1
- package/src/server/routes/named-tunnel.ts +5 -2
- package/src/server/routes/remote-desktop.ts +64 -0
- package/src/server/routes/settings.ts +1 -0
- package/src/server/ws/chat.ts +126 -7
- package/src/server/ws/remote-desktop.ts +86 -0
- package/src/services/account.service.ts +106 -23
- package/src/services/db-backup/db-backup-paths.ts +66 -0
- package/src/services/db-backup/db-backup-restore.ts +105 -0
- package/src/services/db-backup/db-backup-retention.ts +96 -0
- package/src/services/db-backup/db-backup-sync.ts +113 -0
- package/src/services/db-backup/db-backup.service.ts +61 -0
- package/src/services/db.service.ts +29 -1
- package/src/services/fs-credential-path-guard.ts +19 -1
- package/src/services/named-tunnel/cloudflared-login.service.ts +2 -2
- package/src/services/nested-subagent-spy.ts +206 -0
- package/src/services/remote-desktop/access-unit-assembler.ts +90 -0
- package/src/services/remote-desktop/avc1-codec-string.ts +18 -0
- package/src/services/remote-desktop/nal-splitter.ts +100 -0
- package/src/services/remote-desktop/remote-desktop-capture.ts +120 -0
- package/src/services/remote-desktop/remote-desktop-encoder-args.ts +42 -0
- package/src/services/remote-desktop/remote-desktop-flag.ts +10 -0
- package/src/services/remote-desktop/remote-desktop-input.ts +217 -0
- package/src/services/remote-desktop/remote-desktop-nonce.ts +38 -0
- package/src/services/remote-desktop/remote-desktop-session.ts +189 -0
- package/src/services/remote-desktop/remote-desktop-vk-map.ts +41 -0
- package/src/services/subagent-transcript-merger.ts +92 -75
- package/src/services/subprocess-retention.ts +29 -6
- package/src/services/supervisor.ts +58 -0
- package/src/services/team-member-activity/subagent-transcript-index.ts +56 -0
- package/src/types/chat.ts +2 -0
- package/src/web/app.tsx +8 -0
- package/src/web/components/chat/account-dialogs.tsx +11 -4
- package/src/web/components/chat/question-card.tsx +9 -2
- package/src/web/components/chat/usage-badge.tsx +17 -3
- package/src/web/components/floating-window/floating-window.tsx +8 -1
- package/src/web/components/floating-window/open-tab-in-pip.ts +78 -0
- package/src/web/components/floating-window/window-content-registry.ts +2 -0
- package/src/web/components/floating-window/window-pip-registry.ts +46 -0
- package/src/web/components/floating-window/window-store-types.ts +1 -1
- package/src/web/components/layout/mobile-drawer.tsx +38 -27
- package/src/web/components/layout/nav-section-rail.tsx +10 -2
- package/src/web/components/layout/tab-pop-out-menu-item.tsx +25 -2
- package/src/web/components/remote-desktop/open-remote-desktop.ts +26 -0
- package/src/web/components/remote-desktop/remote-desktop-coords.ts +98 -0
- package/src/web/components/remote-desktop/remote-desktop-frame-timestamp.ts +21 -0
- package/src/web/components/remote-desktop/remote-desktop-gesture-classifiers.ts +56 -0
- package/src/web/components/remote-desktop/remote-desktop-mobile-key-bar.tsx +131 -0
- package/src/web/components/remote-desktop/remote-desktop-mobile-sheet.tsx +43 -0
- package/src/web/components/remote-desktop/remote-desktop-mobile-toolbar.tsx +79 -0
- package/src/web/components/remote-desktop/remote-desktop-mobile-view.tsx +190 -0
- package/src/web/components/remote-desktop/remote-desktop-stats-overlay.tsx +54 -0
- package/src/web/components/remote-desktop/remote-desktop-stats.ts +37 -0
- package/src/web/components/remote-desktop/remote-desktop-touch-gesture-tracker.ts +195 -0
- package/src/web/components/remote-desktop/remote-desktop-window-content.tsx +72 -0
- package/src/web/components/remote-desktop/remote-desktop-ws-url.ts +22 -0
- package/src/web/components/remote-desktop/use-h264-canvas-decoder.ts +175 -0
- package/src/web/components/remote-desktop/use-remote-desktop-available.ts +29 -0
- package/src/web/components/remote-desktop/use-remote-desktop-connection.ts +147 -0
- package/src/web/components/remote-desktop/use-remote-desktop-mobile-open-state.ts +18 -0
- package/src/web/components/remote-desktop/use-remote-desktop-touch.ts +224 -0
- package/src/web/components/remote-desktop/use-remote-desktop-virtual-keyboard.ts +50 -0
- package/src/web/components/remote-desktop/use-remote-input-capture.ts +92 -0
- package/src/web/components/tunnels/named-tunnel/named-tunnel-copy.ts +59 -59
- package/src/web/components/tunnels/named-tunnel/named-tunnel-section.tsx +2 -2
- package/src/web/hooks/use-notification-badge.ts +19 -11
- package/src/web/lib/feature-badges.ts +2 -0
- package/src/web/stores/settings-store.ts +13 -0
- package/src/web/stores/streaming-store.ts +21 -2
- package/dist/web/assets/api-client-BogqsFna.js +0 -1
- package/dist/web/assets/api-settings-DfXViPKz.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-BzFm9ELu.js +0 -1
- package/dist/web/assets/chat-tab-DzK8LGti.js +0 -15
- package/dist/web/assets/code-editor-CuMfPN9X.js +0 -10
- package/dist/web/assets/diff-viewer-eaUBjLCH.js +0 -4
- package/dist/web/assets/explorer-body-DkCkSVrN.js +0 -2
- package/dist/web/assets/explorer-window-content-MsnTVngu.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-B72vcb2r.js +0 -1
- package/dist/web/assets/glide-data-grid-B0IY6n_Q.js +0 -138
- package/dist/web/assets/group-chat-tab-DRLDHOp6.js +0 -1
- package/dist/web/assets/index-CBn4SOoT.js +0 -52
- package/dist/web/assets/index-DWpNR3nB.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-3irPxRK_.js +0 -1
- package/dist/web/assets/keybindings-store-d54pv2NK.js +0 -1
- package/dist/web/assets/markdown-renderer-BTS8ifdu.js +0 -1
- package/dist/web/assets/mobile-bottom-sheet-M5iZDX7y.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-BqK2-WuN.js +0 -1
- package/dist/web/assets/notification-store-Yvy1I8gd.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-Z5jWjFCV.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-Bq7UMi8P.js +0 -1
- package/dist/web/assets/process-table-BYwKigiD.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-BLo4BOTD.js +0 -1
- package/dist/web/assets/settings-store-GV5pkkke.js +0 -2
- package/dist/web/assets/settings-tab-BePvIcjd.js +0 -3
- package/dist/web/assets/settings-tab-Br-lJSPa.js +0 -1
- package/dist/web/assets/system-monitor-body-D8Z5QXBB.js +0 -2
- package/dist/web/assets/system-monitor-tab-BclYXFTe.js +0 -1
- package/dist/web/assets/tab-host-window-content-f_Rc5rJK.js +0 -1
- package/dist/web/assets/team-member-sheet-QDHoYCs0.js +0 -2
- package/dist/web/assets/treemap-KZPCXAKY-dyrE6SW2.js +0 -1
- package/dist/web/assets/use-monaco-theme--9tOOkDA.js +0 -1
- package/dist/web/assets/window-store-CQ1lghvv.js +0 -1
- /package/dist/web/assets/{abap-DGlrX_8G.js → abap-CKgBNk5K.js} +0 -0
- /package/dist/web/assets/{actionscript-3-CUqRtUJE.js → actionscript-3-oARhAY6c.js} +0 -0
- /package/dist/web/assets/{ada-CY3Spa33.js → ada-2vi8ASy3.js} +0 -0
- /package/dist/web/assets/{andromeeda-Lxs2TJn7.js → andromeeda-B3vMjPKd.js} +0 -0
- /package/dist/web/assets/{apache-DfxgGdgM.js → apache-DnIEr338.js} +0 -0
- /package/dist/web/assets/{apex-QVDF1dnI.js → apex-B7Qs5AY5.js} +0 -0
- /package/dist/web/assets/{api-client-oY1tC3tM.js → api-client-BkGKTjsq.js} +0 -0
- /package/dist/web/assets/{applescript-pwJ8QXh-.js → applescript-EbQNUCWb.js} +0 -0
- /package/dist/web/assets/{apply-theme-B_bMVL6a.js → apply-theme-Dd_cqGa-.js} +0 -0
- /package/dist/web/assets/{ara-mPjeX5YX.js → ara-CtHdhFRw.js} +0 -0
- /package/dist/web/assets/{asciidoc-Bf7LsDkI.js → asciidoc-BH6qin_O.js} +0 -0
- /package/dist/web/assets/{asm-rRKC1OUx.js → asm-D1XU1ACk.js} +0 -0
- /package/dist/web/assets/{aurora-x-DwQr0DkG.js → aurora-x-BkhcxkuS.js} +0 -0
- /package/dist/web/assets/{awk-Bpt768fN.js → awk-DijzB6o7.js} +0 -0
- /package/dist/web/assets/{ayu-dark-D9lwQHMs.js → ayu-dark-tysG77WC.js} +0 -0
- /package/dist/web/assets/{ayu-light-B4-ptrU5.js → ayu-light-Dg0WMETC.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-DAyRzH5Q.js → ayu-mirage--RsJCjC4.js} +0 -0
- /package/dist/web/assets/{ballerina-Cgdpj1HC.js → ballerina-DT_5-l82.js} +0 -0
- /package/dist/web/assets/{bat-4FrN36S2.js → bat-BRpDlkv0.js} +0 -0
- /package/dist/web/assets/{beancount-DkcxQER3.js → beancount--8Df-WGG.js} +0 -0
- /package/dist/web/assets/{berry-Dnuut-Ml.js → berry-Bc9fo35J.js} +0 -0
- /package/dist/web/assets/{bibtex-CCDwmbuA.js → bibtex-CwyBpp9X.js} +0 -0
- /package/dist/web/assets/{bicep-BC0ryoGM.js → bicep-DiyH2Bs7.js} +0 -0
- /package/dist/web/assets/{bird2-C50V_A-0.js → bird2-CHgK4a2A.js} +0 -0
- /package/dist/web/assets/{c-Ddorhq0U.js → c-BM1qL6-f.js} +0 -0
- /package/dist/web/assets/{c3-DdIf5r9E.js → c3-D2oOjrP7.js} +0 -0
- /package/dist/web/assets/{cadence-s9pd1Wng.js → cadence-nS45wqF6.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-C6hZV1OP.js → can-open-in-ppm-DwP9KU8o.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-CzJNTyu-.js → catppuccin-frappe-BpnJHiCj.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-BNpt-m7s.js → catppuccin-latte-Bb95Wj3h.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-FYGkfsJ5.js → catppuccin-macchiato-Btx8c17W.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-it2g5D1q.js → catppuccin-mocha-B4DZOUGI.js} +0 -0
- /package/dist/web/assets/{clarity-BVFBTjMe.js → clarity-1ps69jU6.js} +0 -0
- /package/dist/web/assets/{clipboard-BWznymz7.js → clipboard-CrHX8AYw.js} +0 -0
- /package/dist/web/assets/{clojure-BSYvXMI8.js → clojure-BklC0hKV.js} +0 -0
- /package/dist/web/assets/{cmake-DGEqH-Np.js → cmake-B573LYAQ.js} +0 -0
- /package/dist/web/assets/{codeowners-D8FCOxWg.js → codeowners-BoYeX89M.js} +0 -0
- /package/dist/web/assets/{codeql-COV0eluG.js → codeql-7Dhf5Udk.js} +0 -0
- /package/dist/web/assets/{common-lisp-xHnZUlgt.js → common-lisp-m1nxlthv.js} +0 -0
- /package/dist/web/assets/{coq-Cs_2i3Xg.js → coq-DNhGmd4a.js} +0 -0
- /package/dist/web/assets/{csharp-B1ONB4PT.js → csharp-P-nAurtS.js} +0 -0
- /package/dist/web/assets/{css-BgGQbvrZ.js → css-LYbSeh3-.js} +0 -0
- /package/dist/web/assets/{csv-CNHmQBzs.js → csv-DHZZZm7X.js} +0 -0
- /package/dist/web/assets/{csv-parser-DWR24J17.js → csv-parser-CY9Ggtg5.js} +0 -0
- /package/dist/web/assets/{cue-ZXAKzwIy.js → cue-D8yLUOle.js} +0 -0
- /package/dist/web/assets/{cypher-4PL5bmT5.js → cypher-9cbW8RYA.js} +0 -0
- /package/dist/web/assets/{d-CEsV3RT2.js → d-ZihzhxqI.js} +0 -0
- /package/dist/web/assets/{dark-plus-NtFnYSDz.js → dark-plus-C8xIA1u3.js} +0 -0
- /package/dist/web/assets/{dart-CKHn4mDf.js → dart-CBm6jKc7.js} +0 -0
- /package/dist/web/assets/{data-grid-types-CxU8oo-j.js → data-grid-types-DkEQ-Na9.js} +0 -0
- /package/dist/web/assets/{dax-Cmkj1I_M.js → dax-B3cx6YeV.js} +0 -0
- /package/dist/web/assets/{desktop-DJLalvPQ.js → desktop-C03SpXth.js} +0 -0
- /package/dist/web/assets/{diff-BnS2wpj6.js → diff-D8LnnvFY.js} +0 -0
- /package/dist/web/assets/{dist-uYjs3Wv6.js → dist-C4XoS_zo.js} +0 -0
- /package/dist/web/assets/{dist-CuIdRyUB.js → dist-Do3fljss.js} +0 -0
- /package/dist/web/assets/{docker-CovNy7ml.js → docker-DwFiOQWW.js} +0 -0
- /package/dist/web/assets/{dotenv-Gh4w3I6B.js → dotenv-CVJ_vFSQ.js} +0 -0
- /package/dist/web/assets/{dracula-NF0tAHXl.js → dracula-DMw8UACY.js} +0 -0
- /package/dist/web/assets/{dracula-soft-Cj_qBurK.js → dracula-soft-BnB3nDrA.js} +0 -0
- /package/dist/web/assets/{dream-maker-CRuZPcl7.js → dream-maker-2riXUQXo.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-BACmC9qj.js → emacs-lisp-BQdYaiB5.js} +0 -0
- /package/dist/web/assets/{everforest-dark-Dd9av4QG.js → everforest-dark-C2FPIWdj.js} +0 -0
- /package/dist/web/assets/{everforest-light-C-jsss-B.js → everforest-light-DMOWf9sD.js} +0 -0
- /package/dist/web/assets/{fennel-BJA9XnL8.js → fennel-JtSHp0vW.js} +0 -0
- /package/dist/web/assets/{fish-CKlhNSc2.js → fish-CflDcRfe.js} +0 -0
- /package/dist/web/assets/{fluent-wfglRk5D.js → fluent-D4eu6Vac.js} +0 -0
- /package/dist/web/assets/{format-bytes-utwHMTry.js → format-bytes-DR3228bu.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-BlXCdid3.js → fortran-free-form-hO4RuC9Z.js} +0 -0
- /package/dist/web/assets/{gdscript-BwAVG6Et.js → gdscript-D7n3a8VM.js} +0 -0
- /package/dist/web/assets/{gdshader-DPc_T7ib.js → gdshader-BhUmrlzG.js} +0 -0
- /package/dist/web/assets/{genie-B-zZSLCX.js → genie-VbyftqBp.js} +0 -0
- /package/dist/web/assets/{gherkin-CJ0ajpGs.js → gherkin-BZzhvUUb.js} +0 -0
- /package/dist/web/assets/{github-dark-Dz8ZkzSP.js → github-dark-C4q41woW.js} +0 -0
- /package/dist/web/assets/{github-dark-default-CNUYo_kp.js → github-dark-default-CMNi7dQX.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-241z_Ycx.js → github-dark-dimmed-BRf_-LlY.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-7r6yZZYH.js → github-dark-high-contrast-xanKBsRI.js} +0 -0
- /package/dist/web/assets/{github-light-C8gmZn-D.js → github-light-BEQeNQCs.js} +0 -0
- /package/dist/web/assets/{github-light-default-GAEgq1eA.js → github-light-default-ceQrtdXg.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-3z91352E.js → github-light-high-contrast-doKbXzgW.js} +0 -0
- /package/dist/web/assets/{gleam-C7vxW5zd.js → gleam-Chzqf4fT.js} +0 -0
- /package/dist/web/assets/{gn-CyJIXwHP.js → gn-CCN_-6fp.js} +0 -0
- /package/dist/web/assets/{gnuplot-CqLbGgPd.js → gnuplot-CIplgwwP.js} +0 -0
- /package/dist/web/assets/{go-DdDcK9aX.js → go-Cjj-9dRs.js} +0 -0
- /package/dist/web/assets/{groovy-UYHggEqH.js → groovy-PqD4K7X1.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-B4ierkJn.js → gruvbox-dark-hard-BAbpUSF-.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-DYwkDSZ6.js → gruvbox-dark-medium-BWcWXDBB.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-CVL4P-Lz.js → gruvbox-dark-soft-Dkx1okkk.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-BJ0LewUZ.js → gruvbox-light-hard-WVsDK0MM.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-CaqqjeGJ.js → gruvbox-light-medium-tiR9t7gr.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-ByKMoVNr.js → gruvbox-light-soft-HzHohaX6.js} +0 -0
- /package/dist/web/assets/{haskell-BilYRVPp.js → haskell-B1eIZfr6.js} +0 -0
- /package/dist/web/assets/{haxe-Brs9Bj1s.js → haxe-BcDdi5xr.js} +0 -0
- /package/dist/web/assets/{hcl-ClrZpol-.js → hcl-Dq-HKVni.js} +0 -0
- /package/dist/web/assets/{hjson-9PvHnYMX.js → hjson-Dr9D9WVU.js} +0 -0
- /package/dist/web/assets/{hlsl-BbBk4vqV.js → hlsl-Bo8t2FuZ.js} +0 -0
- /package/dist/web/assets/{horizon-E5Py0cny.js → horizon-DWG5IXc-.js} +0 -0
- /package/dist/web/assets/{horizon-bright-DVCsNGEk.js → horizon-bright-DFr9wTTx.js} +0 -0
- /package/dist/web/assets/{houston-JdFEax9Y.js → houston-NAVNhkup.js} +0 -0
- /package/dist/web/assets/{hy-W_W3tLKT.js → hy-DnyvUk3B.js} +0 -0
- /package/dist/web/assets/{image-gallery-5IURd6db.js → image-gallery-DoFdNF9i.js} +0 -0
- /package/dist/web/assets/{imba-CfAqJz7T.js → imba-CPbR5W_A.js} +0 -0
- /package/dist/web/assets/{ini-C_3gvKWs.js → ini-lc8_Lt0y.js} +0 -0
- /package/dist/web/assets/{java-CKqtXZ-j.js → java-B0KCo2vK.js} +0 -0
- /package/dist/web/assets/{javascript-C7gSEfae.js → javascript-YqEbNRpd.js} +0 -0
- /package/dist/web/assets/{json-BoN6e11T.js → json-Co0WtOlh.js} +0 -0
- /package/dist/web/assets/{json5-CgE7C8HW.js → json5-2Jhb0QUN.js} +0 -0
- /package/dist/web/assets/{jsonc-DjyoattY.js → jsonc-e72F11nU.js} +0 -0
- /package/dist/web/assets/{jsonl-lI82wGSw.js → jsonl-Bff8IPye.js} +0 -0
- /package/dist/web/assets/{jsonnet-CszEI8va.js → jsonnet-DRCkb-_H.js} +0 -0
- /package/dist/web/assets/{jssm-CZXDlszb.js → jssm-C6UiwVEm.js} +0 -0
- /package/dist/web/assets/{jsx-BeRz0eEz.js → jsx-u1aZlnfA.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-BOmnUiyd.js → kanagawa-dragon-De-RQFV3.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-ffU_P5w-.js → kanagawa-lotus-K8elE4QU.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-DKTJZrMu.js → kanagawa-wave-BrStl_zx.js} +0 -0
- /package/dist/web/assets/{kdl-BWECJveH.js → kdl-CLCfMeZy.js} +0 -0
- /package/dist/web/assets/{kotlin-DpVwBCSt.js → kotlin-DEEC3pNh.js} +0 -0
- /package/dist/web/assets/{kusto-BgVqjUZA.js → kusto-DTqRhCup.js} +0 -0
- /package/dist/web/assets/{laserwave-CEVCi8em.js → laserwave-DsgpUSbA.js} +0 -0
- /package/dist/web/assets/{lean-CGyfRhLJ.js → lean-Dl9MI0Y3.js} +0 -0
- /package/dist/web/assets/{less-B0_H10Ku.js → less-Bg21rao6.js} +0 -0
- /package/dist/web/assets/{lib-hrC3bruJ.js → lib-CXUwxw1M.js} +0 -0
- /package/dist/web/assets/{libesm-DVpFmwJu.js → libesm-CVkncAQz.js} +0 -0
- /package/dist/web/assets/{light-plus-DqzMqPID.js → light-plus-DGNbbK1V.js} +0 -0
- /package/dist/web/assets/{llvm-9ucnfNiF.js → llvm-91_ZX3p-.js} +0 -0
- /package/dist/web/assets/{loader-circle-Dpqcv0eS.js → loader-circle-DouKgIXy.js} +0 -0
- /package/dist/web/assets/{lock-DldbT31x.js → lock-CNxUGpTk.js} +0 -0
- /package/dist/web/assets/{log-m6A2dOSj.js → log-DSXzbq8u.js} +0 -0
- /package/dist/web/assets/{logo-ByPcsC9P.js → logo-BQRNd4tc.js} +0 -0
- /package/dist/web/assets/{luau-DFCo8nBn.js → luau-BE-TMpiZ.js} +0 -0
- /package/dist/web/assets/{make-C90w3MeA.js → make-ePYGKTpc.js} +0 -0
- /package/dist/web/assets/{markdown-DT0uywZG.js → markdown-Cst3wgMW.js} +0 -0
- /package/dist/web/assets/{material-theme-BVUO93tJ.js → material-theme-9XyvnNLb.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-xXgGDwnF.js → material-theme-darker-H1VN4MTS.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-BjStPzWB.js → material-theme-lighter-DAreBbuF.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-wFmSiKjy.js → material-theme-ocean-BpTR-3II.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-e-0CtRoe.js → material-theme-palenight-DUNzX711.js} +0 -0
- /package/dist/web/assets/{matlab-BNaNQAUH.js → matlab-BpYNufBU.js} +0 -0
- /package/dist/web/assets/{mdx-DfpVWAqO.js → mdx-BYjfe1DK.js} +0 -0
- /package/dist/web/assets/{mermaid-Bpq7wFCP.js → mermaid-DPCcIW9B.js} +0 -0
- /package/dist/web/assets/{min-dark-CL2Y0WH6.js → min-dark-DnGOAGCo.js} +0 -0
- /package/dist/web/assets/{min-light-DOgr_IdP.js → min-light-CwV-o31y.js} +0 -0
- /package/dist/web/assets/{mipsasm-C9ie2zlB.js → mipsasm-DdeCPC97.js} +0 -0
- /package/dist/web/assets/{mojo-Md2A2sJy.js → mojo-BmxxZ3iM.js} +0 -0
- /package/dist/web/assets/{monitor-4vWfqzuN.js → monitor-C835ucWH.js} +0 -0
- /package/dist/web/assets/{monokai-nbXIEySB.js → monokai-Cx6cQ-MA.js} +0 -0
- /package/dist/web/assets/{moonbit-CJ-T-s4A.js → moonbit-D2-Gj5vj.js} +0 -0
- /package/dist/web/assets/{move-DwEehLIK.js → move-DSWGoQa8.js} +0 -0
- /package/dist/web/assets/{narrat-CuF4sIKr.js → narrat-D9TnZSSu.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-1dYhfPfq.js → nextflow-groovy-BbL-8PwD.js} +0 -0
- /package/dist/web/assets/{night-owl-gZS5mfzY.js → night-owl-CZitKm5d.js} +0 -0
- /package/dist/web/assets/{night-owl-light-DDAster5.js → night-owl-light-DJVX1Pno.js} +0 -0
- /package/dist/web/assets/{nix-BlbEYs2c.js → nix-R6hr3oln.js} +0 -0
- /package/dist/web/assets/{nord-BRiPb8Vy.js → nord-ChGHya3l.js} +0 -0
- /package/dist/web/assets/{nushell-DgWicB1i.js → nushell-QQWB-GWx.js} +0 -0
- /package/dist/web/assets/{objective-c-D8mPZ42Y.js → objective-c-C0pZ6y73.js} +0 -0
- /package/dist/web/assets/{objective-cpp-B0pNXzuj.js → objective-cpp-BdzVM31a.js} +0 -0
- /package/dist/web/assets/{ocaml-lQd7aK5d.js → ocaml-D4KktNlS.js} +0 -0
- /package/dist/web/assets/{odin-CxtIOBjm.js → odin-Y-fypmGT.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-T_UFnWfe.js → one-dark-pro-BwecIxQL.js} +0 -0
- /package/dist/web/assets/{one-light-LBVqwyV-.js → one-light-Cz7UVzLU.js} +0 -0
- /package/dist/web/assets/{openscad-C5dnS6J7.js → openscad-DtRe3qYD.js} +0 -0
- /package/dist/web/assets/{pascal-CmWCWQML.js → pascal-Ck6I1fGG.js} +0 -0
- /package/dist/web/assets/{pkl-BWWOtDQk.js → pkl-DdFK94VW.js} +0 -0
- /package/dist/web/assets/{plastic-ekhupckF.js → plastic-BQSAzZwR.js} +0 -0
- /package/dist/web/assets/{play-CpCAoQRZ.js → play-CJlWpVMw.js} +0 -0
- /package/dist/web/assets/{plsql-BPsDHXx4.js → plsql-DjXg_CP0.js} +0 -0
- /package/dist/web/assets/{po-BX2FiuW2.js → po-Bw2SuM4r.js} +0 -0
- /package/dist/web/assets/{poimandres-DzXOdZcN.js → poimandres-YMK6c5VN.js} +0 -0
- /package/dist/web/assets/{polar-DDRXgJzG.js → polar-BMu17-O0.js} +0 -0
- /package/dist/web/assets/{portal-container-context-a399Hd9F.js → portal-container-context-DSGdlXrJ.js} +0 -0
- /package/dist/web/assets/{postcss-BHW6XBhx.js → postcss-DWib10RZ.js} +0 -0
- /package/dist/web/assets/{powerquery-B89c2NBb.js → powerquery-Dht4CK0b.js} +0 -0
- /package/dist/web/assets/{powershell-Dvxrd3Tu.js → powershell-DvrCg8ji.js} +0 -0
- /package/dist/web/assets/{prisma-lMK8EFLU.js → prisma-DbodYvCM.js} +0 -0
- /package/dist/web/assets/{prolog-D0YrtMG4.js → prolog-DZ-m6ysB.js} +0 -0
- /package/dist/web/assets/{proto-J0mM25aw.js → proto-HHpG3tGO.js} +0 -0
- /package/dist/web/assets/{puppet-CUT0xkhh.js → puppet-BljHe_75.js} +0 -0
- /package/dist/web/assets/{purescript-CoJWSGRp.js → purescript-DzCiFR0B.js} +0 -0
- /package/dist/web/assets/{python-BBrmuz6P.js → python-B5BQ27cC.js} +0 -0
- /package/dist/web/assets/{qmldir-CUtzs4Q7.js → qmldir-CYlcXrnn.js} +0 -0
- /package/dist/web/assets/{qss-Dm1RZ8aL.js → qss-Ce7T_TEg.js} +0 -0
- /package/dist/web/assets/{r-BGP7qZTe.js → r-Bku-2Jp_.js} +0 -0
- /package/dist/web/assets/{racket-K_6U1lqJ.js → racket-DtfSL3WR.js} +0 -0
- /package/dist/web/assets/{raku-bNSiZeW_.js → raku-CnDLsBJr.js} +0 -0
- /package/dist/web/assets/{react-X4jUntEf.js → react-Dfio3PfK.js} +0 -0
- /package/dist/web/assets/{red-uVeIEF0f.js → red-vbqcE9b-.js} +0 -0
- /package/dist/web/assets/{refresh-cw-B9iv7csb.js → refresh-cw-84mz8aOE.js} +0 -0
- /package/dist/web/assets/{reg-DSm9GWjh.js → reg-DIDLT8-A.js} +0 -0
- /package/dist/web/assets/{regexp-CljRm_j_.js → regexp-CB4h-VPu.js} +0 -0
- /package/dist/web/assets/{rel-d3JcopZg.js → rel-CiQEnWXa.js} +0 -0
- /package/dist/web/assets/{resolve-theme-DLKmm-lE.js → resolve-theme-DPTQHAy1.js} +0 -0
- /package/dist/web/assets/{riscv-CJmaELjT.js → riscv-R78iq5Rf.js} +0 -0
- /package/dist/web/assets/{ron-D0g9B1rW.js → ron-DhYENxc4.js} +0 -0
- /package/dist/web/assets/{rose-pine-DOrD2BSH.js → rose-pine-5wBeyjfJ.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-CzZQ-LCF.js → rose-pine-dawn-FpKtPCuH.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-CdmsYp7C.js → rose-pine-moon-BwcIYc7C.js} +0 -0
- /package/dist/web/assets/{rosmsg-CmDth6pO.js → rosmsg-DWIGAYMl.js} +0 -0
- /package/dist/web/assets/{rotate-ccw-DnuPzJRE.js → rotate-ccw-CNTk2J7l.js} +0 -0
- /package/dist/web/assets/{rust-DGdP6jiR.js → rust-DU_ofKgt.js} +0 -0
- /package/dist/web/assets/{sass-Dkgt2FKZ.js → sass-U9SUuYEy.js} +0 -0
- /package/dist/web/assets/{save-DxonD4y1.js → save-CtW9ojKk.js} +0 -0
- /package/dist/web/assets/{scala-BQLTON6C.js → scala-op4gjA6j.js} +0 -0
- /package/dist/web/assets/{scheme-DKlxUGCi.js → scheme-tEjkR8rL.js} +0 -0
- /package/dist/web/assets/{sdbl-C3iZJQeZ.js → sdbl-C6SSRmZg.js} +0 -0
- /package/dist/web/assets/{send-B-t5Mz26.js → send-C_sLFt56.js} +0 -0
- /package/dist/web/assets/{shallow-jwPzEunk.js → shallow-C1YoJQA-.js} +0 -0
- /package/dist/web/assets/{shellscript-BRu-ZQAx.js → shellscript-Bf2KiwQj.js} +0 -0
- /package/dist/web/assets/{shield-check-CdTiK1j2.js → shield-check-Du6HKYn9.js} +0 -0
- /package/dist/web/assets/{shield-off-DuetkXKM.js → shield-off-CWKb1MQL.js} +0 -0
- /package/dist/web/assets/{slack-dark-qkm_u2zz.js → slack-dark-oGgCey8r.js} +0 -0
- /package/dist/web/assets/{slack-ochin-BP8_8e4m.js → slack-ochin-CemlB8cE.js} +0 -0
- /package/dist/web/assets/{smalltalk-Bnz4gt07.js → smalltalk-CTE-6jrZ.js} +0 -0
- /package/dist/web/assets/{snazzy-light-fbPZg5io.js → snazzy-light-DoEIGnmz.js} +0 -0
- /package/dist/web/assets/{solarized-dark-CM0vTRoi.js → solarized-dark-CStiJyBg.js} +0 -0
- /package/dist/web/assets/{solarized-light-C4_W9mvs.js → solarized-light-CfuNycS9.js} +0 -0
- /package/dist/web/assets/{solidity-Bz6v1PoD.js → solidity-DL6sO5rd.js} +0 -0
- /package/dist/web/assets/{splunk-DyNxu-0i.js → splunk-yK4ZUFBB.js} +0 -0
- /package/dist/web/assets/{sql-DXRL1gw1.js → sql-Lw03eoN8.js} +0 -0
- /package/dist/web/assets/{ssh-config-2z1QHuOG.js → ssh-config-DeRp25TR.js} +0 -0
- /package/dist/web/assets/{stylus-D4I-VaeY.js → stylus-D8OMsPh-.js} +0 -0
- /package/dist/web/assets/{swift-C_2G-tIc.js → swift-nsl9stPV.js} +0 -0
- /package/dist/web/assets/{synthwave-84-osBjChRP.js → synthwave-84-exAgsgpf.js} +0 -0
- /package/dist/web/assets/{system-verilog-zQP2qPNU.js → system-verilog-DBWf00T6.js} +0 -0
- /package/dist/web/assets/{systemd-UGfjRSBM.js → systemd-nhu27Dw5.js} +0 -0
- /package/dist/web/assets/{table-FLU8ei8b.js → table-GAR4upb6.js} +0 -0
- /package/dist/web/assets/{talonscript-C1XrFPwo.js → talonscript-CNOEcGDc.js} +0 -0
- /package/dist/web/assets/{tasl-B5raVn43.js → tasl-CjYZenSH.js} +0 -0
- /package/dist/web/assets/{tcl-3-vbeMIc.js → tcl-BVA09RDz.js} +0 -0
- /package/dist/web/assets/{terraform-a8VXZDm9.js → terraform-C5EloH1q.js} +0 -0
- /package/dist/web/assets/{text-wrap-B05VGRa-.js → text-wrap-D71Jqz5U.js} +0 -0
- /package/dist/web/assets/{tokyo-night-4SRhf-Hz.js → tokyo-night-D764DdhO.js} +0 -0
- /package/dist/web/assets/{toml-B4N0i8wT.js → toml-CCDYblSB.js} +0 -0
- /package/dist/web/assets/{trash-2-CTXlTflF.js → trash-2-C08fhIg1.js} +0 -0
- /package/dist/web/assets/{triangle-alert-BRq0VAfd.js → triangle-alert-85BQgs3T.js} +0 -0
- /package/dist/web/assets/{tsv-DA5k9Lvw.js → tsv-BZ4sA05e.js} +0 -0
- /package/dist/web/assets/{tsx-D9SZ8owC.js → tsx-DPLBzAt5.js} +0 -0
- /package/dist/web/assets/{turtle-BTHTvyY_.js → turtle-CwGHCq40.js} +0 -0
- /package/dist/web/assets/{typescript-DYzV9p5L.js → typescript-CUH0vBAl.js} +0 -0
- /package/dist/web/assets/{typespec-BC15eh7F.js → typespec-Bq31Vq4u.js} +0 -0
- /package/dist/web/assets/{typst-BJUqzA6D.js → typst-MD9BR9W5.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-DFWViA4S.js → use-is-mobile-DUuki97q.js} +0 -0
- /package/dist/web/assets/{utils-C9OjCrou.js → utils-u2fbYPrY.js} +0 -0
- /package/dist/web/assets/{v-50Lps6oA.js → v-DZV7IxIT.js} +0 -0
- /package/dist/web/assets/{vala-8wiUvvrD.js → vala-urd1zi9S.js} +0 -0
- /package/dist/web/assets/{vb-BlgPLt6B.js → vb-DIZU3zbJ.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-BZOrwF_F.js → vendor-xterm-DCj0zgSC.js} +0 -0
- /package/dist/web/assets/{verilog-CD9pVW5p.js → verilog-Ndz_ciTA.js} +0 -0
- /package/dist/web/assets/{vesper-BrivW4PT.js → vesper-C86M7LJp.js} +0 -0
- /package/dist/web/assets/{vhdl-Bunxfa7N.js → vhdl-_klwDUjd.js} +0 -0
- /package/dist/web/assets/{viml-DndUb2qM.js → viml-DzRXWoQh.js} +0 -0
- /package/dist/web/assets/{vitesse-black-BurZSkxW.js → vitesse-black-TWZ20_3U.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-8UShspzC.js → vitesse-dark-Dl7R6fy9.js} +0 -0
- /package/dist/web/assets/{vitesse-light-DghCAZ90.js → vitesse-light-Cs0Dt2_n.js} +0 -0
- /package/dist/web/assets/{vyper-b-Clr-8u.js → vyper-qnCVj8ia.js} +0 -0
- /package/dist/web/assets/{wasm-CpcKStkw.js → wasm-Ckx9jBPe.js} +0 -0
- /package/dist/web/assets/{wasm-C5v2T06Y.js → wasm-Dy-SJ3W9.js} +0 -0
- /package/dist/web/assets/{wenyan-Dz2srLZR.js → wenyan-DTEy2Lx-.js} +0 -0
- /package/dist/web/assets/{wgsl-CeD1-dRb.js → wgsl-DC7n63Sy.js} +0 -0
- /package/dist/web/assets/{wikitext-CyeS-9FH.js → wikitext-1zFoZiW6.js} +0 -0
- /package/dist/web/assets/{wit-Kr-q-qBQ.js → wit-DtTfCRph.js} +0 -0
- /package/dist/web/assets/{wolfram-BKm8bmln.js → wolfram-B2Bgu1KL.js} +0 -0
- /package/dist/web/assets/{x-YDu4m2Iq.js → x-CeN0Qybc.js} +0 -0
- /package/dist/web/assets/{yaml-2XSxomjM.js → yaml-B-Jxk0IQ.js} +0 -0
- /package/dist/web/assets/{zenscript-CKIS34vf.js → zenscript-BWRfvNER.js} +0 -0
- /package/dist/web/assets/{zig-DdHGNllX.js → zig-CkwuvETm.js} +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Send a tab straight into picture-in-picture, without the user ever seeing a window.
|
|
3
|
+
*
|
|
4
|
+
* A PiP window can only adopt an element that is already in the page, and it needs somewhere
|
|
5
|
+
* to put it back. The floating window is that element and that home — so one still opens
|
|
6
|
+
* here, it is simply never shown: the frame keeps a pip-only window off screen, and closing
|
|
7
|
+
* PiP closes it, which re-docks the tab into the panel it came from.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { usePanelStore } from "@/stores/panel-store";
|
|
11
|
+
import { focusPipDocument } from "./pip/pip-focus-target";
|
|
12
|
+
import { attachPipHost } from "./pip/pip-host";
|
|
13
|
+
import { TITLEBAR_HEIGHT } from "./window-chrome-contract";
|
|
14
|
+
import {
|
|
15
|
+
clearPipOnlyWindow,
|
|
16
|
+
markPipOnlyWindow,
|
|
17
|
+
setWindowPip,
|
|
18
|
+
whenWindowSlot,
|
|
19
|
+
} from "./window-pip-registry";
|
|
20
|
+
import { useWindowStore } from "./window-store";
|
|
21
|
+
|
|
22
|
+
export type OpenTabInPipResult = "opened" | "window-cap" | "cancelled";
|
|
23
|
+
|
|
24
|
+
/** Drop the host window; its own teardown hands the tab back to the panel it came from. */
|
|
25
|
+
function discard(windowId: string): void {
|
|
26
|
+
clearPipOnlyWindow(windowId);
|
|
27
|
+
useWindowStore.getState().close(windowId);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Detach a tab into a hidden window and adopt it into a PiP window.
|
|
32
|
+
*
|
|
33
|
+
* Rejects when the browser refuses the request (no support, or the click's activation was
|
|
34
|
+
* already spent); the caller reports that. Call it from a click handler with nothing awaited
|
|
35
|
+
* before it — the one await inside is a React commit, which leaves the activation valid.
|
|
36
|
+
*/
|
|
37
|
+
export async function openTabInPip(tabId: string, panelId: string): Promise<OpenTabInPipResult> {
|
|
38
|
+
const windowId = usePanelStore.getState().popOutTab(tabId, panelId);
|
|
39
|
+
if (!windowId) return "window-cap";
|
|
40
|
+
markPipOnlyWindow(windowId);
|
|
41
|
+
|
|
42
|
+
// The window exists in the store, but its body is created by the frame's layout effect —
|
|
43
|
+
// one commit away.
|
|
44
|
+
const slot = await whenWindowSlot(windowId);
|
|
45
|
+
if (!slot) {
|
|
46
|
+
discard(windowId);
|
|
47
|
+
return "cancelled";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const rect = useWindowStore.getState().windows[windowId]?.rect;
|
|
51
|
+
let handle;
|
|
52
|
+
try {
|
|
53
|
+
handle = await attachPipHost(slot, {
|
|
54
|
+
// A zero falls through to the host's minimum size rather than a magic default.
|
|
55
|
+
width: rect?.w ?? 0,
|
|
56
|
+
height: rect ? rect.h - TITLEBAR_HEIGHT : 0,
|
|
57
|
+
onDetach: () => {
|
|
58
|
+
setWindowPip(windowId, null);
|
|
59
|
+
// Closing PiP means "done with this tab out here", not "give me a window instead":
|
|
60
|
+
// the tab goes back to its strip.
|
|
61
|
+
discard(windowId);
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
} catch (err) {
|
|
65
|
+
discard(windowId);
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Null means the window went away while the request was in flight; the host already
|
|
70
|
+
// restored what it had and called onDetach.
|
|
71
|
+
if (!handle) return "cancelled";
|
|
72
|
+
|
|
73
|
+
setWindowPip(windowId, handle);
|
|
74
|
+
// A DOM move carries no focus with it: without this the tab is visible in PiP but swallows
|
|
75
|
+
// nothing until the user clicks it.
|
|
76
|
+
focusPipDocument(handle.pipWindow.document);
|
|
77
|
+
return "opened";
|
|
78
|
+
}
|
|
@@ -22,6 +22,7 @@ export const WINDOW_CONTENT: Record<WindowKind, LazyExoticComponent<ComponentTyp
|
|
|
22
22
|
"team-member": lazy(() => import("@/components/chat/team-member-window-content")),
|
|
23
23
|
"system-monitor": lazy(() => import("@/components/system/system-monitor-window-content")),
|
|
24
24
|
"tab-host": lazy(() => import("./tab-host-window-content")),
|
|
25
|
+
"remote-desktop": lazy(() => import("@/components/remote-desktop/remote-desktop-window-content")),
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
/** Titlebar text for a window. Falls back to the kind's generic name. */
|
|
@@ -33,6 +34,7 @@ export function windowTitle(kind: WindowKind, payload?: Record<string, unknown>)
|
|
|
33
34
|
return typeof member === "string" && member ? `Session — ${member}` : "Team member";
|
|
34
35
|
}
|
|
35
36
|
if (kind === "system-monitor") return "System Monitor";
|
|
37
|
+
if (kind === "remote-desktop") return "Remote Desktop";
|
|
36
38
|
// A detached tab carries its title in the payload; the generic name only shows for a
|
|
37
39
|
// window whose tab has not been resolved yet (restore before the layout is loaded).
|
|
38
40
|
if (kind === "tab-host") return "Tab";
|
|
@@ -24,6 +24,52 @@ const listeners = new Set<() => void>();
|
|
|
24
24
|
export function publishWindowSlot(windowId: string, el: HTMLElement | null): void {
|
|
25
25
|
if (el) slots.set(windowId, el);
|
|
26
26
|
else slots.delete(windowId);
|
|
27
|
+
for (const notify of listeners) notify();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Resolve once a window has published its body, or `null` if it never does.
|
|
32
|
+
*
|
|
33
|
+
* A window opened to host a picture-in-picture request exists in the store before React has
|
|
34
|
+
* mounted its frame, so the element the PiP host needs does not exist yet in the click
|
|
35
|
+
* handler that created it. Waiting is safe: transient activation survives a commit, it is
|
|
36
|
+
* consuming it twice that the browser refuses.
|
|
37
|
+
*/
|
|
38
|
+
export function whenWindowSlot(windowId: string, timeoutMs = 2000): Promise<HTMLElement | null> {
|
|
39
|
+
const existing = windowSlot(windowId);
|
|
40
|
+
if (existing) return Promise.resolve(existing);
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
const settle = (el: HTMLElement | null) => {
|
|
43
|
+
listeners.delete(check);
|
|
44
|
+
clearTimeout(timer);
|
|
45
|
+
resolve(el);
|
|
46
|
+
};
|
|
47
|
+
const check = () => {
|
|
48
|
+
const el = windowSlot(windowId);
|
|
49
|
+
if (el) settle(el);
|
|
50
|
+
};
|
|
51
|
+
const timer = setTimeout(() => settle(null), timeoutMs);
|
|
52
|
+
listeners.add(check);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Windows that exist only to carry a tab into picture-in-picture: the frame keeps them off
|
|
58
|
+
* screen while PiP is up, and closing PiP closes the window, so the tab goes straight back
|
|
59
|
+
* to its tab strip instead of stranding an empty window the user never asked for.
|
|
60
|
+
*/
|
|
61
|
+
const pipOnly = new Set<string>();
|
|
62
|
+
|
|
63
|
+
export function markPipOnlyWindow(windowId: string): void {
|
|
64
|
+
pipOnly.add(windowId);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function isPipOnlyWindow(windowId: string): boolean {
|
|
68
|
+
return pipOnly.has(windowId);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function clearPipOnlyWindow(windowId: string): void {
|
|
72
|
+
pipOnly.delete(windowId);
|
|
27
73
|
}
|
|
28
74
|
|
|
29
75
|
/** The body element of a mounted window, or null. */
|
|
@@ -7,7 +7,7 @@ import type { Rect } from "./window-geometry";
|
|
|
7
7
|
* Single source of truth: the persistence layer filters this list instead of repeating it,
|
|
8
8
|
* so a new kind can never be silently dropped on reload.
|
|
9
9
|
*/
|
|
10
|
-
export const WINDOW_KINDS = ["explorer", "team-member", "system-monitor", "tab-host"] as const;
|
|
10
|
+
export const WINDOW_KINDS = ["explorer", "team-member", "system-monitor", "tab-host", "remote-desktop"] as const;
|
|
11
11
|
|
|
12
12
|
export type WindowKind = (typeof WINDOW_KINDS)[number];
|
|
13
13
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useCallback, useEffect, useMemo } from "react";
|
|
2
|
-
import { X, Bug as BugIcon, Cloud, FolderTree } from "lucide-react";
|
|
2
|
+
import { X, Bug as BugIcon, Cloud, FolderTree, MonitorSmartphone } from "lucide-react";
|
|
3
3
|
import { useShallow } from "zustand/react/shallow";
|
|
4
4
|
import { useProjectStore } from "@/stores/project-store";
|
|
5
5
|
import { useSettingsStore, type SidebarActiveTab } from "@/stores/settings-store";
|
|
@@ -23,7 +23,10 @@ import { CloudSharePopover } from "@/components/layout/cloud-share-popover";
|
|
|
23
23
|
import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
|
|
24
24
|
import { isMobileDevice } from "@/hooks/use-is-mobile";
|
|
25
25
|
import { openExplorer } from "@/components/os-explorer/open-explorer";
|
|
26
|
+
import { useOpenRemoteDesktop } from "@/components/remote-desktop/open-remote-desktop";
|
|
27
|
+
import { useRemoteDesktopAvailable } from "@/components/remote-desktop/use-remote-desktop-available";
|
|
26
28
|
import { FeatureBadge } from "@/components/ui/feature-badge";
|
|
29
|
+
import type { FeatureBadgeId } from "@/lib/feature-badges";
|
|
27
30
|
import { cn } from "@/lib/utils";
|
|
28
31
|
|
|
29
32
|
// Tab ids the mobile drawer can render content for. `search` is desktop-only for now;
|
|
@@ -33,6 +36,24 @@ const MOBILE_SUPPORTED = new Set<string>([
|
|
|
33
36
|
]);
|
|
34
37
|
const isMobileSupported = (id: SidebarActiveTab) => MOBILE_SUPPORTED.has(id) || id.startsWith("ext:");
|
|
35
38
|
|
|
39
|
+
/** One utility tile in the drawer footer grid — icon over a short single-line label, with an
|
|
40
|
+
* optional corner feature badge. Uniform size so the grid wraps cleanly as tiles are added,
|
|
41
|
+
* instead of a single cramped row where long labels ("Cloud & Share") wrapped and overflowed. */
|
|
42
|
+
function FooterTile({ icon: Icon, label, badge, onClick }: {
|
|
43
|
+
icon: React.ElementType; label: string; badge?: FeatureBadgeId; onClick: () => void;
|
|
44
|
+
}) {
|
|
45
|
+
return (
|
|
46
|
+
<button
|
|
47
|
+
onClick={onClick}
|
|
48
|
+
className="group relative flex flex-col items-center justify-center gap-1 rounded-lg py-2.5 text-text-subtle hover:bg-surface-elevated hover:text-text-secondary transition-colors"
|
|
49
|
+
>
|
|
50
|
+
<Icon className="size-4" />
|
|
51
|
+
<span className="text-[10px] leading-none">{label}</span>
|
|
52
|
+
<FeatureBadge id={badge} variant="corner" />
|
|
53
|
+
</button>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
36
57
|
interface MobileDrawerProps {
|
|
37
58
|
isOpen: boolean;
|
|
38
59
|
onClose: () => void;
|
|
@@ -47,6 +68,8 @@ export function MobileDrawer({ isOpen, onClose, initialTab }: MobileDrawerProps)
|
|
|
47
68
|
const sidebarTabOrder = useSettingsStore((s) => s.sidebarTabOrder);
|
|
48
69
|
const setSidebarTabOrder = useSettingsStore((s) => s.setSidebarTabOrder);
|
|
49
70
|
const contributions = useExtensionStore((s) => s.contributions);
|
|
71
|
+
const { available: remoteDesktopAvailable } = useRemoteDesktopAvailable();
|
|
72
|
+
const openRemoteDesktop = useOpenRemoteDesktop();
|
|
50
73
|
const [activeTab, setActiveTab] = useState<SidebarActiveTab>(initialTab ?? "explorer");
|
|
51
74
|
const [cloudOpen, setCloudOpen] = useState(false);
|
|
52
75
|
|
|
@@ -138,33 +161,21 @@ export function MobileDrawer({ isOpen, onClose, initialTab }: MobileDrawerProps)
|
|
|
138
161
|
onReorder={setSidebarTabOrder}
|
|
139
162
|
/>
|
|
140
163
|
|
|
141
|
-
{/*
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
<div className="
|
|
164
|
+
{/* Footer: version/upgrade on its own line, then a uniform wrapping grid of utility
|
|
165
|
+
tiles (opens explorer/remote/cloud, report bug) — scales cleanly as tiles are added. */}
|
|
166
|
+
<div className="border-t border-border px-3 py-2">
|
|
167
|
+
<div className="grid grid-cols-4 gap-1">
|
|
145
168
|
{/* Not a sidebar tab — the explorer opens as its own full-screen sheet. */}
|
|
146
|
-
<
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
className="flex items-center gap-1 text-[10px] text-text-subtle hover:text-text-secondary transition-colors"
|
|
157
|
-
>
|
|
158
|
-
<Cloud className="size-3" />
|
|
159
|
-
<span>Cloud & Share</span>
|
|
160
|
-
</button>
|
|
161
|
-
<button
|
|
162
|
-
onClick={handleReportBug}
|
|
163
|
-
className="flex items-center gap-1 text-[10px] text-text-subtle hover:text-text-secondary transition-colors"
|
|
164
|
-
>
|
|
165
|
-
<BugIcon className="size-3" />
|
|
166
|
-
<span>Report Bug</span>
|
|
167
|
-
</button>
|
|
169
|
+
<FooterTile icon={FolderTree} label="Files" badge="os-explorer" onClick={() => { onClose(); void openExplorer(); }} />
|
|
170
|
+
{remoteDesktopAvailable && (
|
|
171
|
+
<FooterTile icon={MonitorSmartphone} label="Remote" badge="remote-desktop" onClick={() => { onClose(); openRemoteDesktop(); }} />
|
|
172
|
+
)}
|
|
173
|
+
<FooterTile icon={Cloud} label="Cloud" onClick={() => setCloudOpen(true)} />
|
|
174
|
+
<FooterTile icon={BugIcon} label="Bug" onClick={handleReportBug} />
|
|
175
|
+
</div>
|
|
176
|
+
{/* Version / upgrade pinned at the very bottom, under a divider. */}
|
|
177
|
+
<div className="mt-2 pt-2 border-t border-border px-1 text-[11px]">
|
|
178
|
+
<UpgradeButton align="left" />
|
|
168
179
|
</div>
|
|
169
180
|
</div>
|
|
170
181
|
</div>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { useState, useRef, useEffect, useMemo, memo } from "react";
|
|
2
2
|
import { createPortal } from "react-dom";
|
|
3
|
-
import { Settings, Bug, Cloud, FolderTree } from "lucide-react";
|
|
3
|
+
import { Settings, Bug, Cloud, FolderTree, MonitorSmartphone } from "lucide-react";
|
|
4
4
|
import { openExplorer } from "@/components/os-explorer/open-explorer";
|
|
5
|
+
import { useOpenRemoteDesktop } from "@/components/remote-desktop/open-remote-desktop";
|
|
6
|
+
import { useRemoteDesktopAvailable } from "@/components/remote-desktop/use-remote-desktop-available";
|
|
5
7
|
import { FeatureBadge } from "@/components/ui/feature-badge";
|
|
6
8
|
import type { FeatureBadgeId } from "@/lib/feature-badges";
|
|
7
9
|
import { useSettingsStore, type SidebarActiveTab } from "@/stores/settings-store";
|
|
@@ -147,6 +149,9 @@ export const NavSectionRail = memo(function NavSectionRail({ className }: { clas
|
|
|
147
149
|
return () => window.removeEventListener("open-cloud-share", open);
|
|
148
150
|
}, []);
|
|
149
151
|
|
|
152
|
+
const openRemoteDesktop = useOpenRemoteDesktop();
|
|
153
|
+
const { available: remoteDesktopAvailable } = useRemoteDesktopAvailable();
|
|
154
|
+
|
|
150
155
|
const handleReportBug = () => openBugReportPopup(version);
|
|
151
156
|
|
|
152
157
|
// Rail tab click: collapsed → open on any tab; open → clicking the active tab closes it.
|
|
@@ -209,8 +214,11 @@ export const NavSectionRail = memo(function NavSectionRail({ className }: { clas
|
|
|
209
214
|
</>,
|
|
210
215
|
document.body,
|
|
211
216
|
)}
|
|
212
|
-
{/* Not
|
|
217
|
+
{/* Not sidebar tabs — these open their own floating windows. */}
|
|
213
218
|
<FooterUtil icon={FolderTree} label="File Explorer" featureBadge="os-explorer" onClick={() => void openExplorer()} />
|
|
219
|
+
{remoteDesktopAvailable && (
|
|
220
|
+
<FooterUtil icon={MonitorSmartphone} label="Remote Desktop" featureBadge="remote-desktop" onClick={openRemoteDesktop} />
|
|
221
|
+
)}
|
|
214
222
|
<FooterUtil icon={Bug} label="Report Bug" onClick={handleReportBug} />
|
|
215
223
|
<FooterUtil icon={Settings} label="Settings" active={sidebarActiveTab === "settings"} onClick={() => handleTabClick("settings")} />
|
|
216
224
|
</div>
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* "Open in window" — detaches a tab
|
|
2
|
+
* "Open in window" / "Open in picture-in-picture" — detaches a tab, keeping it live.
|
|
3
|
+
*
|
|
4
|
+
* The PiP route skips the window entirely from the user's point of view: a host window is
|
|
5
|
+
* opened and hidden, and closing PiP closes it, so the tab lands back in this strip.
|
|
3
6
|
*
|
|
4
7
|
* Desktop only: the window layer renders nothing below the md breakpoint, so on a phone
|
|
5
8
|
* the item would move a tab somewhere the user cannot see (a scaled-down window is never
|
|
6
9
|
* the answer — see the mobile-first UI rules).
|
|
7
10
|
*/
|
|
8
|
-
import { ExternalLink } from "lucide-react";
|
|
11
|
+
import { ExternalLink, PictureInPicture2 } from "lucide-react";
|
|
9
12
|
import { toast } from "sonner";
|
|
13
|
+
import { openTabInPip } from "@/components/floating-window/open-tab-in-pip";
|
|
14
|
+
import { isDocumentPipSupported } from "@/components/floating-window/pip/pip-support";
|
|
10
15
|
import { ContextMenuItem, ContextMenuSeparator } from "@/components/ui/context-menu";
|
|
11
16
|
import { useIsMobile } from "@/hooks/use-is-mobile";
|
|
12
17
|
import { usePanelStore } from "@/stores/panel-store";
|
|
@@ -36,6 +41,24 @@ export function TabPopOutMenuItem({ tab, panelId }: TabPopOutMenuItemProps) {
|
|
|
36
41
|
<ExternalLink className="size-3.5 mr-2" />
|
|
37
42
|
Open in window
|
|
38
43
|
</ContextMenuItem>
|
|
44
|
+
{isDocumentPipSupported() && (
|
|
45
|
+
<ContextMenuItem
|
|
46
|
+
onClick={() => {
|
|
47
|
+
// Nothing awaited before this call: it spends the click's activation on the PiP
|
|
48
|
+
// request, and the browser grants that only to a live gesture.
|
|
49
|
+
void openTabInPip(tab.id, panelId)
|
|
50
|
+
.then((result) => {
|
|
51
|
+
if (result === "window-cap") toast.error("Too many windows open — close one first");
|
|
52
|
+
})
|
|
53
|
+
.catch(() => {
|
|
54
|
+
toast.error("Could not open the picture-in-picture window");
|
|
55
|
+
});
|
|
56
|
+
}}
|
|
57
|
+
>
|
|
58
|
+
<PictureInPicture2 className="size-3.5 mr-2" />
|
|
59
|
+
Open in picture-in-picture
|
|
60
|
+
</ContextMenuItem>
|
|
61
|
+
)}
|
|
39
62
|
<ContextMenuSeparator />
|
|
40
63
|
</>
|
|
41
64
|
);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opens the Remote Desktop viewer: a floating window on desktop, the full-screen mobile sheet
|
|
3
|
+
* below `md` (`WindowLayer` renders nothing there — same split `open-explorer.ts` makes for the
|
|
4
|
+
* file explorer). There is one host to control, so a second call on desktop focuses the
|
|
5
|
+
* existing window instead of opening another; on mobile the sheet is a singleton already.
|
|
6
|
+
*/
|
|
7
|
+
import { useCallback } from "react";
|
|
8
|
+
import { useWindowStore } from "@/components/floating-window/window-store";
|
|
9
|
+
import { isMobileDevice } from "@/hooks/use-is-mobile";
|
|
10
|
+
import { useRemoteDesktopMobileOpenState } from "./use-remote-desktop-mobile-open-state";
|
|
11
|
+
|
|
12
|
+
export function useOpenRemoteDesktop(): () => void {
|
|
13
|
+
const openWindow = useWindowStore((s) => s.open);
|
|
14
|
+
const focusWindow = useWindowStore((s) => s.focus);
|
|
15
|
+
const openMobileSheet = useRemoteDesktopMobileOpenState((s) => s.open);
|
|
16
|
+
|
|
17
|
+
return useCallback(() => {
|
|
18
|
+
if (isMobileDevice()) {
|
|
19
|
+
openMobileSheet();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const existing = Object.values(useWindowStore.getState().windows).find((w) => w.kind === "remote-desktop");
|
|
23
|
+
if (existing) focusWindow(existing.id);
|
|
24
|
+
else openWindow("remote-desktop");
|
|
25
|
+
}, [openWindow, focusWindow, openMobileSheet]);
|
|
26
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client → host coordinate mapping. Only the canvas's CSS-pixel bounding rect matters —
|
|
3
|
+
* `devicePixelRatio` describes the *viewer's* screen (irrelevant to host pixels, and would
|
|
4
|
+
* double-scale/misplace the cursor if folded in), so it is deliberately never read here.
|
|
5
|
+
*/
|
|
6
|
+
export interface Fraction {
|
|
7
|
+
xFrac: number;
|
|
8
|
+
yFrac: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Plain bounding-box shape every function here accepts — deliberately not `DOMRect` so pure
|
|
12
|
+
* computed rects (e.g. `letterboxedContentRect`'s output) satisfy it without faking DOM-only
|
|
13
|
+
* members (`right`, `bottom`, `toJSON`, …) that nothing here ever reads. */
|
|
14
|
+
export interface Rect {
|
|
15
|
+
left: number;
|
|
16
|
+
top: number;
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function clamp01(n: number): number {
|
|
22
|
+
return Math.min(Math.max(n, 0), 1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** `rect` is the canvas element's `getBoundingClientRect()`. Fractions are clamped to 0..1 so
|
|
26
|
+
* a pointer that slips just outside the element (fast drag) still maps to an edge, not a
|
|
27
|
+
* wildly out-of-range host coordinate. */
|
|
28
|
+
export function fractionFromPoint(clientX: number, clientY: number, rect: Rect): Fraction {
|
|
29
|
+
const xFrac = rect.width > 0 ? (clientX - rect.left) / rect.width : 0;
|
|
30
|
+
const yFrac = rect.height > 0 ? (clientY - rect.top) / rect.height : 0;
|
|
31
|
+
return { xFrac: clamp01(xFrac), yFrac: clamp01(yFrac) };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** A CSS `transform: translate(panX, panY) scale(scale)` applied around the transformed
|
|
35
|
+
* element's own center (the mobile viewer's default `transform-origin`). */
|
|
36
|
+
export interface ZoomPanTransform {
|
|
37
|
+
scale: number;
|
|
38
|
+
panX: number;
|
|
39
|
+
panY: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Reverse-maps a screen point through an active pinch-zoom/pan transform back to a 0..1
|
|
44
|
+
* fraction of the capture — used by the mobile touch viewer, which zooms/pans the canvas with
|
|
45
|
+
* a CSS transform instead of re-rendering at a different resolution.
|
|
46
|
+
*
|
|
47
|
+
* `rect` MUST be the bounding rect of the never-transformed container the canvas fills at
|
|
48
|
+
* `scale=1, pan=0` (not the live, possibly-transformed canvas rect) — that container is the
|
|
49
|
+
* stable reference frame this function projects screen points back into. Deliberately pure
|
|
50
|
+
* arithmetic rather than reading the live (transformed) element's `getBoundingClientRect()`:
|
|
51
|
+
* jsdom does not compute CSS transforms into that rect at all, so this stays unit-testable,
|
|
52
|
+
* and it avoids relying on `transform-origin` math the browser applies opaquely.
|
|
53
|
+
*/
|
|
54
|
+
export function fractionFromZoomedPoint(
|
|
55
|
+
clientX: number,
|
|
56
|
+
clientY: number,
|
|
57
|
+
rect: Rect,
|
|
58
|
+
transform: ZoomPanTransform,
|
|
59
|
+
): Fraction {
|
|
60
|
+
const scale = transform.scale || 1;
|
|
61
|
+
const cx = rect.left + rect.width / 2;
|
|
62
|
+
const cy = rect.top + rect.height / 2;
|
|
63
|
+
const baseX = cx + (clientX - cx - transform.panX) / scale;
|
|
64
|
+
const baseY = cy + (clientY - cy - transform.panY) / scale;
|
|
65
|
+
return fractionFromPoint(baseX, baseY, rect);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The on-screen sub-rectangle a canvas actually paints its content into under `object-fit:
|
|
70
|
+
* contain` (or the equivalent CSS2.1 replaced-element max-width/max-height algorithm) — the
|
|
71
|
+
* canvas ELEMENT's own box does not shrink to the letterboxed video; only the pixels drawn
|
|
72
|
+
* inside it do. `box` is that element's box at rest (`scale=1, pan=0` — never the live,
|
|
73
|
+
* zoomed/panned rect: see `fractionFromZoomedPoint`'s doc comment for why), `contentWidth`/
|
|
74
|
+
* `contentHeight` are the canvas's drawing-buffer dimensions (its `.width`/`.height`
|
|
75
|
+
* attributes, i.e. the real capture resolution, NOT its CSS size).
|
|
76
|
+
*
|
|
77
|
+
* `object-fit: contain` centers the letterboxed content within `box` by default
|
|
78
|
+
* (`object-position: 50% 50%`), so this rect's own center always coincides with `box`'s
|
|
79
|
+
* center — that is what keeps `fractionFromZoomedPoint`'s transform-origin math (which derives
|
|
80
|
+
* `cx,cy` from whatever rect it's given) correct when this rect is passed to it instead of the
|
|
81
|
+
* raw container box.
|
|
82
|
+
*
|
|
83
|
+
* Falls back to `box` unchanged if the content has no size yet (e.g. before the first decoded
|
|
84
|
+
* frame sets `canvas.width`/`canvas.height`).
|
|
85
|
+
*/
|
|
86
|
+
export function letterboxedContentRect(box: Rect, contentWidth: number, contentHeight: number): Rect {
|
|
87
|
+
if (contentWidth <= 0 || contentHeight <= 0 || box.width <= 0 || box.height <= 0) return box;
|
|
88
|
+
const boxAspect = box.width / box.height;
|
|
89
|
+
const contentAspect = contentWidth / contentHeight;
|
|
90
|
+
if (contentAspect > boxAspect) {
|
|
91
|
+
// Content is relatively WIDER than the box -> width-constrained, letterboxed top/bottom.
|
|
92
|
+
const height = box.width / contentAspect;
|
|
93
|
+
return { left: box.left, top: box.top + (box.height - height) / 2, width: box.width, height };
|
|
94
|
+
}
|
|
95
|
+
// Content is relatively TALLER/narrower than the box -> height-constrained, letterboxed sides.
|
|
96
|
+
const width = box.height * contentAspect;
|
|
97
|
+
return { left: box.left + (box.width - width) / 2, top: box.top, width, height: box.height };
|
|
98
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strictly-increasing microsecond timestamps for `EncodedVideoChunk`.
|
|
3
|
+
*
|
|
4
|
+
* The decoder previously used `performance.now() * 1000` per chunk. Some decoders — especially
|
|
5
|
+
* mobile hardware H.264 decoders — reject a chunk whose timestamp does not strictly increase
|
|
6
|
+
* from the previous one; two chunks landing in the same millisecond (easy at 30fps under normal
|
|
7
|
+
* network/encode jitter) get equal timestamps and can trip that check.
|
|
8
|
+
*
|
|
9
|
+
* This is decode-only playback (no A/V sync, nothing ever reads the timestamp back to schedule
|
|
10
|
+
* presentation), so the value only has to satisfy "strictly greater than the last one" — a
|
|
11
|
+
* frame-index-based synthetic clock does that unconditionally, independent of wall-clock
|
|
12
|
+
* resolution or jitter.
|
|
13
|
+
*/
|
|
14
|
+
const DEFAULT_FPS = 30;
|
|
15
|
+
|
|
16
|
+
/** `frameIndex` is a 0-based, ever-incrementing counter of chunks decoded by ONE decoder
|
|
17
|
+
* instance — reset it to 0 whenever a new `VideoDecoder` is created (a fresh instance has no
|
|
18
|
+
* timestamp history to stay monotonic against). */
|
|
19
|
+
export function frameTimestampMicros(frameIndex: number, fps: number = DEFAULT_FPS): number {
|
|
20
|
+
return Math.round((frameIndex * 1_000_000) / fps);
|
|
21
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure classifiers the mobile touch viewer's gesture engine uses to tell "tap" apart from
|
|
3
|
+
* "drag", and "pinch-zoom" apart from "two-finger scroll". Kept dependency-free (no DOM,
|
|
4
|
+
* no React) so they can be unit-tested without a browser.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** One sampled point in a gesture: client-space coordinates + a timestamp (ms, any monotonic
|
|
8
|
+
* clock — `performance.now()` in the real hook). */
|
|
9
|
+
export interface PointerSample {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
t: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** A tap is a touch that ends close to where it started, quickly — anything else (moved
|
|
16
|
+
* further, or held longer) is a drag/long-press instead. Both thresholds must pass; a fast
|
|
17
|
+
* but far swipe is a drag, and a slow-but-still finger is a long-press, not a tap. */
|
|
18
|
+
export function isTapGesture(
|
|
19
|
+
start: PointerSample,
|
|
20
|
+
end: PointerSample,
|
|
21
|
+
moveThresholdPx = 10,
|
|
22
|
+
maxDurationMs = 300,
|
|
23
|
+
): boolean {
|
|
24
|
+
const dist = Math.hypot(end.x - start.x, end.y - start.y);
|
|
25
|
+
const duration = end.t - start.t;
|
|
26
|
+
return dist <= moveThresholdPx && duration <= maxDurationMs;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type TwoFingerGesture = "pinch" | "scroll";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Two-finger gestures start ambiguous — pinch-zoom and two-finger-scroll both begin as "two
|
|
33
|
+
* fingers moved a little". They are told apart by which signal crosses its threshold first:
|
|
34
|
+
* the distance *between* the fingers changing (pinch) vs. their midpoint translating while
|
|
35
|
+
* staying roughly the same distance apart (scroll). Once a gesture is classified, the caller
|
|
36
|
+
* should keep calling this with the *same* `startDistance` for the rest of the gesture and
|
|
37
|
+
* lock in the first non-null-equivalent result — see `use-remote-desktop-touch.ts`.
|
|
38
|
+
*/
|
|
39
|
+
export function classifyTwoFingerGesture(
|
|
40
|
+
startDistance: number,
|
|
41
|
+
currentDistance: number,
|
|
42
|
+
distanceThresholdPx = 15,
|
|
43
|
+
): TwoFingerGesture {
|
|
44
|
+
return Math.abs(currentDistance - startDistance) > distanceThresholdPx ? "pinch" : "scroll";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Euclidean distance between two touch points — shared helper so the hook and its tests
|
|
48
|
+
* compute "finger spread" identically. */
|
|
49
|
+
export function touchDistance(a: { x: number; y: number }, b: { x: number; y: number }): number {
|
|
50
|
+
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Midpoint between two touch points. */
|
|
54
|
+
export function touchMidpoint(a: { x: number; y: number }, b: { x: number; y: number }): { x: number; y: number } {
|
|
55
|
+
return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
|
|
56
|
+
}
|