@hienlh/ppm 0.18.9 → 0.18.11
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/.spike/cdp-client.ts +116 -0
- package/.spike/cleanup-ppm-workspace.mjs +44 -0
- package/.spike/group-protected-probe.ts +21 -0
- package/.spike/pip-eval.ts +17 -0
- package/.spike/pip-page-helpers.js +119 -0
- package/.spike/pip-results-editor-glue.json +105 -0
- package/.spike/pip-results-editor.json +158 -0
- package/.spike/pip-results-input-isolation.json +28 -0
- package/.spike/pip-results-key-probe.json +58 -0
- package/.spike/pip-results-listener-survival.json +98 -0
- package/.spike/pip-results-listeners.json +36 -0
- package/.spike/pip-results-pagehide.json +92 -0
- package/.spike/pip-results-resize.json +104 -0
- package/.spike/pip-results-terminal-debug.json +99 -0
- package/.spike/pip-results-terminal-v2.json +191 -0
- package/.spike/pip-results-terminal.json +220 -0
- package/.spike/pip-results-xterm-trace.json +73 -0
- package/.spike/pip-spike-common.ts +83 -0
- package/.spike/pip-spike-editor-glue.ts +82 -0
- package/.spike/pip-spike-editor.ts +129 -0
- package/.spike/pip-spike-input-isolation.ts +38 -0
- package/.spike/pip-spike-key-probe.ts +34 -0
- package/.spike/pip-spike-listener-survival.ts +54 -0
- package/.spike/pip-spike-listeners.ts +19 -0
- package/.spike/pip-spike-pagehide.ts +59 -0
- package/.spike/pip-spike-resize.ts +42 -0
- package/.spike/pip-spike-setup.ts +63 -0
- package/.spike/pip-spike-terminal-debug.ts +81 -0
- package/.spike/pip-spike-terminal-v2.ts +139 -0
- package/.spike/pip-spike-terminal.ts +169 -0
- package/.spike/pip-spike-xterm-trace.ts +36 -0
- package/.spike/probe-drag-memo-error.mjs +67 -0
- package/.spike/read-dev-db.ts +15 -0
- package/.spike/scratch-editor-target.ts +7 -0
- package/.spike/smoke-unified-chrome-pip.mjs +353 -0
- package/.spike/tunnel.err +63 -42
- package/.spike/vite-restart.err +663 -0
- package/.spike/w.err +569 -94
- package/CHANGELOG.md +25 -0
- 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-CdH_h0vD.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-CY_454vd.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-CuOQrHIS.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/format-bytes-WVcFxJuT.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-Cehfgrzc.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-pVzBdkpl.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-vTeeJYVZ.js +1 -0
- 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-CR6VpTrX.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/resolve-theme-CRt_7wpd.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-BPYsJDsn.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-CGucu3fb.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-C-Rxv8JN.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/system/build-kill-request.ts +28 -1
- package/src/web/components/system/chart-scale.ts +3 -3
- package/src/web/components/system/kill-confirm-dialog.tsx +44 -28
- package/src/web/components/system/metric-chart-canvas.tsx +1 -2
- package/src/web/components/system/process-columns-grid.ts +39 -29
- package/src/web/components/system/process-group-row.tsx +31 -8
- package/src/web/components/system/process-row.tsx +6 -7
- package/src/web/components/system/process-table-model.ts +4 -22
- package/src/web/components/system/process-table-toolbar.tsx +12 -43
- package/src/web/components/system/process-table.tsx +22 -63
- package/src/web/components/system/sortable-header.tsx +33 -8
- package/src/web/components/system/system-monitor-body.tsx +1 -1
- package/src/web/components/system/use-column-widths.ts +91 -0
- package/src/web/components/system/use-process-kill.ts +100 -0
- 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/src/web/styles/globals.css +5 -3
- package/src/web/theme/builtin/aurora.ts +8 -5
- package/dist/web/assets/ai-resource-editor-DFCuNe-P.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-flMPLoKb.js +0 -15
- package/dist/web/assets/code-editor-C2VQbXzw.js +0 -10
- package/dist/web/assets/context-menu-Cq0u3SK9.js +0 -1
- package/dist/web/assets/database-viewer-BCZOTrPT.js +0 -1
- package/dist/web/assets/diff-viewer-BwfMN-nW.js +0 -4
- package/dist/web/assets/docx-preview-D3Sdh_aT.js +0 -12
- package/dist/web/assets/explorer-body-BKOMM566.js +0 -2
- package/dist/web/assets/explorer-window-content-Bbzijk8t.js +0 -1
- package/dist/web/assets/format-bytes-Dk7B73B7.js +0 -1
- package/dist/web/assets/git-log-panel-DcV7PhqW.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-D4hYLNJU.js +0 -1
- package/dist/web/assets/group-chat-tab-BVPYxjz-.js +0 -1
- package/dist/web/assets/image-preview-D-Ok10eZ.js +0 -1
- package/dist/web/assets/index-CerSxGdf.js +0 -52
- package/dist/web/assets/index-DRA_OpWY.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-lRlrTlkb.js +0 -1
- package/dist/web/assets/keybindings-store-aIY40k2o.js +0 -1
- package/dist/web/assets/markdown-renderer-I89kyQhe.js +0 -1
- package/dist/web/assets/mobile-bottom-sheet-BUOJgiaZ.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-5Uj9ZMM9.js +0 -1
- package/dist/web/assets/notification-store-DJ-OtAG3.js +0 -1
- package/dist/web/assets/overview-panel-Cgi3UPY1.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-Di5xHFyT.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-SLS6i76l.js +0 -1
- package/dist/web/assets/process-table-DL6shbzt.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-JJ6O1Er_.js +0 -1
- package/dist/web/assets/resolve-theme-IdhSR-gx.js +0 -1
- package/dist/web/assets/settings-tab-jbiQwozX.js +0 -1
- package/dist/web/assets/sqlite-viewer-Bq9ZJA2y.js +0 -1
- package/dist/web/assets/system-monitor-body-CKEYWyN9.js +0 -2
- package/dist/web/assets/system-monitor-tab-WjhFFHyM.js +0 -1
- package/dist/web/assets/system-monitor-window-content-CMiISeoC.js +0 -1
- package/dist/web/assets/team-member-sheet-oY5EkH53.js +0 -2
- package/dist/web/assets/team-member-window-content-yCBeI_5X.js +0 -1
- package/dist/web/assets/terminal-tab-BxHtMR7h.js +0 -3
- package/dist/web/assets/tool-cards-BcGrk1zk.js +0 -8
- package/dist/web/assets/treemap-KZPCXAKY-Be3KNmns.js +0 -1
- package/dist/web/assets/use-open-team-member-DdrRXj-M.js +0 -1
- package/dist/web/assets/video-preview-DYAbbmd0.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/src/web/components/system/sparkline-canvas.tsx +0 -63
- /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/{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/{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
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TabPool — persistent tab rendering with DOM reparenting.
|
|
3
3
|
*
|
|
4
|
-
* All tab components are mounted ONCE
|
|
5
|
-
*
|
|
6
|
-
* physically moves
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* All tab components are mounted ONCE and never unmounted when moved between panels or
|
|
5
|
+
* split. Each tab gets a wrapper element that is created once and portalled into; a
|
|
6
|
+
* layout effect physically moves that wrapper into the correct panel slot via appendChild
|
|
7
|
+
* (which moves, not clones). Component instances, hooks, and all internal state (xterm
|
|
8
|
+
* buffer, Monaco editor, chat scroll) survive.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
* to
|
|
10
|
+
* A portal is safe here precisely because the container element is stable: the objection
|
|
11
|
+
* to portals is that *changing* a portal's container remounts its children, and nothing
|
|
12
|
+
* ever swaps a wrapper. In exchange React binds its listeners to the wrapper itself, so
|
|
13
|
+
* they travel with the node — including into another document.
|
|
12
14
|
*/
|
|
13
|
-
import {
|
|
14
|
-
import { Loader2 } from "lucide-react";
|
|
15
|
+
import { useState, useEffect, useSyncExternalStore, lazy } from "react";
|
|
15
16
|
import { usePanelStore } from "@/stores/panel-store";
|
|
16
17
|
import { useMountedTabsStore } from "@/stores/mounted-tabs-store";
|
|
17
18
|
import type { TabType } from "@/stores/tab-store";
|
|
18
19
|
import { collectTabEntries, filterMountableEntries } from "./tab-pool-collect";
|
|
19
|
-
import {
|
|
20
|
+
import { slotRegistry } from "./tab-pool-registry";
|
|
21
|
+
import { ReparentingTab } from "./reparenting-tab";
|
|
22
|
+
import { useWindowPanelReconcile } from "./use-window-panel-reconcile";
|
|
23
|
+
|
|
24
|
+
export { registerPanelSlot } from "./tab-pool-registry";
|
|
20
25
|
|
|
21
26
|
// ---------------------------------------------------------------------------
|
|
22
27
|
// Lazy tab components (single source of truth for all tab types)
|
|
@@ -39,59 +44,29 @@ const TAB_COMPONENTS: Record<TabType, React.LazyExoticComponent<React.ComponentT
|
|
|
39
44
|
group: lazy(() => import("@/components/group-chat/group-chat-tab").then((m) => ({ default: m.GroupChatTab }))),
|
|
40
45
|
};
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
register(panelId: string, el: HTMLDivElement | null) {
|
|
53
|
-
if (el) {
|
|
54
|
-
if (this.slots.get(panelId) === el) return;
|
|
55
|
-
this.slots.set(panelId, el);
|
|
56
|
-
} else {
|
|
57
|
-
if (!this.slots.has(panelId)) return;
|
|
58
|
-
this.slots.delete(panelId);
|
|
59
|
-
}
|
|
60
|
-
this.version++;
|
|
61
|
-
this.listeners.forEach((fn) => fn());
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
get(panelId: string): HTMLDivElement | undefined {
|
|
65
|
-
return this.slots.get(panelId);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
subscribe(fn: SlotListener): () => void {
|
|
69
|
-
this.listeners.add(fn);
|
|
70
|
-
return () => this.listeners.delete(fn);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
getVersion(): number {
|
|
74
|
-
return this.version;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const registry = new SlotRegistry();
|
|
79
|
-
|
|
80
|
-
/** Called by EditorPanel to register its content slot */
|
|
81
|
-
export function registerPanelSlot(panelId: string, el: HTMLDivElement | null) {
|
|
82
|
-
registry.register(panelId, el);
|
|
83
|
-
}
|
|
47
|
+
const HIDDEN_CONTAINER_STYLE: React.CSSProperties = {
|
|
48
|
+
position: "fixed",
|
|
49
|
+
top: 0,
|
|
50
|
+
left: 0,
|
|
51
|
+
width: 0,
|
|
52
|
+
height: 0,
|
|
53
|
+
overflow: "hidden",
|
|
54
|
+
pointerEvents: "none",
|
|
55
|
+
visibility: "hidden",
|
|
56
|
+
};
|
|
84
57
|
|
|
85
58
|
// ---------------------------------------------------------------------------
|
|
86
|
-
// TabPool — renders all tabs
|
|
59
|
+
// TabPool — renders all tabs into wrappers parked off-screen, reparents into slots
|
|
87
60
|
// ---------------------------------------------------------------------------
|
|
88
61
|
export function TabPool() {
|
|
89
|
-
|
|
62
|
+
// State, not a ref: a tab's wrapper must be appended to a real element on its very
|
|
63
|
+
// first layout effect, and a parent ref is still null while its children's effects run.
|
|
64
|
+
const [hiddenContainer, setHiddenContainer] = useState<HTMLDivElement | null>(null);
|
|
90
65
|
|
|
91
66
|
// Re-render when slots change (panel mount/unmount)
|
|
92
67
|
useSyncExternalStore(
|
|
93
|
-
(cb) =>
|
|
94
|
-
() =>
|
|
68
|
+
(cb) => slotRegistry.subscribe(cb),
|
|
69
|
+
() => slotRegistry.getVersion(),
|
|
95
70
|
);
|
|
96
71
|
|
|
97
72
|
const panels = usePanelStore((s) => s.panels);
|
|
@@ -99,6 +74,10 @@ export function TabPool() {
|
|
|
99
74
|
const currentProject = usePanelStore((s) => s.currentProject);
|
|
100
75
|
const projectGrids = usePanelStore((s) => s.projectGrids);
|
|
101
76
|
|
|
77
|
+
// Detached tabs and their floating windows are persisted separately, so a reload can
|
|
78
|
+
// restore one without the other; this repairs the mismatch once per project load.
|
|
79
|
+
useWindowPanelReconcile();
|
|
80
|
+
|
|
102
81
|
// Collect tabs from ALL mounted projects (not just active) to preserve
|
|
103
82
|
// tab state across project switches (keep-alive). Each project's
|
|
104
83
|
// PanelLayout stays mounted (CSS hidden), so slots remain registered.
|
|
@@ -133,118 +112,25 @@ export function TabPool() {
|
|
|
133
112
|
}, [visibleKey]);
|
|
134
113
|
|
|
135
114
|
return (
|
|
136
|
-
// Off-screen
|
|
137
|
-
//
|
|
138
|
-
<div ref={
|
|
139
|
-
{
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
// ReparentingTab — mounts once, physically moves between panel slots
|
|
156
|
-
// ---------------------------------------------------------------------------
|
|
157
|
-
interface ReparentingTabProps {
|
|
158
|
-
tabId: string;
|
|
159
|
-
panelId: string;
|
|
160
|
-
type: TabType;
|
|
161
|
-
metadata?: Record<string, unknown>;
|
|
162
|
-
isActive: boolean;
|
|
163
|
-
hiddenContainer: React.RefObject<HTMLDivElement | null>;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function ReparentingTab({ tabId, panelId, type, metadata, isActive, hiddenContainer }: ReparentingTabProps) {
|
|
167
|
-
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
168
|
-
const Component = TAB_COMPONENTS[type];
|
|
169
|
-
|
|
170
|
-
// On unmount: move wrapper back to hidden container so React's removeChild
|
|
171
|
-
// can find it. Without this, the wrapper stays orphaned in the slot (the DOM
|
|
172
|
-
// patch swallows the NotFoundError) and covers other tabs.
|
|
173
|
-
useLayoutEffect(() => {
|
|
174
|
-
return () => {
|
|
175
|
-
const wrapper = wrapperRef.current;
|
|
176
|
-
const hidden = hiddenContainer.current;
|
|
177
|
-
if (wrapper && hidden && wrapper.parentElement !== hidden) {
|
|
178
|
-
hidden.appendChild(wrapper);
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
}, [hiddenContainer]);
|
|
182
|
-
|
|
183
|
-
// Imperatively move the wrapper DOM node into the correct panel slot.
|
|
184
|
-
// appendChild on an already-mounted node moves it (DOM spec — no clone/destroy).
|
|
185
|
-
// useLayoutEffect runs before paint, so the user never sees the off-screen state.
|
|
186
|
-
// No deps — must run every render because React's reconciliation may call
|
|
187
|
-
// insertBefore() to reorder keyed children, moving reparented nodes back
|
|
188
|
-
// to the hidden container. The early-return guard keeps this cheap.
|
|
189
|
-
useLayoutEffect(() => {
|
|
190
|
-
const wrapper = wrapperRef.current;
|
|
191
|
-
const slot = registry.get(panelId);
|
|
192
|
-
if (!wrapper) return;
|
|
193
|
-
|
|
194
|
-
// Panel slot not mounted (e.g., mobile renders only the focused panel).
|
|
195
|
-
// Move wrapper back to hidden container so it doesn't overlap in the wrong slot.
|
|
196
|
-
if (!slot) {
|
|
197
|
-
const hidden = hiddenContainer.current;
|
|
198
|
-
if (hidden && wrapper.parentElement !== hidden) {
|
|
199
|
-
hidden.appendChild(wrapper);
|
|
200
|
-
}
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (wrapper.parentElement === slot) return;
|
|
205
|
-
|
|
206
|
-
// Save scroll positions — appendChild resets them during the DOM move
|
|
207
|
-
const scrollables: { el: Element; top: number; left: number }[] = [];
|
|
208
|
-
wrapper.querySelectorAll("*").forEach((el) => {
|
|
209
|
-
if (el.scrollTop || el.scrollLeft) {
|
|
210
|
-
scrollables.push({ el, top: el.scrollTop, left: el.scrollLeft });
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
slot.appendChild(wrapper);
|
|
215
|
-
|
|
216
|
-
// Restore scroll positions synchronously before paint
|
|
217
|
-
for (const { el, top, left } of scrollables) {
|
|
218
|
-
el.scrollTop = top;
|
|
219
|
-
el.scrollLeft = left;
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
if (!Component) return null;
|
|
224
|
-
|
|
225
|
-
return (
|
|
226
|
-
<div
|
|
227
|
-
ref={wrapperRef}
|
|
228
|
-
className="absolute inset-0"
|
|
229
|
-
style={isActive ? undefined : { display: "none" }}
|
|
230
|
-
data-tab-pool-id={tabId}
|
|
231
|
-
onMouseDownCapture={() => {
|
|
232
|
-
// Tab content is DOM-reparented out of EditorPanel's fiber subtree, so
|
|
233
|
-
// EditorPanel's onMouseDown never sees clicks on the content body. Set
|
|
234
|
-
// focus here where panelId is known — keeps focusedPanelId correct for
|
|
235
|
-
// every tab type. Dock content is excluded so new tabs open in the grid.
|
|
236
|
-
if (panelId !== DOCK_PANEL_ID) usePanelStore.getState().setFocusedPanel(panelId);
|
|
237
|
-
}}
|
|
238
|
-
>
|
|
239
|
-
<Suspense
|
|
240
|
-
fallback={
|
|
241
|
-
<div className="flex items-center justify-center h-full">
|
|
242
|
-
<Loader2 className="size-6 animate-spin text-primary" />
|
|
243
|
-
</div>
|
|
244
|
-
}
|
|
245
|
-
>
|
|
246
|
-
<Component metadata={metadata} tabId={tabId} />
|
|
247
|
-
</Suspense>
|
|
115
|
+
// Off-screen parking spot. Tab wrappers live here until a layout effect moves them
|
|
116
|
+
// into a panel slot, and come back whenever their panel has no slot mounted.
|
|
117
|
+
<div ref={setHiddenContainer} style={HIDDEN_CONTAINER_STYLE}>
|
|
118
|
+
{hiddenContainer &&
|
|
119
|
+
tabEntries.map((entry) => {
|
|
120
|
+
const Component = TAB_COMPONENTS[entry.type];
|
|
121
|
+
if (!Component) return null;
|
|
122
|
+
return (
|
|
123
|
+
<ReparentingTab
|
|
124
|
+
key={entry.tabId}
|
|
125
|
+
tabId={entry.tabId}
|
|
126
|
+
panelId={entry.panelId}
|
|
127
|
+
component={Component}
|
|
128
|
+
metadata={entry.metadata}
|
|
129
|
+
isActive={entry.isActive}
|
|
130
|
+
hiddenContainer={hiddenContainer}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
133
|
+
})}
|
|
248
134
|
</div>
|
|
249
135
|
);
|
|
250
136
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Open in window" — detaches a tab into a floating window, keeping it live.
|
|
3
|
+
*
|
|
4
|
+
* Desktop only: the window layer renders nothing below the md breakpoint, so on a phone
|
|
5
|
+
* the item would move a tab somewhere the user cannot see (a scaled-down window is never
|
|
6
|
+
* the answer — see the mobile-first UI rules).
|
|
7
|
+
*/
|
|
8
|
+
import { ExternalLink } from "lucide-react";
|
|
9
|
+
import { toast } from "sonner";
|
|
10
|
+
import { ContextMenuItem, ContextMenuSeparator } from "@/components/ui/context-menu";
|
|
11
|
+
import { useIsMobile } from "@/hooks/use-is-mobile";
|
|
12
|
+
import { usePanelStore } from "@/stores/panel-store";
|
|
13
|
+
import type { Tab } from "@/stores/tab-store";
|
|
14
|
+
|
|
15
|
+
interface TabPopOutMenuItemProps {
|
|
16
|
+
tab: Tab;
|
|
17
|
+
/** Panel the tab currently lives in — also where it re-docks when the window closes. */
|
|
18
|
+
panelId: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function TabPopOutMenuItem({ tab, panelId }: TabPopOutMenuItemProps) {
|
|
22
|
+
const isMobile = useIsMobile();
|
|
23
|
+
// The monitor already has a window kind of its own; detaching it would open a second,
|
|
24
|
+
// duplicate presentation of the same data.
|
|
25
|
+
if (isMobile || tab.type === "system-monitor") return null;
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<>
|
|
29
|
+
<ContextMenuItem
|
|
30
|
+
onClick={() => {
|
|
31
|
+
const windowId = usePanelStore.getState().popOutTab(tab.id, panelId);
|
|
32
|
+
// The only rejection a desktop user can hit is the shared window cap.
|
|
33
|
+
if (!windowId) toast.error("Too many windows open — close one first");
|
|
34
|
+
}}
|
|
35
|
+
>
|
|
36
|
+
<ExternalLink className="size-3.5 mr-2" />
|
|
37
|
+
Open in window
|
|
38
|
+
</ContextMenuItem>
|
|
39
|
+
<ContextMenuSeparator />
|
|
40
|
+
</>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot repair of the split between detached tabs and their floating windows.
|
|
3
|
+
*
|
|
4
|
+
* The two halves persist to different keys — window geometry is global and restored by
|
|
5
|
+
* the window layer, panels are restored with the project — so a reload can bring back one
|
|
6
|
+
* without the other. Runs once per project load, after the window layer has restored
|
|
7
|
+
* (otherwise every panel would look orphaned), and unconditionally on mobile, where the
|
|
8
|
+
* window layer renders nothing at all and a workspace synced from a desktop would
|
|
9
|
+
* otherwise hide its detached tabs with no way to reach them.
|
|
10
|
+
*/
|
|
11
|
+
import { useEffect, useRef } from "react";
|
|
12
|
+
import { useIsMobile } from "@/hooks/use-is-mobile";
|
|
13
|
+
import { usePanelStore } from "@/stores/panel-store";
|
|
14
|
+
import { persistWindowPanelChange } from "@/stores/window-panel-actions";
|
|
15
|
+
import { reconcileRunKey, reconcileTabHostWindows } from "@/stores/window-panel-reconcile";
|
|
16
|
+
import { useWindowStore } from "@/components/floating-window/window-store";
|
|
17
|
+
|
|
18
|
+
export function useWindowPanelReconcile(): void {
|
|
19
|
+
const isMobile = useIsMobile();
|
|
20
|
+
const currentProject = usePanelStore((s) => s.currentProject);
|
|
21
|
+
const restored = useWindowStore((s) => s.restored);
|
|
22
|
+
const reconciledFor = useRef<string | null>(null);
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!currentProject) return;
|
|
26
|
+
if (!restored && !isMobile) return;
|
|
27
|
+
const runKey = reconcileRunKey(currentProject, isMobile);
|
|
28
|
+
if (reconciledFor.current === runKey) return;
|
|
29
|
+
reconciledFor.current = runKey;
|
|
30
|
+
|
|
31
|
+
const { panels, grid, focusedPanelId } = usePanelStore.getState();
|
|
32
|
+
// No window layer on mobile ⇒ no window is live ⇒ every detached tab comes home.
|
|
33
|
+
const liveWindowIds = isMobile
|
|
34
|
+
? []
|
|
35
|
+
: Object.values(useWindowStore.getState().windows)
|
|
36
|
+
.filter((w) => w.kind === "tab-host")
|
|
37
|
+
.map((w) => w.id);
|
|
38
|
+
|
|
39
|
+
const result = reconcileTabHostWindows({ panels, grid, focusedPanelId, liveWindowIds });
|
|
40
|
+
if (result.changed) {
|
|
41
|
+
usePanelStore.setState({ panels: result.panels, focusedPanelId: result.focusedPanelId });
|
|
42
|
+
// Both halves: the window-panel blob shrank, and the tabs landed in a grid panel
|
|
43
|
+
// that belongs to the active project's layout.
|
|
44
|
+
persistWindowPanelChange(usePanelStore.getState);
|
|
45
|
+
}
|
|
46
|
+
for (const windowId of result.windowIdsToClose) useWindowStore.getState().close(windowId);
|
|
47
|
+
}, [currentProject, restored, isMobile]);
|
|
48
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Finder-flavoured unified titlebar: traffic lights left (grey when unfocused, hover
|
|
3
|
-
* reveals the glyph), title centred. Height matches the
|
|
4
|
-
* constant (not the real Finder 38px) so a minimised
|
|
5
|
-
* what `FloatingWindow` reserves for it.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
3
|
+
* reveals the glyph), title centred, picture-in-picture at the right end. Height matches the
|
|
4
|
+
* shared `TITLEBAR_HEIGHT` contract constant (not the real Finder 38px) so a minimised
|
|
5
|
+
* window's collapsed height agrees with what `FloatingWindow` reserves for it.
|
|
6
|
+
*
|
|
7
|
+
* Worn by EVERY window kind, not just the explorer: the frame resolves one skin for all of
|
|
8
|
+
* them. Anything below the titlebar (the explorer's own toolbar row, tinted by `skins.css`)
|
|
9
|
+
* belongs to the window body — the chrome slot is only the titlebar itself.
|
|
8
10
|
*
|
|
9
11
|
* `data-skin` is set here (not only on the explorer body) because this titlebar is a
|
|
10
12
|
* sibling of the body in the window tree — the `--x-*` vars it reads only resolve on an
|
|
@@ -14,6 +16,7 @@
|
|
|
14
16
|
import { Minus, Plus, X } from "lucide-react";
|
|
15
17
|
import { cn } from "@/lib/utils";
|
|
16
18
|
import { TITLEBAR_HEIGHT, type WindowChromeProps } from "@/components/floating-window/window-chrome-contract";
|
|
19
|
+
import { PipCaptionButton } from "@/components/floating-window/pip/pip-caption-button";
|
|
17
20
|
|
|
18
21
|
/** The traffic-light colours, plus the unfocused grey — the documented hardcoded hexes. */
|
|
19
22
|
const LIGHTS = [
|
|
@@ -23,7 +26,7 @@ const LIGHTS = [
|
|
|
23
26
|
] as const;
|
|
24
27
|
|
|
25
28
|
export function MacosWindowChrome({
|
|
26
|
-
title, focused, titlebarProps, onMinimize, onToggleMaximize, onClose,
|
|
29
|
+
id, title, focused, titlebarProps, onMinimize, onToggleMaximize, onClose,
|
|
27
30
|
}: WindowChromeProps) {
|
|
28
31
|
const { className, style, ...rest } = titlebarProps;
|
|
29
32
|
const actions = [onClose, onMinimize, onToggleMaximize];
|
|
@@ -56,14 +59,20 @@ export function MacosWindowChrome({
|
|
|
56
59
|
</button>
|
|
57
60
|
))}
|
|
58
61
|
</div>
|
|
62
|
+
{/* A flex child, not an absolutely centred span: the title is boxed between the
|
|
63
|
+
traffic lights and the caption button, so a long title truncates instead of
|
|
64
|
+
painting over either of them. Centre is a few px off true middle — acceptable. */}
|
|
59
65
|
<span
|
|
60
66
|
className={cn(
|
|
61
|
-
"pointer-events-none
|
|
67
|
+
"pointer-events-none flex-1 min-w-0 truncate text-center text-[13px] px-2",
|
|
62
68
|
focused ? "text-text" : "text-text-2",
|
|
63
69
|
)}
|
|
64
70
|
>
|
|
65
71
|
{title}
|
|
66
72
|
</span>
|
|
73
|
+
<div className="flex items-center pr-2">
|
|
74
|
+
<PipCaptionButton id={id} />
|
|
75
|
+
</div>
|
|
67
76
|
</div>
|
|
68
77
|
);
|
|
69
78
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Windows 11 File Explorer-flavoured titlebar:
|
|
3
|
-
*
|
|
4
|
-
* constant (not the real Win11 32px) so a minimised window's
|
|
5
|
-
* what `FloatingWindow` reserves for it.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* Windows 11 File Explorer-flavoured titlebar: title left, caption buttons right (46px wide,
|
|
3
|
+
* close hover red), picture-in-picture left of minimize. Height matches the shared
|
|
4
|
+
* `TITLEBAR_HEIGHT` contract constant (not the real Win11 32px) so a minimised window's
|
|
5
|
+
* collapsed height agrees with what `FloatingWindow` reserves for it.
|
|
6
|
+
*
|
|
7
|
+
* Worn by EVERY window kind, not just the explorer: the frame resolves one skin for all of
|
|
8
|
+
* them. Hence the folder glyph is drawn only for `kind === "explorer"` — it is the File
|
|
9
|
+
* Explorer's app icon, and a system monitor wearing it would be a lie. Anything below the
|
|
10
|
+
* titlebar (the explorer's own toolbar row, tinted by `skins.css`) belongs to the window
|
|
11
|
+
* body — the chrome slot is only the titlebar itself.
|
|
8
12
|
*
|
|
9
13
|
* `data-skin` is set here (not only on the explorer body) because this titlebar is a
|
|
10
14
|
* sibling of the body in the window tree — the `--x-*` vars it reads (`--x-titlebar-bg`,
|
|
@@ -14,6 +18,7 @@
|
|
|
14
18
|
import { Minus, Square, Copy, X } from "lucide-react";
|
|
15
19
|
import { cn } from "@/lib/utils";
|
|
16
20
|
import { TITLEBAR_HEIGHT, type WindowChromeProps } from "@/components/floating-window/window-chrome-contract";
|
|
21
|
+
import { PipCaptionButton } from "@/components/floating-window/pip/pip-caption-button";
|
|
17
22
|
import { WindowsFolderIcon } from "./folder-icon-windows";
|
|
18
23
|
|
|
19
24
|
/** Windows metric: 46px wide caption buttons, full titlebar height. */
|
|
@@ -23,7 +28,7 @@ const CAPTION_BUTTON =
|
|
|
23
28
|
const CLOSE_BUTTON = cn(CAPTION_BUTTON, "can-hover:hover:!bg-[#c42b1c] can-hover:hover:!text-white");
|
|
24
29
|
|
|
25
30
|
export function WindowsWindowChrome({
|
|
26
|
-
title, state, focused, titlebarProps, onMinimize, onToggleMaximize, onClose,
|
|
31
|
+
id, kind, title, state, focused, titlebarProps, onMinimize, onToggleMaximize, onClose,
|
|
27
32
|
}: WindowChromeProps) {
|
|
28
33
|
const { className, style, ...rest } = titlebarProps;
|
|
29
34
|
return (
|
|
@@ -39,9 +44,10 @@ export function WindowsWindowChrome({
|
|
|
39
44
|
)}
|
|
40
45
|
>
|
|
41
46
|
<div className="flex flex-1 min-w-0 items-center gap-2 px-2.5 cursor-default">
|
|
42
|
-
<WindowsFolderIcon className="size-4 shrink-0" />
|
|
47
|
+
{kind === "explorer" && <WindowsFolderIcon className="size-4 shrink-0" />}
|
|
43
48
|
<span className={cn("truncate text-[12px]", focused ? "text-text" : "text-text-2")}>{title}</span>
|
|
44
49
|
</div>
|
|
50
|
+
<PipCaptionButton id={id} className={CAPTION_BUTTON} />
|
|
45
51
|
<button type="button" aria-label="Minimize window" className={CAPTION_BUTTON} onClick={onMinimize}>
|
|
46
52
|
<Minus className="size-3.5" />
|
|
47
53
|
</button>
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type { KillProcessRequest, ProcessInfo } from "../../../types/system-metrics";
|
|
1
|
+
import type { KillProcessRequest, ProcessGroup, ProcessInfo } from "../../../types/system-metrics";
|
|
2
|
+
|
|
3
|
+
/** What the confirm dialog is about to end: one row, or a whole app group. */
|
|
4
|
+
export type KillTarget =
|
|
5
|
+
| { kind: "process"; proc: ProcessInfo }
|
|
6
|
+
| { kind: "group"; group: ProcessGroup; members: ProcessInfo[] };
|
|
2
7
|
|
|
3
8
|
/** Builds the kill request body from a process row's own identity fields — pulled out
|
|
4
9
|
* of the dialog's confirm handler so the payload shape is unit-testable without
|
|
@@ -7,3 +12,25 @@ import type { KillProcessRequest, ProcessInfo } from "../../../types/system-metr
|
|
|
7
12
|
export function buildKillRequest(proc: ProcessInfo, tree: boolean): KillProcessRequest {
|
|
8
13
|
return { pid: proc.pid, startedAt: proc.startedAt, tree };
|
|
9
14
|
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Requests that end every member of a group.
|
|
18
|
+
*
|
|
19
|
+
* An ancestor roll-up ("root:<pid>") is ended with ONE tree kill on its root — the
|
|
20
|
+
* server walks the same descendant set it grouped by, so this is atomic on Windows
|
|
21
|
+
* (`taskkill /T`) and cannot miss a child that forked between snapshot and click.
|
|
22
|
+
* An orphan bucket ("exe:<name>") has no common ancestor, so each member is a
|
|
23
|
+
* separate single-process kill. Protected members are never included: the caller
|
|
24
|
+
* disables the button when any exist, and the server would 403 anyway.
|
|
25
|
+
*/
|
|
26
|
+
export function buildGroupKillRequests(group: ProcessGroup, members: ProcessInfo[]): KillProcessRequest[] {
|
|
27
|
+
const root = group.rootPid !== null ? members.find((m) => m.pid === group.rootPid) : undefined;
|
|
28
|
+
if (root) return [buildKillRequest(root, true)];
|
|
29
|
+
return members.map((m) => buildKillRequest(m, false));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** A group can be ended only when none of its members is refused by the guard —
|
|
33
|
+
* the PPM instance and system groups stay un-endable as a whole. */
|
|
34
|
+
export function isGroupProtected(members: ProcessInfo[]): boolean {
|
|
35
|
+
return members.some((m) => m.protected);
|
|
36
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** Shared scale resolution for the canvas charts: a fixed ceiling (percentage axes)
|
|
2
2
|
* or autoscale to the max of the visible window (byte-rate axes) — pulled out of
|
|
3
|
-
* `
|
|
4
|
-
*
|
|
5
|
-
* full-height
|
|
3
|
+
* `metric-chart-canvas.tsx` so it is unit-testable without a canvas context. A
|
|
4
|
+
* percentage axis must be pinned to 100, otherwise a 3% CPU reading autoscales to a
|
|
5
|
+
* full-height line. */
|
|
6
6
|
export function resolveScaleMax(data: number[], maxValue?: number): number {
|
|
7
7
|
if (maxValue !== undefined) return maxValue;
|
|
8
8
|
return Math.max(...data, 1);
|
|
@@ -5,44 +5,60 @@ import { Button } from "@/components/ui/button";
|
|
|
5
5
|
import { Switch } from "@/components/ui/switch";
|
|
6
6
|
import { useIsMobile } from "@/hooks/use-is-mobile";
|
|
7
7
|
import { formatRam } from "@/lib/format-bytes";
|
|
8
|
-
import type {
|
|
8
|
+
import type { KillTarget } from "./build-kill-request";
|
|
9
9
|
|
|
10
10
|
export interface KillConfirmDialogProps {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
target: KillTarget | null;
|
|
12
|
+
/** `tree` is only meaningful for a single process; a group is always ended whole. */
|
|
13
|
+
onConfirm: (target: KillTarget, tree: boolean) => void;
|
|
13
14
|
onCancel: () => void;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
/** Confirm dialog for ending a process. Bottom sheet below
|
|
17
|
-
* `md`+. The "end child processes" toggle defaults off and
|
|
18
|
-
* never the default focus — Escape/backdrop cancels either
|
|
19
|
-
|
|
17
|
+
/** Confirm dialog for ending a process or a whole app group. Bottom sheet below
|
|
18
|
+
* `md`, centered dialog at `md`+. The "end child processes" toggle defaults off and
|
|
19
|
+
* the destructive action is never the default focus — Escape/backdrop cancels either
|
|
20
|
+
* way. */
|
|
21
|
+
export function KillConfirmDialog({ target, onConfirm, onCancel }: KillConfirmDialogProps) {
|
|
20
22
|
const isMobile = useIsMobile();
|
|
21
23
|
const [tree, setTree] = useState(false);
|
|
22
24
|
|
|
23
25
|
useEffect(() => {
|
|
24
|
-
if (!
|
|
25
|
-
}, [
|
|
26
|
+
if (!target) setTree(false);
|
|
27
|
+
}, [target]);
|
|
26
28
|
|
|
27
|
-
if (!
|
|
29
|
+
if (!target) return null;
|
|
30
|
+
|
|
31
|
+
const isGroup = target.kind === "group";
|
|
32
|
+
const title = isGroup ? "End app" : "End process";
|
|
33
|
+
const cpu = isGroup ? target.group.cpu : target.proc.cpu;
|
|
34
|
+
const ramMB = isGroup ? target.group.ramMB : target.proc.ramMB;
|
|
28
35
|
|
|
29
36
|
const body = (
|
|
30
|
-
<div className="space-y-4" data-testid="sysmon-kill-confirm">
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
<div className="space-y-4" data-testid="sysmon-kill-confirm" data-kill-kind={target.kind}>
|
|
38
|
+
{isGroup ? (
|
|
39
|
+
<p className="text-sm">
|
|
40
|
+
End <span className="font-medium">{target.group.label}</span> and all its{" "}
|
|
41
|
+
<span className="font-medium">{target.members.length}</span> processes?
|
|
42
|
+
</p>
|
|
43
|
+
) : (
|
|
44
|
+
<p className="text-sm">
|
|
45
|
+
End <span className="font-medium">{target.proc.name}</span> (pid {target.proc.pid})?
|
|
46
|
+
</p>
|
|
47
|
+
)}
|
|
34
48
|
<p className="text-xs text-text-subtle">
|
|
35
|
-
CPU {
|
|
49
|
+
CPU {cpu.toFixed(1)}% · RAM {formatRam(ramMB)}
|
|
36
50
|
</p>
|
|
37
|
-
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
{!isGroup && (
|
|
52
|
+
<label className="flex items-center justify-between gap-3 min-h-11 py-1">
|
|
53
|
+
<span className="text-sm">Also end child processes</span>
|
|
54
|
+
<Switch
|
|
55
|
+
checked={tree}
|
|
56
|
+
onCheckedChange={setTree}
|
|
57
|
+
data-testid="sysmon-kill-tree"
|
|
58
|
+
aria-label="Also end child processes"
|
|
59
|
+
/>
|
|
60
|
+
</label>
|
|
61
|
+
)}
|
|
46
62
|
<div className="flex flex-col-reverse md:flex-row gap-2 md:justify-end pt-2">
|
|
47
63
|
<Button
|
|
48
64
|
variant="outline"
|
|
@@ -55,11 +71,11 @@ export function KillConfirmDialog({ process, onConfirm, onCancel }: KillConfirmD
|
|
|
55
71
|
<Button
|
|
56
72
|
variant="destructive"
|
|
57
73
|
autoFocus={false}
|
|
58
|
-
onClick={() => onConfirm(
|
|
74
|
+
onClick={() => onConfirm(target, tree)}
|
|
59
75
|
data-testid="sysmon-kill-confirm-ok"
|
|
60
76
|
className="min-h-11"
|
|
61
77
|
>
|
|
62
|
-
End process
|
|
78
|
+
{isGroup ? `End ${target.members.length} processes` : "End process"}
|
|
63
79
|
</Button>
|
|
64
80
|
</div>
|
|
65
81
|
</div>
|
|
@@ -69,7 +85,7 @@ export function KillConfirmDialog({ process, onConfirm, onCancel }: KillConfirmD
|
|
|
69
85
|
return (
|
|
70
86
|
<BottomSheet open onClose={onCancel}>
|
|
71
87
|
<div className="px-4 pb-4">
|
|
72
|
-
<h2 className="text-base font-semibold mb-3">
|
|
88
|
+
<h2 className="text-base font-semibold mb-3">{title}</h2>
|
|
73
89
|
{body}
|
|
74
90
|
</div>
|
|
75
91
|
</BottomSheet>
|
|
@@ -80,7 +96,7 @@ export function KillConfirmDialog({ process, onConfirm, onCancel }: KillConfirmD
|
|
|
80
96
|
<Dialog open onOpenChange={(open) => !open && onCancel()}>
|
|
81
97
|
<DialogContent>
|
|
82
98
|
<DialogHeader>
|
|
83
|
-
<DialogTitle>
|
|
99
|
+
<DialogTitle>{title}</DialogTitle>
|
|
84
100
|
</DialogHeader>
|
|
85
101
|
{body}
|
|
86
102
|
</DialogContent>
|
|
@@ -20,8 +20,7 @@ interface MetricChartCanvasProps {
|
|
|
20
20
|
* width of its parent — the cards live in a resizable floating window, so a fixed
|
|
21
21
|
* pixel width overflows the card as soon as the window is narrower than designed.
|
|
22
22
|
* No redraw throttle — one draw per prop change, which at a 2s tick cadence is
|
|
23
|
-
* nowhere near a frame budget.
|
|
24
|
-
* used by process rows. */
|
|
23
|
+
* nowhere near a frame budget. */
|
|
25
24
|
export const MetricChartCanvas = memo(function MetricChartCanvas({
|
|
26
25
|
series,
|
|
27
26
|
height,
|