@hienlh/ppm 0.18.10 → 0.18.12
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/CHANGELOG.md +18 -0
- package/README.md +81 -23
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/adaptive-context-menu-DGCKKeTy.js +1 -0
- package/dist/web/assets/ai-resource-editor-BOHHTTe7.js +1 -0
- package/dist/web/assets/ai-settings-section-BigC_nZR.js +1 -0
- package/dist/web/assets/{angular-html-Ctz0zN01.js → angular-html-BYPaydvh.js} +1 -1
- package/dist/web/assets/{angular-ts-QXHpgB1C.js → angular-ts-Bb4AMKlk.js} +1 -1
- package/dist/web/assets/api-client-DTZEgjBQ.js +1 -0
- package/dist/web/assets/{api-settings-kQHV6pYZ.js → api-settings-Bd3M4YpI.js} +1 -1
- package/dist/web/assets/api-settings-kd1j4iR8.js +1 -0
- package/dist/web/assets/{api-themes-CrK0tkW_.js → api-themes-Cpx419SL.js} +1 -1
- package/dist/web/assets/{apl-b9KVk-O4.js → apl-DB2VjFCS.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-8dCMT9r7.js +1 -0
- package/dist/web/assets/{astro-BlFEeGYr.js → astro-BeoJdVpk.js} +1 -1
- package/dist/web/assets/{audio-preview-CZLmhf__.js → audio-preview-BgFuTn-0.js} +1 -1
- package/dist/web/assets/{blade-CGkj2MUI.js → blade-Cf2q1sPf.js} +1 -1
- package/dist/web/assets/{bsl-CVsbb6ap.js → bsl-W1kOaNpu.js} +1 -1
- package/dist/web/assets/{button-BA_fJOtX.js → button-5zTrkEoN.js} +1 -1
- package/dist/web/assets/{cairo-BbIHl2iE.js → cairo-BoAZFcje.js} +1 -1
- package/dist/web/assets/chat-tab-E3bf_V8X.js +15 -0
- package/dist/web/assets/chevron-down-Dp0rpHb8.js +1 -0
- package/dist/web/assets/clipboard-7fw0Shic.js +1 -0
- package/dist/web/assets/{cobol-BWSGjmWb.js → cobol-B0Nm7RXj.js} +1 -1
- package/dist/web/assets/code-editor-BUlM2gXk.js +10 -0
- package/dist/web/assets/{coffee-CWGNOxds.js → coffee-BakMn3on.js} +1 -1
- package/dist/web/assets/{conflict-editor-fRTU3f1o.js → conflict-editor-BUs5k9q_.js} +4 -4
- package/dist/web/assets/context-menu-Bq92km4s.js +1 -0
- package/dist/web/assets/{cpp-DHGV24J2.js → cpp-BRAJQHK2.js} +1 -1
- package/dist/web/assets/{crystal-Vlwf2UMP.js → crystal-kqqO3zkK.js} +1 -1
- package/dist/web/assets/{csv-preview-D1d0cxOJ.js → csv-preview-ByoDgLAZ.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-D9il5DZS.js → data-grid-overlay-editor-Brkf9z41.js} +1 -1
- package/dist/web/assets/database-viewer-Btc3h8Yu.js +1 -0
- package/dist/web/assets/dialog-DwtGlowE.js +1 -0
- package/dist/web/assets/diff-viewer-CZaDnR4w.js +4 -0
- package/dist/web/assets/docx-preview-DAD_vg59.js +12 -0
- package/dist/web/assets/{edge-Bhqk64zS.js → edge-Cq1ZKZuE.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-gq6ALf2B.js → edit-diff-preview-B_VE7ppQ.js} +1 -1
- package/dist/web/assets/{elixir-D466WCFm.js → elixir-BM_JoJRk.js} +1 -1
- package/dist/web/assets/{elm-Bfs2qNPR.js → elm-Dw7oO08Y.js} +1 -1
- package/dist/web/assets/{erb-WI7jUaB6.js → erb-CfKOGAfk.js} +1 -1
- package/dist/web/assets/{erlang-BCBe8nCc.js → erlang-DlDmGVeE.js} +1 -1
- package/dist/web/assets/{esm-CZs9WVDO.js → esm-DGAP0GFh.js} +1 -1
- package/dist/web/assets/explorer-body-9aBmyVpZ.js +2 -0
- package/dist/web/assets/explorer-window-content-DRtqoSPA.js +1 -0
- package/dist/web/assets/extension-store-Cpfh2vMm.js +1 -0
- package/dist/web/assets/{extension-webview-BH_mWYMe.js → extension-webview-B2OnjuCu.js} +2 -2
- package/dist/web/assets/external-link-B8BynhvY.js +1 -0
- package/dist/web/assets/file-store-aOERIEo-.js +1 -0
- package/dist/web/assets/folder-symlink-B8XrtvQK.js +1 -0
- package/dist/web/assets/{fortran-fixed-form-CXLIv8Ox.js → fortran-fixed-form-XnAhQWxS.js} +1 -1
- package/dist/web/assets/{fsharp-CZsYmiw9.js → fsharp-CdNvy0PG.js} +1 -1
- package/dist/web/assets/{gdresource-BGRvoWfC.js → gdresource-DxuG5i8i.js} +1 -1
- package/dist/web/assets/{git-commit-DH6mY3Km.js → git-commit-3lMonsur.js} +1 -1
- package/dist/web/assets/git-log-panel-Co0PBPHC.js +1 -0
- package/dist/web/assets/{git-rebase-C5Gql6Ma.js → git-rebase-N8Z9kIMf.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-2e_8dfbs.js +1 -0
- package/dist/web/assets/{glide-data-grid-n4ox_uev.js → glide-data-grid-C4_zIneN.js} +8 -8
- package/dist/web/assets/{glimmer-js-1-6JMJlj.js → glimmer-js-Dp9OXiib.js} +1 -1
- package/dist/web/assets/{glimmer-ts-C_Njj0nK.js → glimmer-ts-CDVKBcDj.js} +1 -1
- package/dist/web/assets/{glsl-DbkxE1TN.js → glsl-DPJxI4us.js} +1 -1
- package/dist/web/assets/{graphql-BK75fiXl.js → graphql-BrFhaQQl.js} +1 -1
- package/dist/web/assets/group-chat-tab-rOd8J8GC.js +1 -0
- package/dist/web/assets/{hack-DG151vit.js → hack-BzXbDMlA.js} +1 -1
- package/dist/web/assets/{haml-DKeIPQWM.js → haml-CPpkX0s5.js} +1 -1
- package/dist/web/assets/{handlebars-398uCI13.js → handlebars-BqrApy52.js} +1 -1
- package/dist/web/assets/{html-NLWdst5q.js → html-DmjUl-OA.js} +1 -1
- package/dist/web/assets/{html-derivative-CJf_Le2z.js → html-derivative-Cnd6XFR5.js} +1 -1
- package/dist/web/assets/{http-G1K2FozA.js → http-DMLWYun2.js} +1 -1
- package/dist/web/assets/{hurl-WDC6sSBz.js → hurl-CKkCVxbj.js} +1 -1
- package/dist/web/assets/{hxml-Dc3jBXuf.js → hxml-CAx19TtQ.js} +1 -1
- package/dist/web/assets/image-preview-DHUoylQ1.js +1 -0
- package/dist/web/assets/index-BImUaigO.js +52 -0
- package/dist/web/assets/index-CSfi6DSU.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-BZi1Gha1.js +1 -0
- package/dist/web/assets/input-DcEk7mA3.js +1 -0
- package/dist/web/assets/{jinja-CWsQj2y0.js → jinja-BmB9YN9l.js} +1 -1
- package/dist/web/assets/{jison-CciJg2NW.js → jison-BaVsKKpw.js} +1 -1
- package/dist/web/assets/{julia-IOQNJAB7.js → julia-BgVBLveX.js} +1 -1
- package/dist/web/assets/{just-BGdHchwS.js → just-C2ENIbl9.js} +1 -1
- package/dist/web/assets/keybindings-store-BGIyqXHI.js +1 -0
- package/dist/web/assets/keybindings-store-CzV2sPls.js +1 -0
- package/dist/web/assets/{latex-D6TOl-L2.js → latex-BiDIWxKL.js} +1 -1
- package/dist/web/assets/{liquid-CVSvu_Wn.js → liquid-NxpapreE.js} +1 -1
- package/dist/web/assets/loader-circle-gSPVxfvH.js +1 -0
- package/dist/web/assets/lock-Did-87UV.js +1 -0
- package/dist/web/assets/{lua-CcKiU6HW.js → lua-DVepQvwH.js} +1 -1
- package/dist/web/assets/markdown-renderer-CcbR33VG.js +1 -0
- package/dist/web/assets/{markdown-renderer-B317vEys.js → markdown-renderer-DlcDhgrF.js} +3 -3
- package/dist/web/assets/{marko--UOicMGo.js → marko-CJ2606Xl.js} +1 -1
- package/dist/web/assets/{mdc-D690aU2C.js → mdc-D2bjqclE.js} +1 -1
- package/dist/web/assets/{media-url-CylYQld1.js → media-url-H17XJF-I.js} +1 -1
- package/dist/web/assets/mobile-bottom-sheet-g-r2hCFa.js +1 -0
- package/dist/web/assets/mobile-explorer-sheet-SIwQXlwA.js +1 -0
- package/dist/web/assets/monitor-Dv8vn_6O.js +1 -0
- package/dist/web/assets/{nextflow-DR8PhpF8.js → nextflow-BtJwUbfF.js} +1 -1
- package/dist/web/assets/{nginx-Qb9pUk1g.js → nginx-j4gyIhHE.js} +1 -1
- package/dist/web/assets/{nim-DLa8R3NS.js → nim-ClH_gjP5.js} +1 -1
- package/dist/web/assets/notification-store-DV5QtUTg.js +1 -0
- package/dist/web/assets/{number-overlay-editor-D9SkFg1Y.js → number-overlay-editor-C1EqJnWq.js} +1 -1
- package/dist/web/assets/{overview-panel-BxDohIEa.js → overview-panel-vTeeJYVZ.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-o5htEcin.js +1 -0
- package/dist/web/assets/panel-store-BSnkjgHt.js +1 -0
- package/dist/web/assets/pdf-preview-CqFGRY0Z.js +1 -0
- package/dist/web/assets/pencil-BlIIg6RH.js +1 -0
- package/dist/web/assets/{perl-AMNGIneF.js → perl-C9H7X7CT.js} +1 -1
- package/dist/web/assets/{php-CDsOOxXn.js → php-Bx2U-cQ_.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-BXAIFSAD.js +1 -0
- package/dist/web/assets/play-4MZi1Axp.js +1 -0
- package/dist/web/assets/portal-container-context-Cm5HipFr.js +1 -0
- package/dist/web/assets/{postgres-viewer-BWZLW7kI.js → postgres-viewer-DHwcQucn.js} +3 -3
- package/dist/web/assets/process-table-BGRJNlpn.js +1 -0
- package/dist/web/assets/{project-store-B8BkHXy5.js → project-store--nvQiy75.js} +1 -1
- package/dist/web/assets/{pug-C2kdkhQ6.js → pug-Cw74sKsE.js} +1 -1
- package/dist/web/assets/{qml-DRDkUp75.js → qml-BXD94Eqz.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-Dbt2Aebl.js +1 -0
- package/dist/web/assets/{razor-wY_6wUeC.js → razor-DZ0-Ge0S.js} +1 -1
- package/dist/web/assets/refresh-cw-B06yaBrW.js +1 -0
- package/dist/web/assets/rotate-ccw-COXu_9oj.js +1 -0
- package/dist/web/assets/{rst-BRpofyNs.js → rst-Dtdh0QUj.js} +1 -1
- package/dist/web/assets/{ruby-ieATBhWm.js → ruby-BC51BW2Q.js} +1 -1
- package/dist/web/assets/{run-in-terminal-CyS5Itj-.js → run-in-terminal-Sd3KyjN4.js} +1 -1
- package/dist/web/assets/{sas-CoOOEbOO.js → sas-BN8i4qOU.js} +1 -1
- package/dist/web/assets/scroll-area-0gljZ6lF.js +1 -0
- package/dist/web/assets/{scss-_nWV0bsb.js → scss-H-QtA7Rz.js} +1 -1
- package/dist/web/assets/send-BlyNJAzy.js +1 -0
- package/dist/web/assets/{send-to-chat-BcO39BDR.js → send-to-chat-u6m8l-rH.js} +1 -1
- package/dist/web/assets/{settings-store-C20lqh0G.js → settings-store-CHY6Kzin.js} +2 -2
- package/dist/web/assets/settings-tab-Dic6TKkU.js +1 -0
- package/dist/web/assets/settings-tab-IY6K1MiZ.js +3 -0
- package/dist/web/assets/{shaderlab-XkqfIfO8.js → shaderlab-CalNsj_x.js} +1 -1
- package/dist/web/assets/shallow-DYo6goJ4.js +1 -0
- package/dist/web/assets/{shellsession-BKBIqTlM.js → shellsession-BFrcoR8x.js} +1 -1
- package/dist/web/assets/{soy-oVDnPzzh.js → soy-CNbku7vP.js} +1 -1
- package/dist/web/assets/{sparql-N2VclEsF.js → sparql-BN_orcVp.js} +1 -1
- package/dist/web/assets/{sql-query-editor-BwPjEaP9.js → sql-query-editor-C6pC3I8l.js} +1 -1
- package/dist/web/assets/sqlite-viewer-DTr5PzUb.js +1 -0
- package/dist/web/assets/{stata-BuuClVDg.js → stata-C6a5Ijzq.js} +1 -1
- package/dist/web/assets/{surrealql-DE5_63MS.js → surrealql-ClplI_HY.js} +1 -1
- package/dist/web/assets/{svelte--YWjlOrK.js → svelte-DNm-UNXB.js} +1 -1
- package/dist/web/assets/switch-DKvKya9y.js +1 -0
- package/dist/web/assets/system-monitor-body-iwGiCns9.js +2 -0
- package/dist/web/assets/system-monitor-tab-DdXQhEel.js +1 -0
- package/dist/web/assets/system-monitor-window-content-BUqRsPK2.js +1 -0
- package/dist/web/assets/tab-host-window-content-BnqGPu8a.js +1 -0
- package/dist/web/assets/{tab-store-DAsvpx4t.js → tab-store-CJuJRapl.js} +1 -1
- package/dist/web/assets/team-member-sheet-LkAFSCvb.js +2 -0
- package/dist/web/assets/team-member-window-content-T4Q5JI-G.js +1 -0
- package/dist/web/assets/{templ-MlpvJx4a.js → templ-CSdqVobu.js} +1 -1
- package/dist/web/assets/terminal-tab-Bb2rZegQ.js +3 -0
- package/dist/web/assets/{tex-0loAoXJG.js → tex-DzSJ4kcZ.js} +1 -1
- package/dist/web/assets/text-wrap-CBT4Gxtg.js +1 -0
- package/dist/web/assets/tool-cards-lhqhrDTT.js +8 -0
- package/dist/web/assets/trash-2-Bk4yYlck.js +1 -0
- package/dist/web/assets/treemap-KZPCXAKY-DUbnl9dz.js +1 -0
- package/dist/web/assets/triangle-alert-B8EYecpe.js +1 -0
- package/dist/web/assets/{ts-tags-pt-Ug0hK.js → ts-tags-C28w3bTg.js} +1 -1
- package/dist/web/assets/{twig-DOePpLOL.js → twig-i5jY3QXB.js} +1 -1
- package/dist/web/assets/upload-BNlX8D07.js +1 -0
- package/dist/web/assets/{use-blob-url-BKyVxOZw.js → use-blob-url-Dsq9OjTh.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-DSCdlrjO.js → use-monaco-theme-BZvlsoBv.js} +1 -1
- package/dist/web/assets/use-open-team-member-DkiEjFYE.js +1 -0
- package/dist/web/assets/{use-websocket-iJfc7EbK.js → use-websocket-B8R50f7f.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-DrwG0NYt.js → vendor-mermaid-By4AVvJY.js} +1 -1
- package/dist/web/assets/video-preview-m0-3p7QZ.js +1 -0
- package/dist/web/assets/{vue-D6f-rprj.js → vue-Ceyet_lv.js} +1 -1
- package/dist/web/assets/{vue-html-DEYRkS1V.js → vue-html-GuU7g_hg.js} +1 -1
- package/dist/web/assets/{vue-vine-CxSG2ojf.js → vue-vine-CxXoaJr2.js} +1 -1
- package/dist/web/assets/window-store-CsEW6jiE.js +1 -0
- package/dist/web/assets/{xml-DhrxbATj.js → xml-CbqOVhkP.js} +1 -1
- package/dist/web/assets/{xsl-CU0ZndUO.js → xsl-KfAmCauy.js} +1 -1
- package/dist/web/index.html +56 -27
- package/dist/web/sw.js +1 -1
- package/docs/code-standards.md +8 -0
- package/docs/codebase-summary.md +19 -5
- package/docs/design-guidelines.md +13 -2
- package/docs/project-roadmap.md +9 -0
- package/docs/system-architecture.md +83 -6
- package/package.json +1 -1
- package/src/web/components/chat/file-picker.tsx +5 -2
- package/src/web/components/chat/mode-selector.tsx +5 -2
- package/src/web/components/chat/model-selector.tsx +5 -2
- package/src/web/components/chat/model-thinking-selector.tsx +5 -2
- package/src/web/components/chat/provider-selector.tsx +5 -2
- package/src/web/components/chat/slash-command-picker.tsx +5 -2
- package/src/web/components/editor/code-editor.tsx +13 -3
- package/src/web/components/editor/conflict-editor.tsx +9 -0
- package/src/web/components/editor/diff-viewer.tsx +9 -0
- package/src/web/components/floating-window/floating-window.tsx +23 -15
- package/src/web/components/floating-window/pip/pip-caption-button.tsx +108 -0
- package/src/web/components/floating-window/pip/pip-focus-target.ts +58 -0
- package/src/web/components/floating-window/pip/pip-geometry.ts +46 -0
- package/src/web/components/floating-window/pip/pip-host.ts +156 -0
- package/src/web/components/floating-window/pip/pip-key-forward.ts +59 -0
- package/src/web/components/floating-window/pip/pip-resize-signal.ts +33 -0
- package/src/web/components/floating-window/pip/pip-style-copy.ts +108 -0
- package/src/web/components/floating-window/pip/pip-support.ts +33 -0
- package/src/web/components/floating-window/tab-host-window-content.tsx +80 -0
- package/src/web/components/floating-window/use-window-body-element.ts +67 -0
- package/src/web/components/floating-window/use-window-drag.ts +5 -0
- package/src/web/components/floating-window/use-window-gesture-context.ts +14 -0
- package/src/web/components/floating-window/use-window-resize.ts +5 -0
- package/src/web/components/floating-window/window-content-registry.ts +4 -16
- package/src/web/components/floating-window/window-layer.tsx +1 -2
- package/src/web/components/floating-window/window-persistence.ts +9 -2
- package/src/web/components/floating-window/window-pip-placeholder.tsx +31 -0
- package/src/web/components/floating-window/window-pip-registry.ts +69 -0
- package/src/web/components/floating-window/window-skin-chrome.tsx +21 -0
- package/src/web/components/floating-window/window-store-types.ts +8 -2
- package/src/web/components/layout/reparenting-tab.tsx +136 -0
- package/src/web/components/layout/tab-bar.tsx +2 -0
- package/src/web/components/layout/tab-pool-collect.ts +38 -2
- package/src/web/components/layout/tab-pool-registry.ts +48 -0
- package/src/web/components/layout/tab-pool.tsx +54 -168
- package/src/web/components/layout/tab-pop-out-menu-item.tsx +42 -0
- package/src/web/components/layout/use-window-panel-reconcile.ts +48 -0
- package/src/web/components/os-explorer/skins/macos-window-chrome.tsx +16 -7
- package/src/web/components/os-explorer/skins/windows-window-chrome.tsx +14 -8
- package/src/web/components/ui/context-menu.tsx +10 -3
- package/src/web/components/ui/dialog.tsx +10 -1
- package/src/web/components/ui/dropdown-menu.tsx +10 -3
- package/src/web/components/ui/mobile-bottom-sheet.tsx +7 -4
- package/src/web/components/ui/portal-container-context.tsx +40 -0
- package/src/web/components/ui/select.tsx +3 -1
- package/src/web/components/ui/tooltip.tsx +3 -1
- package/src/web/hooks/use-terminal.ts +24 -3
- package/src/web/stores/panel-store.ts +72 -7
- package/src/web/stores/panel-utils.ts +36 -0
- package/src/web/stores/window-panel-actions.ts +211 -0
- package/src/web/stores/window-panel-persistence.ts +115 -0
- package/src/web/stores/window-panel-reconcile.ts +97 -0
- package/.spike/group-protected-probe.ts +0 -21
- package/.spike/s.err +0 -63
- package/.spike/tunnel.err +0 -22
- package/.spike/w.err +0 -28
- package/dist/web/assets/ai-resource-editor-mdDKG-rw.js +0 -1
- package/dist/web/assets/api-client-CzABTreM.js +0 -1
- package/dist/web/assets/api-settings-nblja3Rk.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-C7ra20CE.js +0 -1
- package/dist/web/assets/chat-tab-C060A94y.js +0 -15
- package/dist/web/assets/code-editor-WELegzdp.js +0 -10
- package/dist/web/assets/context-menu-Cq0u3SK9.js +0 -1
- package/dist/web/assets/database-viewer-DevnWTV4.js +0 -1
- package/dist/web/assets/diff-viewer-DGxVg1pD.js +0 -4
- package/dist/web/assets/docx-preview-Cx-zLwAw.js +0 -12
- package/dist/web/assets/explorer-body-j_4hVc34.js +0 -2
- package/dist/web/assets/explorer-window-content-DdrGwk3w.js +0 -1
- package/dist/web/assets/git-log-panel-CfpXRJcP.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-D4hYLNJU.js +0 -1
- package/dist/web/assets/group-chat-tab-dYuuknLN.js +0 -1
- package/dist/web/assets/image-preview-Ss38ex8g.js +0 -1
- package/dist/web/assets/index-BiTiXgBZ.css +0 -2
- package/dist/web/assets/index-Ch8l9de-.js +0 -52
- package/dist/web/assets/info-3K5VOQVL-lRlrTlkb.js +0 -1
- package/dist/web/assets/keybindings-store-CDfTjwZX.js +0 -1
- package/dist/web/assets/markdown-renderer-CpRlpLHw.js +0 -1
- package/dist/web/assets/mobile-bottom-sheet-BUOJgiaZ.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-D1Bv9UCT.js +0 -1
- package/dist/web/assets/notification-store-KwTAZT8b.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-BIhk1mvp.js +0 -1
- package/dist/web/assets/panel-store-DCD82zc1.js +0 -1
- package/dist/web/assets/pdf-preview-dwRe54ht.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-SLS6i76l.js +0 -1
- package/dist/web/assets/process-table-CI-fnVsy.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-JJ6O1Er_.js +0 -1
- package/dist/web/assets/settings-tab-mPxrKkfm.js +0 -1
- package/dist/web/assets/sqlite-viewer-Cs-_D942.js +0 -1
- package/dist/web/assets/system-monitor-body-CV7-0hZG.js +0 -2
- package/dist/web/assets/system-monitor-tab-Ce-8Axhh.js +0 -1
- package/dist/web/assets/system-monitor-window-content-CetwYOQy.js +0 -1
- package/dist/web/assets/team-member-sheet-CjgaQjsZ.js +0 -2
- package/dist/web/assets/team-member-window-content-DNJiYWS7.js +0 -1
- package/dist/web/assets/terminal-tab-DF7521sT.js +0 -3
- package/dist/web/assets/tool-cards-DCAXGDJI.js +0 -8
- package/dist/web/assets/treemap-KZPCXAKY-Be3KNmns.js +0 -1
- package/dist/web/assets/use-open-team-member-H4k74HnV.js +0 -1
- package/dist/web/assets/video-preview-B0ZWpX0F.js +0 -1
- package/src/web/components/floating-window/default-window-chrome.tsx +0 -71
- package/src/web/components/os-explorer/skins/explorer-skin-chrome.tsx +0 -17
- /package/dist/web/assets/{abap-MRbmsXOs.js → abap-C6nB04tn.js} +0 -0
- /package/dist/web/assets/{actionscript-3-BDDHKqa4.js → actionscript-3-Vx4rw2sC.js} +0 -0
- /package/dist/web/assets/{ada-DpuV9KwV.js → ada-Ccd8vM20.js} +0 -0
- /package/dist/web/assets/{andromeeda-D6qUCKJo.js → andromeeda-DnBX5xMg.js} +0 -0
- /package/dist/web/assets/{apache-CX1NU_Tl.js → apache-B-9_sx0g.js} +0 -0
- /package/dist/web/assets/{apex-B4-aoQ3K.js → apex-_wPVBYoL.js} +0 -0
- /package/dist/web/assets/{api-client-BSB14J4w.js → api-client-aQb5hHE5.js} +0 -0
- /package/dist/web/assets/{applescript-Dm9NI6KR.js → applescript-CcvD-qr0.js} +0 -0
- /package/dist/web/assets/{apply-theme-BH_d4amk.js → apply-theme-BeLRfsSu.js} +0 -0
- /package/dist/web/assets/{ara-BGN8GAYn.js → ara-C40Ztoms.js} +0 -0
- /package/dist/web/assets/{asciidoc-s_yVuR3t.js → asciidoc-CybYkJV4.js} +0 -0
- /package/dist/web/assets/{asm-BzQdSvTe.js → asm-9eOKwzR0.js} +0 -0
- /package/dist/web/assets/{aurora-x-BJTLETG_.js → aurora-x-B5ZH4t7t.js} +0 -0
- /package/dist/web/assets/{awk-BQEGWxvX.js → awk-Dqilob-2.js} +0 -0
- /package/dist/web/assets/{ayu-dark-CpTORmLc.js → ayu-dark-CPgRhf5r.js} +0 -0
- /package/dist/web/assets/{ayu-light-D8PVj-e6.js → ayu-light-Do06Q52f.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-DyElQHtm.js → ayu-mirage-_BhxcrxY.js} +0 -0
- /package/dist/web/assets/{ballerina-C82NkRtj.js → ballerina-DDwK54QW.js} +0 -0
- /package/dist/web/assets/{bat-0X7DtGI-.js → bat-BGyGlzGk.js} +0 -0
- /package/dist/web/assets/{beancount-Xgvy6YRl.js → beancount-CRWBdapI.js} +0 -0
- /package/dist/web/assets/{berry-CCT2pZcQ.js → berry-DbSFn2gO.js} +0 -0
- /package/dist/web/assets/{bibtex-CpXgZ9M_.js → bibtex-QpsV9gm9.js} +0 -0
- /package/dist/web/assets/{bicep-fkeSA62l.js → bicep-CxS8CUve.js} +0 -0
- /package/dist/web/assets/{bird2-Co7SeAI8.js → bird2-CuZhQzYR.js} +0 -0
- /package/dist/web/assets/{bot-CunPuEdW.js → bot-D6sx11y0.js} +0 -0
- /package/dist/web/assets/{c-BpmrTvJh.js → c-9bnDqE3g.js} +0 -0
- /package/dist/web/assets/{c3-BZ_Z0RrR.js → c3-JMZTrOhA.js} +0 -0
- /package/dist/web/assets/{cadence-B0GBC8OF.js → cadence-DsDNayJS.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-omBzUBBq.js → can-open-in-ppm-BJfpynya.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-DIt_xR7m.js → catppuccin-frappe-DYIKXXBe.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-Dw40AcqA.js → catppuccin-latte-IYYOnUJ8.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-BJ7DfVEF.js → catppuccin-macchiato-BrJ_7mfS.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-NI2lfXzU.js → catppuccin-mocha-gzSu7v7-.js} +0 -0
- /package/dist/web/assets/{chevron-right-BLOtX8Vy.js → chevron-right-De-Wz5Lz.js} +0 -0
- /package/dist/web/assets/{circle-hjUGru6R.js → circle-BCy0AUCo.js} +0 -0
- /package/dist/web/assets/{clarity-F39L0xMJ.js → clarity-DLzsC0Hb.js} +0 -0
- /package/dist/web/assets/{clock-CvhF4DJP.js → clock-C1CQUQPZ.js} +0 -0
- /package/dist/web/assets/{clojure-DloMkd8K.js → clojure-DS1BvoTt.js} +0 -0
- /package/dist/web/assets/{cmake-CwerJun_.js → cmake-CDvsJwYp.js} +0 -0
- /package/dist/web/assets/{code-DDPoqVri.js → code-DJgYrFzm.js} +0 -0
- /package/dist/web/assets/{codeowners-CQyVz4Qf.js → codeowners-BjsYiflJ.js} +0 -0
- /package/dist/web/assets/{codeql-Bb229zuY.js → codeql-CG-7ARat.js} +0 -0
- /package/dist/web/assets/{common-lisp-KMlIwq5I.js → common-lisp-DSO1Lbh9.js} +0 -0
- /package/dist/web/assets/{copy-DKn11Pye.js → copy-BewHj66E.js} +0 -0
- /package/dist/web/assets/{coq-DHX_3IIo.js → coq-DYdh3oP_.js} +0 -0
- /package/dist/web/assets/{csharp-CEmCZv9Q.js → csharp-DxEBz5s0.js} +0 -0
- /package/dist/web/assets/{css-CqZqBD05.js → css-dal3Q-8C.js} +0 -0
- /package/dist/web/assets/{csv-l1g_V5MV.js → csv-CpqjMGiA.js} +0 -0
- /package/dist/web/assets/{csv-parser-CnS0wqr6.js → csv-parser-3umBA4NY.js} +0 -0
- /package/dist/web/assets/{cue-BrxRmilg.js → cue-DinoJ_5k.js} +0 -0
- /package/dist/web/assets/{cypher-rZkKwqZc.js → cypher-DzxqmkUW.js} +0 -0
- /package/dist/web/assets/{d-BALR-QuP.js → d-BxNwJuEC.js} +0 -0
- /package/dist/web/assets/{dark-plus-Cj7rVwh-.js → dark-plus-Clmv3V-0.js} +0 -0
- /package/dist/web/assets/{dart-CWQcdkXk.js → dart-BWVtXD35.js} +0 -0
- /package/dist/web/assets/{data-grid-types-CYvF-xK5.js → data-grid-types-B4n51Fck.js} +0 -0
- /package/dist/web/assets/{database-BH0urvbs.js → database-Y3ESDK4-.js} +0 -0
- /package/dist/web/assets/{dax-BNHD-QBA.js → dax-DsImuWgJ.js} +0 -0
- /package/dist/web/assets/{desktop-CN0IXPrP.js → desktop-B0jJuG2r.js} +0 -0
- /package/dist/web/assets/{diff-BtOXapES.js → diff-CWqAAxoE.js} +0 -0
- /package/dist/web/assets/{dist-DB1Oaqcc.js → dist-B-EXdSYE.js} +0 -0
- /package/dist/web/assets/{dist-Di6G_5jU.js → dist-C0eNNfbt.js} +0 -0
- /package/dist/web/assets/{docker-DNsAo_qO.js → docker-CYFCJdIL.js} +0 -0
- /package/dist/web/assets/{dotenv-D6Pl6aOU.js → dotenv-CKDUjURg.js} +0 -0
- /package/dist/web/assets/{download-zCATy4x4.js → download-DG3_9xXy.js} +0 -0
- /package/dist/web/assets/{dracula-C3m-w12D.js → dracula-CSoPspHE.js} +0 -0
- /package/dist/web/assets/{dracula-soft-BYqvXm6Z.js → dracula-soft-BuFjw5L1.js} +0 -0
- /package/dist/web/assets/{dream-maker-DZAPbPTi.js → dream-maker-B6PdDRZu.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-Ao5SW8ay.js → emacs-lisp-CMcXvD0G.js} +0 -0
- /package/dist/web/assets/{everforest-dark-uC8QYotQ.js → everforest-dark-cU8-wYzi.js} +0 -0
- /package/dist/web/assets/{everforest-light-CTgsVNMr.js → everforest-light-KhorllqK.js} +0 -0
- /package/dist/web/assets/{fennel-WuBw6IR1.js → fennel-BCELZK87.js} +0 -0
- /package/dist/web/assets/{file-exclamation-point-COAwgNGw.js → file-exclamation-point-CZ4DiR75.js} +0 -0
- /package/dist/web/assets/{fish-Byy9dusu.js → fish-BQc0y_jy.js} +0 -0
- /package/dist/web/assets/{fluent-CDxb_sgw.js → fluent-BTINnwF6.js} +0 -0
- /package/dist/web/assets/{format-bytes-BE_W3UBg.js → format-bytes-WVcFxJuT.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-DKWSTamT.js → fortran-free-form-BQim9wDz.js} +0 -0
- /package/dist/web/assets/{gdscript-prYHMgtD.js → gdscript-03w5u8un.js} +0 -0
- /package/dist/web/assets/{gdshader-D-RM-SQk.js → gdshader-Dp2daNzU.js} +0 -0
- /package/dist/web/assets/{genie-CowkJhej.js → genie-CoNcjPiD.js} +0 -0
- /package/dist/web/assets/{gherkin-CLFpoVYJ.js → gherkin-NrPOSPQL.js} +0 -0
- /package/dist/web/assets/{github-dark-default-BK_1Qgb8.js → github-dark-default-DOKw-1cI.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-Cv9lj6f-.js → github-dark-dimmed-DJRNMkEA.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-CW5ZgIDh.js → github-dark-high-contrast-Bj7jJ_Gs.js} +0 -0
- /package/dist/web/assets/{github-dark-nW2F-RLd.js → github-dark-z4RE9ZqA.js} +0 -0
- /package/dist/web/assets/{github-light-D4PqBHGZ.js → github-light-B4k_yMFu.js} +0 -0
- /package/dist/web/assets/{github-light-default-B-cHtJJV.js → github-light-default-BHc-Uzhs.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-Dt0HJq50.js → github-light-high-contrast-CHisIywL.js} +0 -0
- /package/dist/web/assets/{gleam-DwSyXJWP.js → gleam-CfbypZ4q.js} +0 -0
- /package/dist/web/assets/{gn-Cv5WEzHc.js → gn-YoAjyhJa.js} +0 -0
- /package/dist/web/assets/{gnuplot-D7bRdY_M.js → gnuplot-xVkc1f1c.js} +0 -0
- /package/dist/web/assets/{go-DiRVJ22U.js → go-GPCwP3Gu.js} +0 -0
- /package/dist/web/assets/{groovy-BHAgLTeO.js → groovy-Crh4Yww9.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-C8QZ3gzY.js → gruvbox-dark-hard-BluUFuDS.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-Dp1eeid2.js → gruvbox-dark-medium-Cxk1FWQp.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-Cwq0dWVj.js → gruvbox-dark-soft-CHXMiFmj.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-CLQCq2-w.js → gruvbox-light-hard-B6eKPjAD.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-APHsh6Mo.js → gruvbox-light-medium-pDwMm1ut.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-CX-fYc64.js → gruvbox-light-soft-Cxu6kHqK.js} +0 -0
- /package/dist/web/assets/{haskell-C4Tw-TDa.js → haskell-C6JKHjbK.js} +0 -0
- /package/dist/web/assets/{haxe-B7fSduTQ.js → haxe-BuBNdF0a.js} +0 -0
- /package/dist/web/assets/{hcl-Bi3ho6yC.js → hcl-DZpDdGj2.js} +0 -0
- /package/dist/web/assets/{hjson-BXwae2M1.js → hjson-CBkhYRuo.js} +0 -0
- /package/dist/web/assets/{hlsl-CRuQLBSa.js → hlsl-C5nMxnp9.js} +0 -0
- /package/dist/web/assets/{horizon-DtdQ6qjv.js → horizon-VAFvA6R6.js} +0 -0
- /package/dist/web/assets/{horizon-bright-BXSF_uKq.js → horizon-bright-BC0xn7T3.js} +0 -0
- /package/dist/web/assets/{houston-C6ASpUjT.js → houston-BxrUivmz.js} +0 -0
- /package/dist/web/assets/{hy-BrWBHtHY.js → hy-DLtOXoaH.js} +0 -0
- /package/dist/web/assets/{image-gallery-CGvlv8zR.js → image-gallery-Gnf7TdCR.js} +0 -0
- /package/dist/web/assets/{imba-C_JJXckG.js → imba-BdpFXM2W.js} +0 -0
- /package/dist/web/assets/{ini-DEE_vSHQ.js → ini-BInJO_T0.js} +0 -0
- /package/dist/web/assets/{java-CnmpcjcT.js → java-Dxuddnkb.js} +0 -0
- /package/dist/web/assets/{javascript-C-M7sa2e.js → javascript-CVamJfLY.js} +0 -0
- /package/dist/web/assets/{json-BjZ3dAk6.js → json-BLZ0ozYk.js} +0 -0
- /package/dist/web/assets/{json5-BQ2vpqjp.js → json5-BnXzmMKs.js} +0 -0
- /package/dist/web/assets/{jsonc-C5MjoWGx.js → jsonc-CSgkSga7.js} +0 -0
- /package/dist/web/assets/{jsonl-JvhrmQJI.js → jsonl-CY5W2nF2.js} +0 -0
- /package/dist/web/assets/{jsonnet-C5pdZVuo.js → jsonnet-CEJYH3sF.js} +0 -0
- /package/dist/web/assets/{jssm-Db17uybX.js → jssm-CsJc7Uhk.js} +0 -0
- /package/dist/web/assets/{jsx-tJp2Cyqu.js → jsx-jCiRaHU7.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-BculT_Y1.js → kanagawa-dragon-DfoA_GxX.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-yQgHUGwU.js → kanagawa-lotus-BOLYJpWd.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-CyGoWN4d.js → kanagawa-wave-DfKlbT1G.js} +0 -0
- /package/dist/web/assets/{kdl-Bn8R1REF.js → kdl-CmssIFTi.js} +0 -0
- /package/dist/web/assets/{kotlin-DWughK73.js → kotlin-BRsNgp6x.js} +0 -0
- /package/dist/web/assets/{kusto--serPb0x.js → kusto-T8X9jUab.js} +0 -0
- /package/dist/web/assets/{laserwave-DfAPJ1tt.js → laserwave-DkJMVJ8Z.js} +0 -0
- /package/dist/web/assets/{lean-UAm1HOKl.js → lean-C65KGVPq.js} +0 -0
- /package/dist/web/assets/{less-Xj6Ka0fF.js → less-exIPdDlf.js} +0 -0
- /package/dist/web/assets/{lib-DgNcCtj3.js → lib-mC1NZfuw.js} +0 -0
- /package/dist/web/assets/{libesm-CPh1Av0r.js → libesm-DSutUtl1.js} +0 -0
- /package/dist/web/assets/{light-plus-BfS7gPcj.js → light-plus-DiHUXAZt.js} +0 -0
- /package/dist/web/assets/{llvm-DvWiVwvU.js → llvm-CJBnEzFM.js} +0 -0
- /package/dist/web/assets/{log-Bo5z9bNz.js → log-DxMyUMuP.js} +0 -0
- /package/dist/web/assets/{logo-CrIjcMZT.js → logo-CC9NKzca.js} +0 -0
- /package/dist/web/assets/{luau-C9TsYwNt.js → luau-Bw10I6zf.js} +0 -0
- /package/dist/web/assets/{make-GYq4qVbx.js → make-C_6M90m6.js} +0 -0
- /package/dist/web/assets/{markdown-p5mNledS.js → markdown-bR9_R-LF.js} +0 -0
- /package/dist/web/assets/{material-theme-CWYOVxsP.js → material-theme-BUx2Qujn.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-BDGty7YH.js → material-theme-darker-CRJrPgKm.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-JbgOgV3n.js → material-theme-lighter-CUAYppPa.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-EMOpLpa2.js → material-theme-ocean-DuINF1fg.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-CY5hgm7h.js → material-theme-palenight-W6_icGCj.js} +0 -0
- /package/dist/web/assets/{matlab-C-He_NTH.js → matlab-rfqn_b3z.js} +0 -0
- /package/dist/web/assets/{mdx-Cr2TR5fj.js → mdx-Bh1B_YOJ.js} +0 -0
- /package/dist/web/assets/{mermaid-BYc0-B0U.js → mermaid-Dxf6Ya2k.js} +0 -0
- /package/dist/web/assets/{min-dark-CMJwqJqB.js → min-dark-CivZ2L0h.js} +0 -0
- /package/dist/web/assets/{min-light-Cx6vFiEX.js → min-light-B1Ykqtma.js} +0 -0
- /package/dist/web/assets/{mipsasm-Bjer5HwK.js → mipsasm-DynHaM0d.js} +0 -0
- /package/dist/web/assets/{mojo-t90PR-Y2.js → mojo-Clw5PbGH.js} +0 -0
- /package/dist/web/assets/{monokai-dci_PdCm.js → monokai-DFIooFZT.js} +0 -0
- /package/dist/web/assets/{moonbit-AAzI-Hd-.js → moonbit-DnBSZWGM.js} +0 -0
- /package/dist/web/assets/{move-kwBhnhrG.js → move-CCcL2PfL.js} +0 -0
- /package/dist/web/assets/{narrat-CXww2YQL.js → narrat-BDarg5Lk.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-CJXsuXGB.js → nextflow-groovy-DrZOeCNW.js} +0 -0
- /package/dist/web/assets/{night-owl-_GD204Wr.js → night-owl-BnZZCK7v.js} +0 -0
- /package/dist/web/assets/{night-owl-light-DNgkw3kl.js → night-owl-light-CEwBsVHS.js} +0 -0
- /package/dist/web/assets/{nix-BgiorKFd.js → nix-amCzOPMR.js} +0 -0
- /package/dist/web/assets/{nord-CaBmcxFC.js → nord-BIs2BC6q.js} +0 -0
- /package/dist/web/assets/{nushell-DUh4UGx1.js → nushell-Y02fo4yw.js} +0 -0
- /package/dist/web/assets/{objective-c-Cl9KU86S.js → objective-c-7xOZtWW1.js} +0 -0
- /package/dist/web/assets/{objective-cpp-DVkIA8A0.js → objective-cpp-eVtjUvVB.js} +0 -0
- /package/dist/web/assets/{ocaml-vvoHTak0.js → ocaml-Bi6ZwqG4.js} +0 -0
- /package/dist/web/assets/{odin-Cyjw8woZ.js → odin-8xf1Y0S9.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-B1cviILi.js → one-dark-pro-hVv-_y_b.js} +0 -0
- /package/dist/web/assets/{one-light-BPGUJeYI.js → one-light-CJJ3MtHt.js} +0 -0
- /package/dist/web/assets/{openscad-BLMdTUU8.js → openscad-B2HcywLk.js} +0 -0
- /package/dist/web/assets/{pascal-i5niy3e7.js → pascal-C7fllV_7.js} +0 -0
- /package/dist/web/assets/{pkl-CuOV7SsU.js → pkl-qvLC1IWP.js} +0 -0
- /package/dist/web/assets/{plastic-Bf_zE5KL.js → plastic-BT1wHZv2.js} +0 -0
- /package/dist/web/assets/{plsql-cfqEtMD3.js → plsql-1MsmdmJD.js} +0 -0
- /package/dist/web/assets/{plus-BM-Ty0fp.js → plus-BhMZqFsN.js} +0 -0
- /package/dist/web/assets/{po-CFJcWgjr.js → po-BigskytD.js} +0 -0
- /package/dist/web/assets/{poimandres-G5YoaIFf.js → poimandres-DuklniF7.js} +0 -0
- /package/dist/web/assets/{polar-rcjs3i9R.js → polar-e2pjN_sp.js} +0 -0
- /package/dist/web/assets/{postcss-CBKY1FTZ.js → postcss-DtAeYjWw.js} +0 -0
- /package/dist/web/assets/{powerquery-Db7SXLbO.js → powerquery-Cr2PtehI.js} +0 -0
- /package/dist/web/assets/{powershell-LFy3MUTP.js → powershell-BxFTGLJ4.js} +0 -0
- /package/dist/web/assets/{prisma-BE8GR1lH.js → prisma-COWJiwdZ.js} +0 -0
- /package/dist/web/assets/{prolog-DOn5lR1e.js → prolog-DFvGKRx6.js} +0 -0
- /package/dist/web/assets/{proto-wr-TpAK_.js → proto-CcK80lFt.js} +0 -0
- /package/dist/web/assets/{puppet-D2Dkv62u.js → puppet-BF60bZ4F.js} +0 -0
- /package/dist/web/assets/{purescript-DvgJgPdy.js → purescript-zL_69MzU.js} +0 -0
- /package/dist/web/assets/{python-C7TlkHhK.js → python-CIwKhfb_.js} +0 -0
- /package/dist/web/assets/{qmldir-CtZMwhcW.js → qmldir-CXNe04Lo.js} +0 -0
- /package/dist/web/assets/{qss-dNZ2btnl.js → qss-C8lAWe6G.js} +0 -0
- /package/dist/web/assets/{r-BlqnNkHS.js → r-CL5ZVL3_.js} +0 -0
- /package/dist/web/assets/{racket-CzRQrGc4.js → racket-BBfh0uh0.js} +0 -0
- /package/dist/web/assets/{raku-BwutWhBF.js → raku-o6E8R5Q3.js} +0 -0
- /package/dist/web/assets/{react-I_EwPIZi.js → react-CBTnT4sY.js} +0 -0
- /package/dist/web/assets/{red-BMXMywmL.js → red-GomRF2Xp.js} +0 -0
- /package/dist/web/assets/{reg-BqOKrIOw.js → reg-_ffDIvx9.js} +0 -0
- /package/dist/web/assets/{regexp-Bero1BN2.js → regexp-Bl5sF65W.js} +0 -0
- /package/dist/web/assets/{rel-BXKWIElA.js → rel-DgMdqDuj.js} +0 -0
- /package/dist/web/assets/{resolve-theme-B9ABAH_3.js → resolve-theme-CRt_7wpd.js} +0 -0
- /package/dist/web/assets/{riscv-BbbBYJBo.js → riscv-8b3-Ye4X.js} +0 -0
- /package/dist/web/assets/{ron-BtVTWW4b.js → ron-DrmU1KHP.js} +0 -0
- /package/dist/web/assets/{rose-pine-hvkvQzvU.js → rose-pine-C_-E2tF1.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-D7lwhUei.js → rose-pine-dawn-DEfhNlFH.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-CoHDmsIw.js → rose-pine-moon-BdvX3gdn.js} +0 -0
- /package/dist/web/assets/{rosmsg-CdaZFgI8.js → rosmsg-B6GhGpd5.js} +0 -0
- /package/dist/web/assets/{rust-Dy2qsphD.js → rust-DmC97M1-.js} +0 -0
- /package/dist/web/assets/{sass-Bz7NVxDb.js → sass-B0tJOHLM.js} +0 -0
- /package/dist/web/assets/{save-C4z1p51e.js → save-CtIGOjmx.js} +0 -0
- /package/dist/web/assets/{scala-sXSwsNyq.js → scala-n8zaFOXv.js} +0 -0
- /package/dist/web/assets/{scheme-DS7TUbN7.js → scheme-BKD9ztBU.js} +0 -0
- /package/dist/web/assets/{sdbl-iISFvIep.js → sdbl-D8gB5-rS.js} +0 -0
- /package/dist/web/assets/{shellscript-BkIl4ApC.js → shellscript-BfXlf_Ao.js} +0 -0
- /package/dist/web/assets/{shield-check-C5laObJv.js → shield-check-B0iGUiOK.js} +0 -0
- /package/dist/web/assets/{shield-off-DULFtyLS.js → shield-off-BNLWBhcq.js} +0 -0
- /package/dist/web/assets/{slack-dark-B1eg0_m2.js → slack-dark-CylEddse.js} +0 -0
- /package/dist/web/assets/{slack-ochin-mdkc1ldu.js → slack-ochin-w8wg8vuC.js} +0 -0
- /package/dist/web/assets/{smalltalk-CORtd03t.js → smalltalk-hiAXA64u.js} +0 -0
- /package/dist/web/assets/{snazzy-light-Bc6Q2G89.js → snazzy-light-BwlV3Xty.js} +0 -0
- /package/dist/web/assets/{solarized-dark-CF83zRXM.js → solarized-dark-vmNGdykz.js} +0 -0
- /package/dist/web/assets/{solarized-light-BoKQZaYU.js → solarized-light-DGv_0JXq.js} +0 -0
- /package/dist/web/assets/{solidity-DOgi1N4w.js → solidity-Y7QSH0B1.js} +0 -0
- /package/dist/web/assets/{sparkles-Dqsf3hq6.js → sparkles-Dh-_J2Rd.js} +0 -0
- /package/dist/web/assets/{splunk-BXfw5ZLy.js → splunk-BtgpLjHi.js} +0 -0
- /package/dist/web/assets/{sql-BcVs-eX4.js → sql-CRHYhOia.js} +0 -0
- /package/dist/web/assets/{ssh-config-CLCtNkkd.js → ssh-config-DOqSs3au.js} +0 -0
- /package/dist/web/assets/{stylus-DdP992aO.js → stylus-crCAEaBT.js} +0 -0
- /package/dist/web/assets/{swift-BnGb6Lgc.js → swift-eE3rT7TC.js} +0 -0
- /package/dist/web/assets/{synthwave-84-cg9264l9.js → synthwave-84-BWy14LBX.js} +0 -0
- /package/dist/web/assets/{system-verilog-GbHpszs3.js → system-verilog-DC0-DZM4.js} +0 -0
- /package/dist/web/assets/{systemd-Dz-bNsDQ.js → systemd-to5p6N8I.js} +0 -0
- /package/dist/web/assets/{table-CHmxuh6M.js → table-Bbc783ko.js} +0 -0
- /package/dist/web/assets/{talonscript-CFIidoBA.js → talonscript-DoTcU8wm.js} +0 -0
- /package/dist/web/assets/{tasl-Cu-TRTKx.js → tasl-cNZvUs95.js} +0 -0
- /package/dist/web/assets/{tcl-DwCHCB1K.js → tcl-mZE8sZH8.js} +0 -0
- /package/dist/web/assets/{terraform-BzZw4T1z.js → terraform-CqHPpIfu.js} +0 -0
- /package/dist/web/assets/{tokyo-night-RKsj2-tv.js → tokyo-night-Tp2rTIZd.js} +0 -0
- /package/dist/web/assets/{toml-CirbOgDP.js → toml-CU_vscgn.js} +0 -0
- /package/dist/web/assets/{tsv-CraRcWdU.js → tsv-ik7iFB9D.js} +0 -0
- /package/dist/web/assets/{tsx-CjFg0lgw.js → tsx-BMvvMKiv.js} +0 -0
- /package/dist/web/assets/{turtle-B-WBIOa6.js → turtle-DBqKCq9o.js} +0 -0
- /package/dist/web/assets/{typescript-MpLarYn1.js → typescript-DXJDmMZZ.js} +0 -0
- /package/dist/web/assets/{typespec-B7QlHMZ_.js → typespec-CBseCMtZ.js} +0 -0
- /package/dist/web/assets/{typst-CcHSKFZj.js → typst-4oY25U9y.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-BXGVvczu.js → use-is-mobile-D1weanbj.js} +0 -0
- /package/dist/web/assets/{utils-DoY4yTP-.js → utils-BNRH507E.js} +0 -0
- /package/dist/web/assets/{v-xTGhWZuD.js → v-BXaZ_1oy.js} +0 -0
- /package/dist/web/assets/{vala-DwebjH3H.js → vala-BImWJE7z.js} +0 -0
- /package/dist/web/assets/{vb-BxJT2RAy.js → vb-CLfj2_sy.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-CU6zIYMB.js → vendor-xterm-_yyu5n32.js} +0 -0
- /package/dist/web/assets/{verilog-CvV6RHPD.js → verilog-BWa8Ed2b.js} +0 -0
- /package/dist/web/assets/{vesper-CY3qd7E_.js → vesper-BGj1cg6m.js} +0 -0
- /package/dist/web/assets/{vhdl-B9ZX-sUL.js → vhdl-mByK7mlx.js} +0 -0
- /package/dist/web/assets/{viml-Y42h_ExQ.js → viml-CugmlW5g.js} +0 -0
- /package/dist/web/assets/{vitesse-black-DkXP6Sv-.js → vitesse-black-vPdpy9TL.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-B9CkIB6r.js → vitesse-dark-BuQK3dUh.js} +0 -0
- /package/dist/web/assets/{vitesse-light-C7DHrJCK.js → vitesse-light-B3nz1XL9.js} +0 -0
- /package/dist/web/assets/{vyper-Cnd9s5j-.js → vyper-DH_GTIHG.js} +0 -0
- /package/dist/web/assets/{wasm-DQE71XTB.js → wasm-C-LF9GjX.js} +0 -0
- /package/dist/web/assets/{wasm-iWe7Fzjc.js → wasm-DfVbVJlW.js} +0 -0
- /package/dist/web/assets/{wenyan-Bc5Pnm9l.js → wenyan-CzQkHyHx.js} +0 -0
- /package/dist/web/assets/{wgsl-D-YUAWkP.js → wgsl-Du_M1DW9.js} +0 -0
- /package/dist/web/assets/{wikitext-DYQDUYf2.js → wikitext-BWN_w5S7.js} +0 -0
- /package/dist/web/assets/{wit-P6u7mfwy.js → wit-BR13v5HD.js} +0 -0
- /package/dist/web/assets/{wolfram-6SXLUqao.js → wolfram-BoXxp_Xl.js} +0 -0
- /package/dist/web/assets/{x-BcqfTY_7.js → x-nhriOX9o.js} +0 -0
- /package/dist/web/assets/{yaml-CQiMLVcZ.js → yaml-DpR_EF-d.js} +0 -0
- /package/dist/web/assets/{zenscript-DFMywo_P.js → zenscript-C-EdUtUd.js} +0 -0
- /package/dist/web/assets/{zig-CtAjaIiF.js → zig-BD4eA5nU.js} +0 -0
|
@@ -3,6 +3,7 @@ import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
|
|
3
3
|
import { Select as SelectPrimitive } from "radix-ui"
|
|
4
4
|
|
|
5
5
|
import { cn } from "@/lib/utils"
|
|
6
|
+
import { usePortalContainer } from "./portal-container-context"
|
|
6
7
|
|
|
7
8
|
function Select({
|
|
8
9
|
...props
|
|
@@ -55,8 +56,9 @@ function SelectContent({
|
|
|
55
56
|
align = "center",
|
|
56
57
|
...props
|
|
57
58
|
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
|
59
|
+
const container = usePortalContainer()
|
|
58
60
|
return (
|
|
59
|
-
<SelectPrimitive.Portal>
|
|
61
|
+
<SelectPrimitive.Portal container={container}>
|
|
60
62
|
<SelectPrimitive.Content
|
|
61
63
|
data-slot="select-content"
|
|
62
64
|
className={cn(
|
|
@@ -4,6 +4,7 @@ import * as React from "react"
|
|
|
4
4
|
import { Tooltip as TooltipPrimitive } from "radix-ui"
|
|
5
5
|
|
|
6
6
|
import { cn } from "@/lib/utils"
|
|
7
|
+
import { usePortalContainer } from "./portal-container-context"
|
|
7
8
|
|
|
8
9
|
function TooltipProvider({
|
|
9
10
|
delayDuration = 0,
|
|
@@ -36,8 +37,9 @@ function TooltipContent({
|
|
|
36
37
|
children,
|
|
37
38
|
...props
|
|
38
39
|
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
|
40
|
+
const container = usePortalContainer()
|
|
39
41
|
return (
|
|
40
|
-
<TooltipPrimitive.Portal>
|
|
42
|
+
<TooltipPrimitive.Portal container={container}>
|
|
41
43
|
<TooltipPrimitive.Content
|
|
42
44
|
data-slot="tooltip-content"
|
|
43
45
|
sideOffset={sideOffset}
|
|
@@ -8,6 +8,7 @@ import { useSettingsStore } from "@/stores/settings-store";
|
|
|
8
8
|
import { buildXtermTheme } from "@/theme/adapters/xterm-adapter";
|
|
9
9
|
import { resolveTheme as resolvePpmTheme } from "@/theme/resolve-theme";
|
|
10
10
|
import { getCurrentAppliedTheme, THEME_CHANGE_EVENT } from "@/theme/apply-theme";
|
|
11
|
+
import { onHostResize } from "@/components/floating-window/pip/pip-resize-signal";
|
|
11
12
|
import type { PpmTheme } from "@/theme/types";
|
|
12
13
|
|
|
13
14
|
/** Current active PpmTheme → xterm ITheme (prefers the live applied theme). */
|
|
@@ -400,10 +401,17 @@ export function useTerminal(
|
|
|
400
401
|
|
|
401
402
|
// Keepalive heartbeat + zombie detection (covers suspend/sleep/network drop)
|
|
402
403
|
const heartbeatInterval = setInterval(checkConnection, HEARTBEAT_INTERVAL_MS);
|
|
404
|
+
// Always the main document: a tab mounts there and is only moved into a
|
|
405
|
+
// picture-in-picture window afterwards, and this is resolved once at mount.
|
|
406
|
+
// So a terminal that is visible in PiP while the main tab is hidden is still
|
|
407
|
+
// treated as hidden and does not reconnect until the main tab comes back —
|
|
408
|
+
// checkConnection() reads the main document's visibility directly too, so
|
|
409
|
+
// re-resolving this one would not change that on its own.
|
|
410
|
+
const hostDoc = container.ownerDocument;
|
|
403
411
|
const onVisibility = () => {
|
|
404
|
-
if (
|
|
412
|
+
if (hostDoc.visibilityState === "visible") checkConnection();
|
|
405
413
|
};
|
|
406
|
-
|
|
414
|
+
hostDoc.addEventListener("visibilitychange", onVisibility);
|
|
407
415
|
|
|
408
416
|
// ResizeObserver for auto-fit — skip when tab is hidden (0 dimensions).
|
|
409
417
|
// Debounced: an on-screen keyboard resizes the container many times as it
|
|
@@ -426,6 +434,18 @@ export function useTerminal(
|
|
|
426
434
|
});
|
|
427
435
|
resizeObserver.observe(container);
|
|
428
436
|
|
|
437
|
+
// Host-driven resize (picture-in-picture): the ResizeObserver above only
|
|
438
|
+
// reports a PiP-driven size seconds later, so refit as soon as the host says
|
|
439
|
+
// its size changed.
|
|
440
|
+
const unsubHostResize = onHostResize(container, () => {
|
|
441
|
+
try {
|
|
442
|
+
fitAddon.fit();
|
|
443
|
+
sendResize();
|
|
444
|
+
} catch {
|
|
445
|
+
// Ignore fit errors while the tab is detached or tearing down
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
|
|
429
449
|
// React to theme changes — the theme-change event fires after CSS vars are
|
|
430
450
|
// applied, covering style, mode, system-OS, and imported-theme swaps.
|
|
431
451
|
const onThemeChange = () => { term.options.theme = currentXtermTheme(); };
|
|
@@ -434,10 +454,11 @@ export function useTerminal(
|
|
|
434
454
|
|
|
435
455
|
return () => {
|
|
436
456
|
unsubTheme();
|
|
457
|
+
unsubHostResize();
|
|
437
458
|
if (fitTimer) clearTimeout(fitTimer);
|
|
438
459
|
resizeObserver.disconnect();
|
|
439
460
|
clearInterval(heartbeatInterval);
|
|
440
|
-
|
|
461
|
+
hostDoc.removeEventListener("visibilitychange", onVisibility);
|
|
441
462
|
if (reconnectTimer.current) clearTimeout(reconnectTimer.current);
|
|
442
463
|
if (readyQuietTimer.current) clearTimeout(readyQuietTimer.current);
|
|
443
464
|
if (readyMaxTimer.current) clearTimeout(readyMaxTimer.current);
|
|
@@ -17,7 +17,17 @@ import {
|
|
|
17
17
|
deriveTabId,
|
|
18
18
|
visibleTabs,
|
|
19
19
|
DOCK_PANEL_ID,
|
|
20
|
+
isWindowPanelId,
|
|
20
21
|
} from "./panel-utils";
|
|
22
|
+
import {
|
|
23
|
+
makePopOutTab,
|
|
24
|
+
makeRedockFromWindow,
|
|
25
|
+
hydrateWindowPanels,
|
|
26
|
+
stripProjectFromWindowPanels,
|
|
27
|
+
syncWindowPanel,
|
|
28
|
+
} from "./window-panel-actions";
|
|
29
|
+
import { saveWindowPanels } from "./window-panel-persistence";
|
|
30
|
+
import { useWindowStore } from "@/components/floating-window/window-store";
|
|
21
31
|
import {
|
|
22
32
|
makeToggleDock,
|
|
23
33
|
makeSetDockVisible,
|
|
@@ -120,6 +130,16 @@ export interface PanelStore {
|
|
|
120
130
|
/** Park a terminal from a grid panel into __dock__ without killing the PTY session. */
|
|
121
131
|
redockTab: (tabId: string, fromPanelId: string) => void;
|
|
122
132
|
|
|
133
|
+
// Floating-window actions
|
|
134
|
+
/**
|
|
135
|
+
* Detach a tab into a floating window, returning the window id — or null when the
|
|
136
|
+
* request is rejected (mobile, a tab type that cannot detach, or the window cap),
|
|
137
|
+
* in which case nothing changed and the caller reports it.
|
|
138
|
+
*/
|
|
139
|
+
popOutTab: (tabId: string, fromPanelId: string) => string | null;
|
|
140
|
+
/** Send a window's tabs back to the grid and drop its panel. Runs on window close. */
|
|
141
|
+
redockFromWindow: (windowId: string, originPanelId?: string | null) => void;
|
|
142
|
+
|
|
123
143
|
// Helpers
|
|
124
144
|
getPanelForTab: (tabId: string) => Panel | undefined;
|
|
125
145
|
isMobile: () => boolean;
|
|
@@ -171,6 +191,22 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
|
|
|
171
191
|
return panelId ?? get().focusedPanelId;
|
|
172
192
|
}
|
|
173
193
|
|
|
194
|
+
/**
|
|
195
|
+
* The focus to commit when a tab was activated in `pid`.
|
|
196
|
+
*
|
|
197
|
+
* Focus decides where the next `openTab()` with no explicit panel lands, and a
|
|
198
|
+
* floating window renders no tab bar — a tab opened inside one would be unreachable
|
|
199
|
+
* until the window closes, and the id would be persisted with the layout. So
|
|
200
|
+
* activating a tab that lives in a window leaves focus where it was: the window is
|
|
201
|
+
* already in front of the user, nothing more is needed to "focus" it.
|
|
202
|
+
*
|
|
203
|
+
* Every caller here picks `pid` by scanning the whole `panels` map, which includes
|
|
204
|
+
* the off-grid window panels.
|
|
205
|
+
*/
|
|
206
|
+
function focusAfterActivate(pid: string): string {
|
|
207
|
+
return isWindowPanelId(pid) ? get().focusedPanelId : pid;
|
|
208
|
+
}
|
|
209
|
+
|
|
174
210
|
return {
|
|
175
211
|
...defaultLayout(),
|
|
176
212
|
currentProject: null,
|
|
@@ -188,8 +224,13 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
|
|
|
188
224
|
toggleDockExpanded: () => set((s) => ({ dockExpanded: !s.dockExpanded })),
|
|
189
225
|
openInDock: makeOpenInDock(set, get),
|
|
190
226
|
redockTab: makeRedockTab(set, get),
|
|
227
|
+
popOutTab: makePopOutTab(set, get),
|
|
228
|
+
redockFromWindow: makeRedockFromWindow(set, get),
|
|
191
229
|
|
|
192
230
|
switchProject: (projectName) => {
|
|
231
|
+
// Window panels are global, not part of any project's layout blob, so they are
|
|
232
|
+
// merged into the flat map once — before the first project reads it.
|
|
233
|
+
hydrateWindowPanels(set, get);
|
|
193
234
|
const { currentProject, panels, grid, focusedPanelId, projectGrids, projectFocused, dock, projectDock } = get();
|
|
194
235
|
|
|
195
236
|
// No-op if same project
|
|
@@ -401,18 +442,26 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
|
|
|
401
442
|
};
|
|
402
443
|
}
|
|
403
444
|
|
|
445
|
+
// A window panel is off-grid, so the loop above never reaches it: a floating
|
|
446
|
+
// window would keep showing a tab of a project that no longer exists.
|
|
447
|
+
const stripped = stripProjectFromWindowPanels(cleanedPanels, projectName);
|
|
448
|
+
|
|
404
449
|
set({
|
|
405
450
|
projectGrids: newGrids,
|
|
406
451
|
projectFocused: newFocused,
|
|
407
452
|
projectDock: newProjectDock,
|
|
408
|
-
panels:
|
|
453
|
+
panels: stripped.panels,
|
|
409
454
|
currentProject: null,
|
|
410
455
|
});
|
|
456
|
+
saveWindowPanels(stripped.panels);
|
|
457
|
+
for (const windowId of stripped.windowIdsToClose) useWindowStore.getState().close(windowId);
|
|
411
458
|
// Re-trigger full load from localStorage
|
|
412
459
|
get().switchProject(projectName);
|
|
413
460
|
},
|
|
414
461
|
|
|
415
462
|
setFocusedPanel: (panelId) => {
|
|
463
|
+
// Focus drives where the next tab opens, so it must stay on a real, on-grid panel.
|
|
464
|
+
if (isWindowPanelId(panelId)) return;
|
|
416
465
|
if (get().panels[panelId]) set({ focusedPanelId: panelId });
|
|
417
466
|
},
|
|
418
467
|
|
|
@@ -451,7 +500,7 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
|
|
|
451
500
|
const existing = p.tabs.find((t) => t.type === "chat" && t.metadata?.sessionId === sid);
|
|
452
501
|
if (existing) {
|
|
453
502
|
set((s) => ({
|
|
454
|
-
focusedPanelId: p.id,
|
|
503
|
+
focusedPanelId: focusAfterActivate(p.id),
|
|
455
504
|
panels: {
|
|
456
505
|
...s.panels,
|
|
457
506
|
[p.id]: { ...p, tabs: stampActive(p.tabs, existing.id), activeTabId: existing.id, tabHistory: pushHistory(p.tabHistory, existing.id) },
|
|
@@ -469,7 +518,7 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
|
|
|
469
518
|
const existing = p.tabs.find((t) => t.id === baseId);
|
|
470
519
|
if (existing) {
|
|
471
520
|
set((s) => ({
|
|
472
|
-
focusedPanelId: p.id,
|
|
521
|
+
focusedPanelId: focusAfterActivate(p.id),
|
|
473
522
|
panels: {
|
|
474
523
|
...s.panels,
|
|
475
524
|
[p.id]: {
|
|
@@ -581,8 +630,12 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
|
|
|
581
630
|
// no-op for it) so the map-delete would destroy the reserved dock panel, and a
|
|
582
631
|
// later redock (moveTab → __dock__) would silently no-op (to === undefined),
|
|
583
632
|
// leaving the terminal stuck in the grid while an empty dock opens.
|
|
633
|
+
// A window panel is exempt from the "keep the last panel" rule: that rule
|
|
634
|
+
// protects the grid from ending up with nothing to render, and a window panel
|
|
635
|
+
// is not in the grid. Leaving it behind would strand an empty floating window.
|
|
584
636
|
const gridPanelCount = s.grid.flat().length;
|
|
585
|
-
|
|
637
|
+
const removable = isWindowPanelId(pid) || (gridPanelCount > 1 && pid !== DOCK_PANEL_ID);
|
|
638
|
+
if (newTabs.length === 0 && removable) {
|
|
586
639
|
const { [pid]: _, ...rest } = s.panels;
|
|
587
640
|
const newGrid = gridRemovePanel(s.grid, pid);
|
|
588
641
|
// Focus must land on a panel still in the grid — Object.keys(rest)
|
|
@@ -603,6 +656,9 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
|
|
|
603
656
|
if (pid === DOCK_PANEL_ID && activeProjectDockTabCount(get) === 0) {
|
|
604
657
|
get().setDockVisible(false);
|
|
605
658
|
}
|
|
659
|
+
|
|
660
|
+
// A window that lost its last tab closes with it — it can never show anything again.
|
|
661
|
+
if (isWindowPanelId(pid)) syncWindowPanel(set, get, pid);
|
|
606
662
|
},
|
|
607
663
|
|
|
608
664
|
setActiveTab: (tabId, panelId?) => {
|
|
@@ -612,7 +668,7 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
|
|
|
612
668
|
set((s) => {
|
|
613
669
|
const p = s.panels[pid]!;
|
|
614
670
|
return {
|
|
615
|
-
focusedPanelId: pid,
|
|
671
|
+
focusedPanelId: focusAfterActivate(pid),
|
|
616
672
|
panels: { ...s.panels, [pid]: { ...p, tabs: stampActive(p.tabs, tabId), activeTabId: tabId, tabHistory: pushHistory(p.tabHistory, tabId) } },
|
|
617
673
|
};
|
|
618
674
|
});
|
|
@@ -667,8 +723,13 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
|
|
|
667
723
|
// Auto-close empty source panel if not last in current grid.
|
|
668
724
|
// Guard: never attempt to remove __dock__ from the grid — it is intentionally
|
|
669
725
|
// absent from grid and gridRemovePanel would be a no-op, but the panels-map
|
|
670
|
-
// delete would destroy the dock panel entirely.
|
|
671
|
-
|
|
726
|
+
// delete would destroy the dock panel entirely. The dock is reserved and outlives
|
|
727
|
+
// its tabs; only its visibility follows them.
|
|
728
|
+
// A window panel is skipped for a different reason: its lifetime belongs to the
|
|
729
|
+
// floating window, so syncWindowPanel below drops it together with the window
|
|
730
|
+
// rather than leaving an open, empty one behind.
|
|
731
|
+
const offGridSource = fromPanelId === DOCK_PANEL_ID || isWindowPanelId(fromPanelId);
|
|
732
|
+
if (fromTabs.length === 0 && gridPanelCount > 1 && !offGridSource) {
|
|
672
733
|
const { [fromPanelId]: _, ...rest } = s.panels;
|
|
673
734
|
return {
|
|
674
735
|
panels: {
|
|
@@ -690,6 +751,10 @@ export const usePanelStore = create<PanelStore>()((set, get) => {
|
|
|
690
751
|
};
|
|
691
752
|
});
|
|
692
753
|
persist();
|
|
754
|
+
|
|
755
|
+
// Moving the last tab out of a window empties it exactly as closing that tab would,
|
|
756
|
+
// and the window has no tab bar to fill itself from — same owner, same outcome.
|
|
757
|
+
if (isWindowPanelId(fromPanelId)) syncWindowPanel(set, get, fromPanelId);
|
|
693
758
|
},
|
|
694
759
|
|
|
695
760
|
splitPanel: (direction, tabId, sourcePanelId, targetPanelId?) => {
|
|
@@ -29,6 +29,42 @@ export const DOCK_PANEL_ID = "__dock__";
|
|
|
29
29
|
*/
|
|
30
30
|
export const DOCK_ALLOWED_TAB_TYPES = new Set<TabType>(["terminal", "system-monitor"]);
|
|
31
31
|
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Floating-window panels
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Prefix of the reserved panel IDs that host tabs detached into a floating window.
|
|
38
|
+
* Like the dock, such a panel lives in the `panels` map but is intentionally excluded
|
|
39
|
+
* from `grid`, so all grid math (MAX_ROWS, split, column count) ignores it. The
|
|
40
|
+
* window id is the suffix, which is what ties the panel to its window.
|
|
41
|
+
*/
|
|
42
|
+
export const WINDOW_PANEL_PREFIX = "__win__:";
|
|
43
|
+
|
|
44
|
+
/** Panel ID hosting the tabs of the floating window `windowId`. */
|
|
45
|
+
export function windowPanelId(windowId: string): string {
|
|
46
|
+
return `${WINDOW_PANEL_PREFIX}${windowId}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function isWindowPanelId(panelId: string): boolean {
|
|
50
|
+
return panelId.startsWith(WINDOW_PANEL_PREFIX);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** The window a panel belongs to, or null when it is not a window panel. */
|
|
54
|
+
export function windowIdFromPanelId(panelId: string): string | null {
|
|
55
|
+
return isWindowPanelId(panelId) ? panelId.slice(WINDOW_PANEL_PREFIX.length) || null : null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Create the off-grid panel for a floating window, with an empty tab list. */
|
|
59
|
+
export function createWindowPanel(windowId: string): Panel {
|
|
60
|
+
return {
|
|
61
|
+
id: windowPanelId(windowId),
|
|
62
|
+
tabs: [],
|
|
63
|
+
activeTabId: null,
|
|
64
|
+
tabHistory: [],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
32
68
|
/** Visible/height state for the dock — stored per-project via projectDock map. */
|
|
33
69
|
export interface DockState {
|
|
34
70
|
visible: boolean;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action factories for tabs that live in a floating window, for usePanelStore.
|
|
3
|
+
*
|
|
4
|
+
* Extracted to keep panel-store.ts near its size budget, mirroring dock-actions.ts.
|
|
5
|
+
* This module is the ONLY writer of `__win__:` panels, which is what keeps the
|
|
6
|
+
* invariant cheap to check: a window panel exists in the `panels` map and never in
|
|
7
|
+
* `grid`, so no grid math (MAX_ROWS, split, column count) can ever see one.
|
|
8
|
+
*
|
|
9
|
+
* Second invariant, enforced after every move: `focusedPanelId` is never a window
|
|
10
|
+
* panel. `moveTab` focuses its target unconditionally, and `resolvePanel()` sends the
|
|
11
|
+
* next `openTab()` with no explicit panel to the focused one — leaving focus on the
|
|
12
|
+
* window would silently open new tabs inside it.
|
|
13
|
+
*/
|
|
14
|
+
import type { StoreApi } from "zustand";
|
|
15
|
+
import type { Panel } from "./panel-utils";
|
|
16
|
+
import {
|
|
17
|
+
createWindowPanel,
|
|
18
|
+
isWindowPanelId,
|
|
19
|
+
windowIdFromPanelId,
|
|
20
|
+
windowPanelId,
|
|
21
|
+
} from "./panel-utils";
|
|
22
|
+
import { persistDock } from "./dock-actions";
|
|
23
|
+
import { loadWindowPanels, saveWindowPanels } from "./window-panel-persistence";
|
|
24
|
+
import { useWindowStore } from "@/components/floating-window/window-store";
|
|
25
|
+
import { MAX_WINDOWS } from "@/components/floating-window/window-geometry";
|
|
26
|
+
import type { PanelStore } from "./panel-store";
|
|
27
|
+
|
|
28
|
+
type Set = StoreApi<PanelStore>["setState"];
|
|
29
|
+
type Get = StoreApi<PanelStore>["getState"];
|
|
30
|
+
|
|
31
|
+
/** Tab types that never detach — the monitor already owns a window kind of its own. */
|
|
32
|
+
const NON_POPPABLE_TAB_TYPES = new Set(["system-monitor"]);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A grid panel to hold focus: the preferred one when it is still in the grid, else the
|
|
36
|
+
* first grid panel. Returns null only for an empty grid (nothing can be focused).
|
|
37
|
+
*/
|
|
38
|
+
function gridFocusTarget(grid: string[][], preferred?: string | null): string | null {
|
|
39
|
+
const flat = grid.flat();
|
|
40
|
+
if (preferred && flat.includes(preferred)) return preferred;
|
|
41
|
+
return flat[0] ?? null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Persist both halves of a window-panel mutation: the global window-panel blob and the
|
|
46
|
+
* active project's layout (the other side of a move is a grid panel). persistDock writes
|
|
47
|
+
* the whole PanelLayout — grid panels, focus and dock — not just the dock.
|
|
48
|
+
*/
|
|
49
|
+
export function persistWindowPanelChange(get: Get): void {
|
|
50
|
+
saveWindowPanels(get().panels);
|
|
51
|
+
persistDock(get);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Keep a floating window and its panel in lockstep after a tab left the panel: an empty
|
|
56
|
+
* tab-host window has no way back to a tab, so it closes with its panel.
|
|
57
|
+
*
|
|
58
|
+
* Every way a tab can leave — closed, moved to the grid or the dock, dragged out — ends
|
|
59
|
+
* here, so the panel and the window are created and destroyed by the same two functions.
|
|
60
|
+
* Both halves are idempotent: a panel already dropped by the caller and a window already
|
|
61
|
+
* closed are both no-ops.
|
|
62
|
+
*/
|
|
63
|
+
export function syncWindowPanel(set: Set, get: Get, panelId: string): void {
|
|
64
|
+
if (get().panels[panelId]?.tabs.length) {
|
|
65
|
+
saveWindowPanels(get().panels);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
set((s) => {
|
|
69
|
+
const { [panelId]: _dropped, ...rest } = s.panels;
|
|
70
|
+
return { panels: rest };
|
|
71
|
+
});
|
|
72
|
+
saveWindowPanels(get().panels);
|
|
73
|
+
const windowId = windowIdFromPanelId(panelId);
|
|
74
|
+
if (windowId) useWindowStore.getState().close(windowId);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Merge the persisted window panels into the flat panels map, once per session.
|
|
79
|
+
*
|
|
80
|
+
* They are global, so this runs on the first project load and never again — a later
|
|
81
|
+
* switch must not resurrect a panel the user has since re-docked. Live panels win the
|
|
82
|
+
* merge; a stale persisted twin can only be older than what is in memory.
|
|
83
|
+
*/
|
|
84
|
+
let windowPanelsHydrated = false;
|
|
85
|
+
|
|
86
|
+
export function hydrateWindowPanels(set: Set, get: Get): void {
|
|
87
|
+
if (windowPanelsHydrated) return;
|
|
88
|
+
windowPanelsHydrated = true;
|
|
89
|
+
const loaded = loadWindowPanels();
|
|
90
|
+
if (Object.keys(loaded).length === 0) return;
|
|
91
|
+
set({ panels: { ...loaded, ...get().panels } });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Detach a tab into a new floating window. Returns the window id, or null when the
|
|
96
|
+
* request is rejected — in which case nothing is mutated and the caller reports it.
|
|
97
|
+
*/
|
|
98
|
+
export function makePopOutTab(set: Set, get: Get) {
|
|
99
|
+
return function popOutTab(tabId: string, fromPanelId: string): string | null {
|
|
100
|
+
// The window layer is desktop-only; on mobile a detached tab would be invisible.
|
|
101
|
+
if (get().isMobile()) return null;
|
|
102
|
+
|
|
103
|
+
const from = get().panels[fromPanelId];
|
|
104
|
+
const tab = from?.tabs.find((t) => t.id === tabId);
|
|
105
|
+
if (!tab || NON_POPPABLE_TAB_TYPES.has(tab.type)) return null;
|
|
106
|
+
|
|
107
|
+
// Pre-check the cap: at the cap `open()` focuses the oldest window and returns ITS
|
|
108
|
+
// id, which would attach this tab to an unrelated window.
|
|
109
|
+
const windowStore = useWindowStore.getState();
|
|
110
|
+
if (Object.keys(windowStore.windows).length >= MAX_WINDOWS) return null;
|
|
111
|
+
|
|
112
|
+
const windowId = windowStore.open("tab-host", { originPanelId: fromPanelId, title: tab.title });
|
|
113
|
+
const panelId = windowPanelId(windowId);
|
|
114
|
+
set((s) => ({ panels: { ...s.panels, [panelId]: createWindowPanel(windowId) } }));
|
|
115
|
+
|
|
116
|
+
get().moveTab(tabId, fromPanelId, panelId);
|
|
117
|
+
|
|
118
|
+
const focus = gridFocusTarget(get().grid, fromPanelId);
|
|
119
|
+
if (focus) set({ focusedPanelId: focus });
|
|
120
|
+
persistWindowPanelChange(get);
|
|
121
|
+
return windowId;
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Send every tab of a window's panel back to the grid and drop the panel.
|
|
127
|
+
*
|
|
128
|
+
* Called from the window body's layout-effect cleanup, so it covers every close path
|
|
129
|
+
* (titlebar ×, keyboard close, a programmatic `close()`), and is a no-op once the panel
|
|
130
|
+
* is gone — closing an emptied window re-enters here and must not resurrect anything.
|
|
131
|
+
*/
|
|
132
|
+
export function makeRedockFromWindow(set: Set, get: Get) {
|
|
133
|
+
return function redockFromWindow(windowId: string, originPanelId?: string | null): void {
|
|
134
|
+
const panelId = windowPanelId(windowId);
|
|
135
|
+
const panel = get().panels[panelId];
|
|
136
|
+
if (!panel) return;
|
|
137
|
+
|
|
138
|
+
const target = redockTarget(get(), originPanelId);
|
|
139
|
+
if (target) {
|
|
140
|
+
for (const tab of [...panel.tabs]) get().moveTab(tab.id, panelId, target);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
set((s) => {
|
|
144
|
+
const { [panelId]: _dropped, ...rest } = s.panels;
|
|
145
|
+
// moveTab focused the target; re-assert it here so the resolved target wins even
|
|
146
|
+
// when the last moveTab picked a different one (or none ran at all).
|
|
147
|
+
const focus = gridFocusTarget(s.grid, target ?? s.focusedPanelId);
|
|
148
|
+
return focus ? { panels: rest, focusedPanelId: focus } : { panels: rest };
|
|
149
|
+
});
|
|
150
|
+
persistWindowPanelChange(get);
|
|
151
|
+
|
|
152
|
+
// The body can unmount without the window closing: the whole desktop window layer is
|
|
153
|
+
// dropped below the `md` breakpoint, which re-docks the tabs but would leave the
|
|
154
|
+
// window entry in `ppm-windows` — restored empty and unfillable on the way back, and
|
|
155
|
+
// burning one of MAX_WINDOWS on every reload. `close()` is a no-op when the window is
|
|
156
|
+
// already gone (the ×/keyboard paths), and re-entry here returns early: the panel is
|
|
157
|
+
// deleted above.
|
|
158
|
+
useWindowStore.getState().close(windowId);
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Where a detached tab goes home to: its origin panel while that still exists, else the
|
|
164
|
+
* focused panel when it is a grid panel, else the first grid panel. The origin may be the
|
|
165
|
+
* dock (a terminal parked there before it was detached) but never another window.
|
|
166
|
+
*/
|
|
167
|
+
function redockTarget(state: PanelStore, originPanelId?: string | null): string | null {
|
|
168
|
+
if (originPanelId && state.panels[originPanelId] && !isWindowPanelId(originPanelId)) {
|
|
169
|
+
return originPanelId;
|
|
170
|
+
}
|
|
171
|
+
return gridFocusTarget(state.grid, state.focusedPanelId);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Drop a project's tabs from every window panel, returning the panels map to commit and
|
|
176
|
+
* the windows whose panel is now empty. Used when a project is reloaded: its grid panels
|
|
177
|
+
* are discarded, and a window still showing one of its tabs would outlive the project.
|
|
178
|
+
*/
|
|
179
|
+
export function stripProjectFromWindowPanels(
|
|
180
|
+
panels: Record<string, Panel>,
|
|
181
|
+
projectName: string,
|
|
182
|
+
): { panels: Record<string, Panel>; windowIdsToClose: string[] } {
|
|
183
|
+
const next: Record<string, Panel> = { ...panels };
|
|
184
|
+
const windowIdsToClose: string[] = [];
|
|
185
|
+
|
|
186
|
+
for (const [id, panel] of Object.entries(panels)) {
|
|
187
|
+
if (!isWindowPanelId(id)) continue;
|
|
188
|
+
const tabs = panel.tabs.filter((t) => t.projectId !== projectName);
|
|
189
|
+
if (tabs.length === panel.tabs.length) continue;
|
|
190
|
+
|
|
191
|
+
const windowId = windowIdFromPanelId(id);
|
|
192
|
+
if (tabs.length === 0) {
|
|
193
|
+
delete next[id];
|
|
194
|
+
if (windowId) windowIdsToClose.push(windowId);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
const ids = new Set(tabs.map((t) => t.id));
|
|
198
|
+
const tabHistory = panel.tabHistory.filter((h) => ids.has(h));
|
|
199
|
+
next[id] = {
|
|
200
|
+
...panel,
|
|
201
|
+
tabs,
|
|
202
|
+
tabHistory,
|
|
203
|
+
activeTabId:
|
|
204
|
+
panel.activeTabId && ids.has(panel.activeTabId)
|
|
205
|
+
? panel.activeTabId
|
|
206
|
+
: (tabHistory[tabHistory.length - 1] ?? tabs[tabs.length - 1]!.id),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return { panels: next, windowIdsToClose };
|
|
211
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* localStorage persistence for the off-grid panels that host detached tabs.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately its own global key instead of a field inside `PanelLayout`: floating
|
|
5
|
+
* windows are global (one `ppm-windows` blob for the whole app) while a PanelLayout is
|
|
6
|
+
* per project. Folding a global panel into a per-project blob is what forced the
|
|
7
|
+
* merge/union machinery the dock needs on every project switch. Consequence, accepted:
|
|
8
|
+
* window panels are not synced to the server workspace — the same limitation the window
|
|
9
|
+
* geometry already has.
|
|
10
|
+
*/
|
|
11
|
+
import type { Panel } from "./panel-utils";
|
|
12
|
+
import { isWindowPanelId } from "./panel-utils";
|
|
13
|
+
import type { Tab, TabType } from "./tab-store";
|
|
14
|
+
|
|
15
|
+
const STORAGE_KEY = "ppm-window-panels";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Tab types a persisted window panel may bring back. Written as an exhaustive record so
|
|
19
|
+
* adding a TabType is a compile error here rather than a silent gap. `system-monitor` is
|
|
20
|
+
* false because it can never be popped out; everything else a crafted blob names is
|
|
21
|
+
* rejected, so it cannot mount an arbitrary component in the privileged window slot.
|
|
22
|
+
*/
|
|
23
|
+
const POPPABLE_TAB_TYPES: Record<TabType, boolean> = {
|
|
24
|
+
terminal: true,
|
|
25
|
+
chat: true,
|
|
26
|
+
editor: true,
|
|
27
|
+
database: true,
|
|
28
|
+
sqlite: true,
|
|
29
|
+
postgres: true,
|
|
30
|
+
"git-diff": true,
|
|
31
|
+
settings: true,
|
|
32
|
+
extension: true,
|
|
33
|
+
"extension-webview": true,
|
|
34
|
+
"conflict-editor": true,
|
|
35
|
+
"system-monitor": false,
|
|
36
|
+
"git-log": true,
|
|
37
|
+
"ai-resource": true,
|
|
38
|
+
group: true,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function isPoppableTabType(type: unknown): type is TabType {
|
|
42
|
+
return typeof type === "string" && POPPABLE_TAB_TYPES[type as TabType] === true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isValidTab(value: unknown): value is Tab {
|
|
46
|
+
if (!value || typeof value !== "object") return false;
|
|
47
|
+
const t = value as Record<string, unknown>;
|
|
48
|
+
return typeof t.id === "string" && !!t.id && typeof t.title === "string" && isPoppableTabType(t.type);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Keep only the window panels out of the full panels map, dropping empty ones. */
|
|
52
|
+
function selectWindowPanels(panels: Record<string, Panel>): Record<string, Panel> {
|
|
53
|
+
const out: Record<string, Panel> = {};
|
|
54
|
+
for (const [id, panel] of Object.entries(panels)) {
|
|
55
|
+
if (!isWindowPanelId(id) || panel.tabs.length === 0) continue;
|
|
56
|
+
out[id] = panel;
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function saveWindowPanels(panels: Record<string, Panel>): void {
|
|
62
|
+
try {
|
|
63
|
+
const windowPanels = selectWindowPanels(panels);
|
|
64
|
+
if (Object.keys(windowPanels).length === 0) localStorage.removeItem(STORAGE_KEY);
|
|
65
|
+
else localStorage.setItem(STORAGE_KEY, JSON.stringify(windowPanels));
|
|
66
|
+
} catch {
|
|
67
|
+
/* quota exceeded or storage disabled — never block a tab move over persistence */
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Read persisted window panels, dropping anything malformed or not allowed in a window. */
|
|
72
|
+
export function loadWindowPanels(): Record<string, Panel> {
|
|
73
|
+
let raw: string | null = null;
|
|
74
|
+
try {
|
|
75
|
+
raw = localStorage.getItem(STORAGE_KEY);
|
|
76
|
+
} catch {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
if (!raw) return {};
|
|
80
|
+
|
|
81
|
+
let parsed: unknown;
|
|
82
|
+
try {
|
|
83
|
+
parsed = JSON.parse(raw);
|
|
84
|
+
} catch {
|
|
85
|
+
return {};
|
|
86
|
+
}
|
|
87
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
88
|
+
|
|
89
|
+
const out: Record<string, Panel> = {};
|
|
90
|
+
for (const [id, value] of Object.entries(parsed as Record<string, unknown>)) {
|
|
91
|
+
if (!isWindowPanelId(id) || !value || typeof value !== "object") continue;
|
|
92
|
+
const panel = value as Record<string, unknown>;
|
|
93
|
+
if (!Array.isArray(panel.tabs)) continue;
|
|
94
|
+
const tabs = panel.tabs.filter(isValidTab);
|
|
95
|
+
if (tabs.length === 0) continue;
|
|
96
|
+
const ids = new Set(tabs.map((t) => t.id));
|
|
97
|
+
const tabHistory = Array.isArray(panel.tabHistory)
|
|
98
|
+
? panel.tabHistory.filter((h): h is string => typeof h === "string" && ids.has(h))
|
|
99
|
+
: [];
|
|
100
|
+
const activeTabId =
|
|
101
|
+
typeof panel.activeTabId === "string" && ids.has(panel.activeTabId)
|
|
102
|
+
? panel.activeTabId
|
|
103
|
+
: (tabHistory[tabHistory.length - 1] ?? tabs[tabs.length - 1]!.id);
|
|
104
|
+
out[id] = { id, tabs, activeTabId, tabHistory };
|
|
105
|
+
}
|
|
106
|
+
return out;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function clearWindowPanels(): void {
|
|
110
|
+
try {
|
|
111
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
112
|
+
} catch {
|
|
113
|
+
/* storage disabled */
|
|
114
|
+
}
|
|
115
|
+
}
|