@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.
Files changed (543) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +81 -23
  3. package/assets/skills/ppm/SKILL.md +1 -1
  4. package/assets/skills/ppm/references/http-api.md +1 -1
  5. package/dist/web/assets/adaptive-context-menu-DGCKKeTy.js +1 -0
  6. package/dist/web/assets/ai-resource-editor-BOHHTTe7.js +1 -0
  7. package/dist/web/assets/ai-settings-section-BigC_nZR.js +1 -0
  8. package/dist/web/assets/{angular-html-Ctz0zN01.js → angular-html-BYPaydvh.js} +1 -1
  9. package/dist/web/assets/{angular-ts-QXHpgB1C.js → angular-ts-Bb4AMKlk.js} +1 -1
  10. package/dist/web/assets/api-client-DTZEgjBQ.js +1 -0
  11. package/dist/web/assets/{api-settings-kQHV6pYZ.js → api-settings-Bd3M4YpI.js} +1 -1
  12. package/dist/web/assets/api-settings-kd1j4iR8.js +1 -0
  13. package/dist/web/assets/{api-themes-CrK0tkW_.js → api-themes-Cpx419SL.js} +1 -1
  14. package/dist/web/assets/{apl-b9KVk-O4.js → apl-DB2VjFCS.js} +1 -1
  15. package/dist/web/assets/architecture-PBZL5I3N-8dCMT9r7.js +1 -0
  16. package/dist/web/assets/{astro-BlFEeGYr.js → astro-BeoJdVpk.js} +1 -1
  17. package/dist/web/assets/{audio-preview-CZLmhf__.js → audio-preview-BgFuTn-0.js} +1 -1
  18. package/dist/web/assets/{blade-CGkj2MUI.js → blade-Cf2q1sPf.js} +1 -1
  19. package/dist/web/assets/{bsl-CVsbb6ap.js → bsl-W1kOaNpu.js} +1 -1
  20. package/dist/web/assets/{button-BA_fJOtX.js → button-5zTrkEoN.js} +1 -1
  21. package/dist/web/assets/{cairo-BbIHl2iE.js → cairo-BoAZFcje.js} +1 -1
  22. package/dist/web/assets/chat-tab-E3bf_V8X.js +15 -0
  23. package/dist/web/assets/chevron-down-Dp0rpHb8.js +1 -0
  24. package/dist/web/assets/clipboard-7fw0Shic.js +1 -0
  25. package/dist/web/assets/{cobol-BWSGjmWb.js → cobol-B0Nm7RXj.js} +1 -1
  26. package/dist/web/assets/code-editor-BUlM2gXk.js +10 -0
  27. package/dist/web/assets/{coffee-CWGNOxds.js → coffee-BakMn3on.js} +1 -1
  28. package/dist/web/assets/{conflict-editor-fRTU3f1o.js → conflict-editor-BUs5k9q_.js} +4 -4
  29. package/dist/web/assets/context-menu-Bq92km4s.js +1 -0
  30. package/dist/web/assets/{cpp-DHGV24J2.js → cpp-BRAJQHK2.js} +1 -1
  31. package/dist/web/assets/{crystal-Vlwf2UMP.js → crystal-kqqO3zkK.js} +1 -1
  32. package/dist/web/assets/{csv-preview-D1d0cxOJ.js → csv-preview-ByoDgLAZ.js} +1 -1
  33. package/dist/web/assets/{data-grid-overlay-editor-D9il5DZS.js → data-grid-overlay-editor-Brkf9z41.js} +1 -1
  34. package/dist/web/assets/database-viewer-Btc3h8Yu.js +1 -0
  35. package/dist/web/assets/dialog-DwtGlowE.js +1 -0
  36. package/dist/web/assets/diff-viewer-CZaDnR4w.js +4 -0
  37. package/dist/web/assets/docx-preview-DAD_vg59.js +12 -0
  38. package/dist/web/assets/{edge-Bhqk64zS.js → edge-Cq1ZKZuE.js} +1 -1
  39. package/dist/web/assets/{edit-diff-preview-gq6ALf2B.js → edit-diff-preview-B_VE7ppQ.js} +1 -1
  40. package/dist/web/assets/{elixir-D466WCFm.js → elixir-BM_JoJRk.js} +1 -1
  41. package/dist/web/assets/{elm-Bfs2qNPR.js → elm-Dw7oO08Y.js} +1 -1
  42. package/dist/web/assets/{erb-WI7jUaB6.js → erb-CfKOGAfk.js} +1 -1
  43. package/dist/web/assets/{erlang-BCBe8nCc.js → erlang-DlDmGVeE.js} +1 -1
  44. package/dist/web/assets/{esm-CZs9WVDO.js → esm-DGAP0GFh.js} +1 -1
  45. package/dist/web/assets/explorer-body-9aBmyVpZ.js +2 -0
  46. package/dist/web/assets/explorer-window-content-DRtqoSPA.js +1 -0
  47. package/dist/web/assets/extension-store-Cpfh2vMm.js +1 -0
  48. package/dist/web/assets/{extension-webview-BH_mWYMe.js → extension-webview-B2OnjuCu.js} +2 -2
  49. package/dist/web/assets/external-link-B8BynhvY.js +1 -0
  50. package/dist/web/assets/file-store-aOERIEo-.js +1 -0
  51. package/dist/web/assets/folder-symlink-B8XrtvQK.js +1 -0
  52. package/dist/web/assets/{fortran-fixed-form-CXLIv8Ox.js → fortran-fixed-form-XnAhQWxS.js} +1 -1
  53. package/dist/web/assets/{fsharp-CZsYmiw9.js → fsharp-CdNvy0PG.js} +1 -1
  54. package/dist/web/assets/{gdresource-BGRvoWfC.js → gdresource-DxuG5i8i.js} +1 -1
  55. package/dist/web/assets/{git-commit-DH6mY3Km.js → git-commit-3lMonsur.js} +1 -1
  56. package/dist/web/assets/git-log-panel-Co0PBPHC.js +1 -0
  57. package/dist/web/assets/{git-rebase-C5Gql6Ma.js → git-rebase-N8Z9kIMf.js} +1 -1
  58. package/dist/web/assets/gitGraph-HDMCJU4V-2e_8dfbs.js +1 -0
  59. package/dist/web/assets/{glide-data-grid-n4ox_uev.js → glide-data-grid-C4_zIneN.js} +8 -8
  60. package/dist/web/assets/{glimmer-js-1-6JMJlj.js → glimmer-js-Dp9OXiib.js} +1 -1
  61. package/dist/web/assets/{glimmer-ts-C_Njj0nK.js → glimmer-ts-CDVKBcDj.js} +1 -1
  62. package/dist/web/assets/{glsl-DbkxE1TN.js → glsl-DPJxI4us.js} +1 -1
  63. package/dist/web/assets/{graphql-BK75fiXl.js → graphql-BrFhaQQl.js} +1 -1
  64. package/dist/web/assets/group-chat-tab-rOd8J8GC.js +1 -0
  65. package/dist/web/assets/{hack-DG151vit.js → hack-BzXbDMlA.js} +1 -1
  66. package/dist/web/assets/{haml-DKeIPQWM.js → haml-CPpkX0s5.js} +1 -1
  67. package/dist/web/assets/{handlebars-398uCI13.js → handlebars-BqrApy52.js} +1 -1
  68. package/dist/web/assets/{html-NLWdst5q.js → html-DmjUl-OA.js} +1 -1
  69. package/dist/web/assets/{html-derivative-CJf_Le2z.js → html-derivative-Cnd6XFR5.js} +1 -1
  70. package/dist/web/assets/{http-G1K2FozA.js → http-DMLWYun2.js} +1 -1
  71. package/dist/web/assets/{hurl-WDC6sSBz.js → hurl-CKkCVxbj.js} +1 -1
  72. package/dist/web/assets/{hxml-Dc3jBXuf.js → hxml-CAx19TtQ.js} +1 -1
  73. package/dist/web/assets/image-preview-DHUoylQ1.js +1 -0
  74. package/dist/web/assets/index-BImUaigO.js +52 -0
  75. package/dist/web/assets/index-CSfi6DSU.css +2 -0
  76. package/dist/web/assets/info-3K5VOQVL-BZi1Gha1.js +1 -0
  77. package/dist/web/assets/input-DcEk7mA3.js +1 -0
  78. package/dist/web/assets/{jinja-CWsQj2y0.js → jinja-BmB9YN9l.js} +1 -1
  79. package/dist/web/assets/{jison-CciJg2NW.js → jison-BaVsKKpw.js} +1 -1
  80. package/dist/web/assets/{julia-IOQNJAB7.js → julia-BgVBLveX.js} +1 -1
  81. package/dist/web/assets/{just-BGdHchwS.js → just-C2ENIbl9.js} +1 -1
  82. package/dist/web/assets/keybindings-store-BGIyqXHI.js +1 -0
  83. package/dist/web/assets/keybindings-store-CzV2sPls.js +1 -0
  84. package/dist/web/assets/{latex-D6TOl-L2.js → latex-BiDIWxKL.js} +1 -1
  85. package/dist/web/assets/{liquid-CVSvu_Wn.js → liquid-NxpapreE.js} +1 -1
  86. package/dist/web/assets/loader-circle-gSPVxfvH.js +1 -0
  87. package/dist/web/assets/lock-Did-87UV.js +1 -0
  88. package/dist/web/assets/{lua-CcKiU6HW.js → lua-DVepQvwH.js} +1 -1
  89. package/dist/web/assets/markdown-renderer-CcbR33VG.js +1 -0
  90. package/dist/web/assets/{markdown-renderer-B317vEys.js → markdown-renderer-DlcDhgrF.js} +3 -3
  91. package/dist/web/assets/{marko--UOicMGo.js → marko-CJ2606Xl.js} +1 -1
  92. package/dist/web/assets/{mdc-D690aU2C.js → mdc-D2bjqclE.js} +1 -1
  93. package/dist/web/assets/{media-url-CylYQld1.js → media-url-H17XJF-I.js} +1 -1
  94. package/dist/web/assets/mobile-bottom-sheet-g-r2hCFa.js +1 -0
  95. package/dist/web/assets/mobile-explorer-sheet-SIwQXlwA.js +1 -0
  96. package/dist/web/assets/monitor-Dv8vn_6O.js +1 -0
  97. package/dist/web/assets/{nextflow-DR8PhpF8.js → nextflow-BtJwUbfF.js} +1 -1
  98. package/dist/web/assets/{nginx-Qb9pUk1g.js → nginx-j4gyIhHE.js} +1 -1
  99. package/dist/web/assets/{nim-DLa8R3NS.js → nim-ClH_gjP5.js} +1 -1
  100. package/dist/web/assets/notification-store-DV5QtUTg.js +1 -0
  101. package/dist/web/assets/{number-overlay-editor-D9SkFg1Y.js → number-overlay-editor-C1EqJnWq.js} +1 -1
  102. package/dist/web/assets/{overview-panel-BxDohIEa.js → overview-panel-vTeeJYVZ.js} +1 -1
  103. package/dist/web/assets/packet-RMMSAZCW-o5htEcin.js +1 -0
  104. package/dist/web/assets/panel-store-BSnkjgHt.js +1 -0
  105. package/dist/web/assets/pdf-preview-CqFGRY0Z.js +1 -0
  106. package/dist/web/assets/pencil-BlIIg6RH.js +1 -0
  107. package/dist/web/assets/{perl-AMNGIneF.js → perl-C9H7X7CT.js} +1 -1
  108. package/dist/web/assets/{php-CDsOOxXn.js → php-Bx2U-cQ_.js} +1 -1
  109. package/dist/web/assets/pie-UPGHQEXC-BXAIFSAD.js +1 -0
  110. package/dist/web/assets/play-4MZi1Axp.js +1 -0
  111. package/dist/web/assets/portal-container-context-Cm5HipFr.js +1 -0
  112. package/dist/web/assets/{postgres-viewer-BWZLW7kI.js → postgres-viewer-DHwcQucn.js} +3 -3
  113. package/dist/web/assets/process-table-BGRJNlpn.js +1 -0
  114. package/dist/web/assets/{project-store-B8BkHXy5.js → project-store--nvQiy75.js} +1 -1
  115. package/dist/web/assets/{pug-C2kdkhQ6.js → pug-Cw74sKsE.js} +1 -1
  116. package/dist/web/assets/{qml-DRDkUp75.js → qml-BXD94Eqz.js} +1 -1
  117. package/dist/web/assets/radar-KQ55EAFF-Dbt2Aebl.js +1 -0
  118. package/dist/web/assets/{razor-wY_6wUeC.js → razor-DZ0-Ge0S.js} +1 -1
  119. package/dist/web/assets/refresh-cw-B06yaBrW.js +1 -0
  120. package/dist/web/assets/rotate-ccw-COXu_9oj.js +1 -0
  121. package/dist/web/assets/{rst-BRpofyNs.js → rst-Dtdh0QUj.js} +1 -1
  122. package/dist/web/assets/{ruby-ieATBhWm.js → ruby-BC51BW2Q.js} +1 -1
  123. package/dist/web/assets/{run-in-terminal-CyS5Itj-.js → run-in-terminal-Sd3KyjN4.js} +1 -1
  124. package/dist/web/assets/{sas-CoOOEbOO.js → sas-BN8i4qOU.js} +1 -1
  125. package/dist/web/assets/scroll-area-0gljZ6lF.js +1 -0
  126. package/dist/web/assets/{scss-_nWV0bsb.js → scss-H-QtA7Rz.js} +1 -1
  127. package/dist/web/assets/send-BlyNJAzy.js +1 -0
  128. package/dist/web/assets/{send-to-chat-BcO39BDR.js → send-to-chat-u6m8l-rH.js} +1 -1
  129. package/dist/web/assets/{settings-store-C20lqh0G.js → settings-store-CHY6Kzin.js} +2 -2
  130. package/dist/web/assets/settings-tab-Dic6TKkU.js +1 -0
  131. package/dist/web/assets/settings-tab-IY6K1MiZ.js +3 -0
  132. package/dist/web/assets/{shaderlab-XkqfIfO8.js → shaderlab-CalNsj_x.js} +1 -1
  133. package/dist/web/assets/shallow-DYo6goJ4.js +1 -0
  134. package/dist/web/assets/{shellsession-BKBIqTlM.js → shellsession-BFrcoR8x.js} +1 -1
  135. package/dist/web/assets/{soy-oVDnPzzh.js → soy-CNbku7vP.js} +1 -1
  136. package/dist/web/assets/{sparql-N2VclEsF.js → sparql-BN_orcVp.js} +1 -1
  137. package/dist/web/assets/{sql-query-editor-BwPjEaP9.js → sql-query-editor-C6pC3I8l.js} +1 -1
  138. package/dist/web/assets/sqlite-viewer-DTr5PzUb.js +1 -0
  139. package/dist/web/assets/{stata-BuuClVDg.js → stata-C6a5Ijzq.js} +1 -1
  140. package/dist/web/assets/{surrealql-DE5_63MS.js → surrealql-ClplI_HY.js} +1 -1
  141. package/dist/web/assets/{svelte--YWjlOrK.js → svelte-DNm-UNXB.js} +1 -1
  142. package/dist/web/assets/switch-DKvKya9y.js +1 -0
  143. package/dist/web/assets/system-monitor-body-iwGiCns9.js +2 -0
  144. package/dist/web/assets/system-monitor-tab-DdXQhEel.js +1 -0
  145. package/dist/web/assets/system-monitor-window-content-BUqRsPK2.js +1 -0
  146. package/dist/web/assets/tab-host-window-content-BnqGPu8a.js +1 -0
  147. package/dist/web/assets/{tab-store-DAsvpx4t.js → tab-store-CJuJRapl.js} +1 -1
  148. package/dist/web/assets/team-member-sheet-LkAFSCvb.js +2 -0
  149. package/dist/web/assets/team-member-window-content-T4Q5JI-G.js +1 -0
  150. package/dist/web/assets/{templ-MlpvJx4a.js → templ-CSdqVobu.js} +1 -1
  151. package/dist/web/assets/terminal-tab-Bb2rZegQ.js +3 -0
  152. package/dist/web/assets/{tex-0loAoXJG.js → tex-DzSJ4kcZ.js} +1 -1
  153. package/dist/web/assets/text-wrap-CBT4Gxtg.js +1 -0
  154. package/dist/web/assets/tool-cards-lhqhrDTT.js +8 -0
  155. package/dist/web/assets/trash-2-Bk4yYlck.js +1 -0
  156. package/dist/web/assets/treemap-KZPCXAKY-DUbnl9dz.js +1 -0
  157. package/dist/web/assets/triangle-alert-B8EYecpe.js +1 -0
  158. package/dist/web/assets/{ts-tags-pt-Ug0hK.js → ts-tags-C28w3bTg.js} +1 -1
  159. package/dist/web/assets/{twig-DOePpLOL.js → twig-i5jY3QXB.js} +1 -1
  160. package/dist/web/assets/upload-BNlX8D07.js +1 -0
  161. package/dist/web/assets/{use-blob-url-BKyVxOZw.js → use-blob-url-Dsq9OjTh.js} +1 -1
  162. package/dist/web/assets/{use-monaco-theme-DSCdlrjO.js → use-monaco-theme-BZvlsoBv.js} +1 -1
  163. package/dist/web/assets/use-open-team-member-DkiEjFYE.js +1 -0
  164. package/dist/web/assets/{use-websocket-iJfc7EbK.js → use-websocket-B8R50f7f.js} +1 -1
  165. package/dist/web/assets/{vendor-mermaid-DrwG0NYt.js → vendor-mermaid-By4AVvJY.js} +1 -1
  166. package/dist/web/assets/video-preview-m0-3p7QZ.js +1 -0
  167. package/dist/web/assets/{vue-D6f-rprj.js → vue-Ceyet_lv.js} +1 -1
  168. package/dist/web/assets/{vue-html-DEYRkS1V.js → vue-html-GuU7g_hg.js} +1 -1
  169. package/dist/web/assets/{vue-vine-CxSG2ojf.js → vue-vine-CxXoaJr2.js} +1 -1
  170. package/dist/web/assets/window-store-CsEW6jiE.js +1 -0
  171. package/dist/web/assets/{xml-DhrxbATj.js → xml-CbqOVhkP.js} +1 -1
  172. package/dist/web/assets/{xsl-CU0ZndUO.js → xsl-KfAmCauy.js} +1 -1
  173. package/dist/web/index.html +56 -27
  174. package/dist/web/sw.js +1 -1
  175. package/docs/code-standards.md +8 -0
  176. package/docs/codebase-summary.md +19 -5
  177. package/docs/design-guidelines.md +13 -2
  178. package/docs/project-roadmap.md +9 -0
  179. package/docs/system-architecture.md +83 -6
  180. package/package.json +1 -1
  181. package/src/web/components/chat/file-picker.tsx +5 -2
  182. package/src/web/components/chat/mode-selector.tsx +5 -2
  183. package/src/web/components/chat/model-selector.tsx +5 -2
  184. package/src/web/components/chat/model-thinking-selector.tsx +5 -2
  185. package/src/web/components/chat/provider-selector.tsx +5 -2
  186. package/src/web/components/chat/slash-command-picker.tsx +5 -2
  187. package/src/web/components/editor/code-editor.tsx +13 -3
  188. package/src/web/components/editor/conflict-editor.tsx +9 -0
  189. package/src/web/components/editor/diff-viewer.tsx +9 -0
  190. package/src/web/components/floating-window/floating-window.tsx +23 -15
  191. package/src/web/components/floating-window/pip/pip-caption-button.tsx +108 -0
  192. package/src/web/components/floating-window/pip/pip-focus-target.ts +58 -0
  193. package/src/web/components/floating-window/pip/pip-geometry.ts +46 -0
  194. package/src/web/components/floating-window/pip/pip-host.ts +156 -0
  195. package/src/web/components/floating-window/pip/pip-key-forward.ts +59 -0
  196. package/src/web/components/floating-window/pip/pip-resize-signal.ts +33 -0
  197. package/src/web/components/floating-window/pip/pip-style-copy.ts +108 -0
  198. package/src/web/components/floating-window/pip/pip-support.ts +33 -0
  199. package/src/web/components/floating-window/tab-host-window-content.tsx +80 -0
  200. package/src/web/components/floating-window/use-window-body-element.ts +67 -0
  201. package/src/web/components/floating-window/use-window-drag.ts +5 -0
  202. package/src/web/components/floating-window/use-window-gesture-context.ts +14 -0
  203. package/src/web/components/floating-window/use-window-resize.ts +5 -0
  204. package/src/web/components/floating-window/window-content-registry.ts +4 -16
  205. package/src/web/components/floating-window/window-layer.tsx +1 -2
  206. package/src/web/components/floating-window/window-persistence.ts +9 -2
  207. package/src/web/components/floating-window/window-pip-placeholder.tsx +31 -0
  208. package/src/web/components/floating-window/window-pip-registry.ts +69 -0
  209. package/src/web/components/floating-window/window-skin-chrome.tsx +21 -0
  210. package/src/web/components/floating-window/window-store-types.ts +8 -2
  211. package/src/web/components/layout/reparenting-tab.tsx +136 -0
  212. package/src/web/components/layout/tab-bar.tsx +2 -0
  213. package/src/web/components/layout/tab-pool-collect.ts +38 -2
  214. package/src/web/components/layout/tab-pool-registry.ts +48 -0
  215. package/src/web/components/layout/tab-pool.tsx +54 -168
  216. package/src/web/components/layout/tab-pop-out-menu-item.tsx +42 -0
  217. package/src/web/components/layout/use-window-panel-reconcile.ts +48 -0
  218. package/src/web/components/os-explorer/skins/macos-window-chrome.tsx +16 -7
  219. package/src/web/components/os-explorer/skins/windows-window-chrome.tsx +14 -8
  220. package/src/web/components/ui/context-menu.tsx +10 -3
  221. package/src/web/components/ui/dialog.tsx +10 -1
  222. package/src/web/components/ui/dropdown-menu.tsx +10 -3
  223. package/src/web/components/ui/mobile-bottom-sheet.tsx +7 -4
  224. package/src/web/components/ui/portal-container-context.tsx +40 -0
  225. package/src/web/components/ui/select.tsx +3 -1
  226. package/src/web/components/ui/tooltip.tsx +3 -1
  227. package/src/web/hooks/use-terminal.ts +24 -3
  228. package/src/web/stores/panel-store.ts +72 -7
  229. package/src/web/stores/panel-utils.ts +36 -0
  230. package/src/web/stores/window-panel-actions.ts +211 -0
  231. package/src/web/stores/window-panel-persistence.ts +115 -0
  232. package/src/web/stores/window-panel-reconcile.ts +97 -0
  233. package/.spike/group-protected-probe.ts +0 -21
  234. package/.spike/s.err +0 -63
  235. package/.spike/tunnel.err +0 -22
  236. package/.spike/w.err +0 -28
  237. package/dist/web/assets/ai-resource-editor-mdDKG-rw.js +0 -1
  238. package/dist/web/assets/api-client-CzABTreM.js +0 -1
  239. package/dist/web/assets/api-settings-nblja3Rk.js +0 -1
  240. package/dist/web/assets/architecture-PBZL5I3N-C7ra20CE.js +0 -1
  241. package/dist/web/assets/chat-tab-C060A94y.js +0 -15
  242. package/dist/web/assets/code-editor-WELegzdp.js +0 -10
  243. package/dist/web/assets/context-menu-Cq0u3SK9.js +0 -1
  244. package/dist/web/assets/database-viewer-DevnWTV4.js +0 -1
  245. package/dist/web/assets/diff-viewer-DGxVg1pD.js +0 -4
  246. package/dist/web/assets/docx-preview-Cx-zLwAw.js +0 -12
  247. package/dist/web/assets/explorer-body-j_4hVc34.js +0 -2
  248. package/dist/web/assets/explorer-window-content-DdrGwk3w.js +0 -1
  249. package/dist/web/assets/git-log-panel-CfpXRJcP.js +0 -1
  250. package/dist/web/assets/gitGraph-HDMCJU4V-D4hYLNJU.js +0 -1
  251. package/dist/web/assets/group-chat-tab-dYuuknLN.js +0 -1
  252. package/dist/web/assets/image-preview-Ss38ex8g.js +0 -1
  253. package/dist/web/assets/index-BiTiXgBZ.css +0 -2
  254. package/dist/web/assets/index-Ch8l9de-.js +0 -52
  255. package/dist/web/assets/info-3K5VOQVL-lRlrTlkb.js +0 -1
  256. package/dist/web/assets/keybindings-store-CDfTjwZX.js +0 -1
  257. package/dist/web/assets/markdown-renderer-CpRlpLHw.js +0 -1
  258. package/dist/web/assets/mobile-bottom-sheet-BUOJgiaZ.js +0 -1
  259. package/dist/web/assets/mobile-explorer-sheet-D1Bv9UCT.js +0 -1
  260. package/dist/web/assets/notification-store-KwTAZT8b.js +0 -1
  261. package/dist/web/assets/packet-RMMSAZCW-BIhk1mvp.js +0 -1
  262. package/dist/web/assets/panel-store-DCD82zc1.js +0 -1
  263. package/dist/web/assets/pdf-preview-dwRe54ht.js +0 -1
  264. package/dist/web/assets/pie-UPGHQEXC-SLS6i76l.js +0 -1
  265. package/dist/web/assets/process-table-CI-fnVsy.js +0 -1
  266. package/dist/web/assets/radar-KQ55EAFF-JJ6O1Er_.js +0 -1
  267. package/dist/web/assets/settings-tab-mPxrKkfm.js +0 -1
  268. package/dist/web/assets/sqlite-viewer-Cs-_D942.js +0 -1
  269. package/dist/web/assets/system-monitor-body-CV7-0hZG.js +0 -2
  270. package/dist/web/assets/system-monitor-tab-Ce-8Axhh.js +0 -1
  271. package/dist/web/assets/system-monitor-window-content-CetwYOQy.js +0 -1
  272. package/dist/web/assets/team-member-sheet-CjgaQjsZ.js +0 -2
  273. package/dist/web/assets/team-member-window-content-DNJiYWS7.js +0 -1
  274. package/dist/web/assets/terminal-tab-DF7521sT.js +0 -3
  275. package/dist/web/assets/tool-cards-DCAXGDJI.js +0 -8
  276. package/dist/web/assets/treemap-KZPCXAKY-Be3KNmns.js +0 -1
  277. package/dist/web/assets/use-open-team-member-H4k74HnV.js +0 -1
  278. package/dist/web/assets/video-preview-B0ZWpX0F.js +0 -1
  279. package/src/web/components/floating-window/default-window-chrome.tsx +0 -71
  280. package/src/web/components/os-explorer/skins/explorer-skin-chrome.tsx +0 -17
  281. /package/dist/web/assets/{abap-MRbmsXOs.js → abap-C6nB04tn.js} +0 -0
  282. /package/dist/web/assets/{actionscript-3-BDDHKqa4.js → actionscript-3-Vx4rw2sC.js} +0 -0
  283. /package/dist/web/assets/{ada-DpuV9KwV.js → ada-Ccd8vM20.js} +0 -0
  284. /package/dist/web/assets/{andromeeda-D6qUCKJo.js → andromeeda-DnBX5xMg.js} +0 -0
  285. /package/dist/web/assets/{apache-CX1NU_Tl.js → apache-B-9_sx0g.js} +0 -0
  286. /package/dist/web/assets/{apex-B4-aoQ3K.js → apex-_wPVBYoL.js} +0 -0
  287. /package/dist/web/assets/{api-client-BSB14J4w.js → api-client-aQb5hHE5.js} +0 -0
  288. /package/dist/web/assets/{applescript-Dm9NI6KR.js → applescript-CcvD-qr0.js} +0 -0
  289. /package/dist/web/assets/{apply-theme-BH_d4amk.js → apply-theme-BeLRfsSu.js} +0 -0
  290. /package/dist/web/assets/{ara-BGN8GAYn.js → ara-C40Ztoms.js} +0 -0
  291. /package/dist/web/assets/{asciidoc-s_yVuR3t.js → asciidoc-CybYkJV4.js} +0 -0
  292. /package/dist/web/assets/{asm-BzQdSvTe.js → asm-9eOKwzR0.js} +0 -0
  293. /package/dist/web/assets/{aurora-x-BJTLETG_.js → aurora-x-B5ZH4t7t.js} +0 -0
  294. /package/dist/web/assets/{awk-BQEGWxvX.js → awk-Dqilob-2.js} +0 -0
  295. /package/dist/web/assets/{ayu-dark-CpTORmLc.js → ayu-dark-CPgRhf5r.js} +0 -0
  296. /package/dist/web/assets/{ayu-light-D8PVj-e6.js → ayu-light-Do06Q52f.js} +0 -0
  297. /package/dist/web/assets/{ayu-mirage-DyElQHtm.js → ayu-mirage-_BhxcrxY.js} +0 -0
  298. /package/dist/web/assets/{ballerina-C82NkRtj.js → ballerina-DDwK54QW.js} +0 -0
  299. /package/dist/web/assets/{bat-0X7DtGI-.js → bat-BGyGlzGk.js} +0 -0
  300. /package/dist/web/assets/{beancount-Xgvy6YRl.js → beancount-CRWBdapI.js} +0 -0
  301. /package/dist/web/assets/{berry-CCT2pZcQ.js → berry-DbSFn2gO.js} +0 -0
  302. /package/dist/web/assets/{bibtex-CpXgZ9M_.js → bibtex-QpsV9gm9.js} +0 -0
  303. /package/dist/web/assets/{bicep-fkeSA62l.js → bicep-CxS8CUve.js} +0 -0
  304. /package/dist/web/assets/{bird2-Co7SeAI8.js → bird2-CuZhQzYR.js} +0 -0
  305. /package/dist/web/assets/{bot-CunPuEdW.js → bot-D6sx11y0.js} +0 -0
  306. /package/dist/web/assets/{c-BpmrTvJh.js → c-9bnDqE3g.js} +0 -0
  307. /package/dist/web/assets/{c3-BZ_Z0RrR.js → c3-JMZTrOhA.js} +0 -0
  308. /package/dist/web/assets/{cadence-B0GBC8OF.js → cadence-DsDNayJS.js} +0 -0
  309. /package/dist/web/assets/{can-open-in-ppm-omBzUBBq.js → can-open-in-ppm-BJfpynya.js} +0 -0
  310. /package/dist/web/assets/{catppuccin-frappe-DIt_xR7m.js → catppuccin-frappe-DYIKXXBe.js} +0 -0
  311. /package/dist/web/assets/{catppuccin-latte-Dw40AcqA.js → catppuccin-latte-IYYOnUJ8.js} +0 -0
  312. /package/dist/web/assets/{catppuccin-macchiato-BJ7DfVEF.js → catppuccin-macchiato-BrJ_7mfS.js} +0 -0
  313. /package/dist/web/assets/{catppuccin-mocha-NI2lfXzU.js → catppuccin-mocha-gzSu7v7-.js} +0 -0
  314. /package/dist/web/assets/{chevron-right-BLOtX8Vy.js → chevron-right-De-Wz5Lz.js} +0 -0
  315. /package/dist/web/assets/{circle-hjUGru6R.js → circle-BCy0AUCo.js} +0 -0
  316. /package/dist/web/assets/{clarity-F39L0xMJ.js → clarity-DLzsC0Hb.js} +0 -0
  317. /package/dist/web/assets/{clock-CvhF4DJP.js → clock-C1CQUQPZ.js} +0 -0
  318. /package/dist/web/assets/{clojure-DloMkd8K.js → clojure-DS1BvoTt.js} +0 -0
  319. /package/dist/web/assets/{cmake-CwerJun_.js → cmake-CDvsJwYp.js} +0 -0
  320. /package/dist/web/assets/{code-DDPoqVri.js → code-DJgYrFzm.js} +0 -0
  321. /package/dist/web/assets/{codeowners-CQyVz4Qf.js → codeowners-BjsYiflJ.js} +0 -0
  322. /package/dist/web/assets/{codeql-Bb229zuY.js → codeql-CG-7ARat.js} +0 -0
  323. /package/dist/web/assets/{common-lisp-KMlIwq5I.js → common-lisp-DSO1Lbh9.js} +0 -0
  324. /package/dist/web/assets/{copy-DKn11Pye.js → copy-BewHj66E.js} +0 -0
  325. /package/dist/web/assets/{coq-DHX_3IIo.js → coq-DYdh3oP_.js} +0 -0
  326. /package/dist/web/assets/{csharp-CEmCZv9Q.js → csharp-DxEBz5s0.js} +0 -0
  327. /package/dist/web/assets/{css-CqZqBD05.js → css-dal3Q-8C.js} +0 -0
  328. /package/dist/web/assets/{csv-l1g_V5MV.js → csv-CpqjMGiA.js} +0 -0
  329. /package/dist/web/assets/{csv-parser-CnS0wqr6.js → csv-parser-3umBA4NY.js} +0 -0
  330. /package/dist/web/assets/{cue-BrxRmilg.js → cue-DinoJ_5k.js} +0 -0
  331. /package/dist/web/assets/{cypher-rZkKwqZc.js → cypher-DzxqmkUW.js} +0 -0
  332. /package/dist/web/assets/{d-BALR-QuP.js → d-BxNwJuEC.js} +0 -0
  333. /package/dist/web/assets/{dark-plus-Cj7rVwh-.js → dark-plus-Clmv3V-0.js} +0 -0
  334. /package/dist/web/assets/{dart-CWQcdkXk.js → dart-BWVtXD35.js} +0 -0
  335. /package/dist/web/assets/{data-grid-types-CYvF-xK5.js → data-grid-types-B4n51Fck.js} +0 -0
  336. /package/dist/web/assets/{database-BH0urvbs.js → database-Y3ESDK4-.js} +0 -0
  337. /package/dist/web/assets/{dax-BNHD-QBA.js → dax-DsImuWgJ.js} +0 -0
  338. /package/dist/web/assets/{desktop-CN0IXPrP.js → desktop-B0jJuG2r.js} +0 -0
  339. /package/dist/web/assets/{diff-BtOXapES.js → diff-CWqAAxoE.js} +0 -0
  340. /package/dist/web/assets/{dist-DB1Oaqcc.js → dist-B-EXdSYE.js} +0 -0
  341. /package/dist/web/assets/{dist-Di6G_5jU.js → dist-C0eNNfbt.js} +0 -0
  342. /package/dist/web/assets/{docker-DNsAo_qO.js → docker-CYFCJdIL.js} +0 -0
  343. /package/dist/web/assets/{dotenv-D6Pl6aOU.js → dotenv-CKDUjURg.js} +0 -0
  344. /package/dist/web/assets/{download-zCATy4x4.js → download-DG3_9xXy.js} +0 -0
  345. /package/dist/web/assets/{dracula-C3m-w12D.js → dracula-CSoPspHE.js} +0 -0
  346. /package/dist/web/assets/{dracula-soft-BYqvXm6Z.js → dracula-soft-BuFjw5L1.js} +0 -0
  347. /package/dist/web/assets/{dream-maker-DZAPbPTi.js → dream-maker-B6PdDRZu.js} +0 -0
  348. /package/dist/web/assets/{emacs-lisp-Ao5SW8ay.js → emacs-lisp-CMcXvD0G.js} +0 -0
  349. /package/dist/web/assets/{everforest-dark-uC8QYotQ.js → everforest-dark-cU8-wYzi.js} +0 -0
  350. /package/dist/web/assets/{everforest-light-CTgsVNMr.js → everforest-light-KhorllqK.js} +0 -0
  351. /package/dist/web/assets/{fennel-WuBw6IR1.js → fennel-BCELZK87.js} +0 -0
  352. /package/dist/web/assets/{file-exclamation-point-COAwgNGw.js → file-exclamation-point-CZ4DiR75.js} +0 -0
  353. /package/dist/web/assets/{fish-Byy9dusu.js → fish-BQc0y_jy.js} +0 -0
  354. /package/dist/web/assets/{fluent-CDxb_sgw.js → fluent-BTINnwF6.js} +0 -0
  355. /package/dist/web/assets/{format-bytes-BE_W3UBg.js → format-bytes-WVcFxJuT.js} +0 -0
  356. /package/dist/web/assets/{fortran-free-form-DKWSTamT.js → fortran-free-form-BQim9wDz.js} +0 -0
  357. /package/dist/web/assets/{gdscript-prYHMgtD.js → gdscript-03w5u8un.js} +0 -0
  358. /package/dist/web/assets/{gdshader-D-RM-SQk.js → gdshader-Dp2daNzU.js} +0 -0
  359. /package/dist/web/assets/{genie-CowkJhej.js → genie-CoNcjPiD.js} +0 -0
  360. /package/dist/web/assets/{gherkin-CLFpoVYJ.js → gherkin-NrPOSPQL.js} +0 -0
  361. /package/dist/web/assets/{github-dark-default-BK_1Qgb8.js → github-dark-default-DOKw-1cI.js} +0 -0
  362. /package/dist/web/assets/{github-dark-dimmed-Cv9lj6f-.js → github-dark-dimmed-DJRNMkEA.js} +0 -0
  363. /package/dist/web/assets/{github-dark-high-contrast-CW5ZgIDh.js → github-dark-high-contrast-Bj7jJ_Gs.js} +0 -0
  364. /package/dist/web/assets/{github-dark-nW2F-RLd.js → github-dark-z4RE9ZqA.js} +0 -0
  365. /package/dist/web/assets/{github-light-D4PqBHGZ.js → github-light-B4k_yMFu.js} +0 -0
  366. /package/dist/web/assets/{github-light-default-B-cHtJJV.js → github-light-default-BHc-Uzhs.js} +0 -0
  367. /package/dist/web/assets/{github-light-high-contrast-Dt0HJq50.js → github-light-high-contrast-CHisIywL.js} +0 -0
  368. /package/dist/web/assets/{gleam-DwSyXJWP.js → gleam-CfbypZ4q.js} +0 -0
  369. /package/dist/web/assets/{gn-Cv5WEzHc.js → gn-YoAjyhJa.js} +0 -0
  370. /package/dist/web/assets/{gnuplot-D7bRdY_M.js → gnuplot-xVkc1f1c.js} +0 -0
  371. /package/dist/web/assets/{go-DiRVJ22U.js → go-GPCwP3Gu.js} +0 -0
  372. /package/dist/web/assets/{groovy-BHAgLTeO.js → groovy-Crh4Yww9.js} +0 -0
  373. /package/dist/web/assets/{gruvbox-dark-hard-C8QZ3gzY.js → gruvbox-dark-hard-BluUFuDS.js} +0 -0
  374. /package/dist/web/assets/{gruvbox-dark-medium-Dp1eeid2.js → gruvbox-dark-medium-Cxk1FWQp.js} +0 -0
  375. /package/dist/web/assets/{gruvbox-dark-soft-Cwq0dWVj.js → gruvbox-dark-soft-CHXMiFmj.js} +0 -0
  376. /package/dist/web/assets/{gruvbox-light-hard-CLQCq2-w.js → gruvbox-light-hard-B6eKPjAD.js} +0 -0
  377. /package/dist/web/assets/{gruvbox-light-medium-APHsh6Mo.js → gruvbox-light-medium-pDwMm1ut.js} +0 -0
  378. /package/dist/web/assets/{gruvbox-light-soft-CX-fYc64.js → gruvbox-light-soft-Cxu6kHqK.js} +0 -0
  379. /package/dist/web/assets/{haskell-C4Tw-TDa.js → haskell-C6JKHjbK.js} +0 -0
  380. /package/dist/web/assets/{haxe-B7fSduTQ.js → haxe-BuBNdF0a.js} +0 -0
  381. /package/dist/web/assets/{hcl-Bi3ho6yC.js → hcl-DZpDdGj2.js} +0 -0
  382. /package/dist/web/assets/{hjson-BXwae2M1.js → hjson-CBkhYRuo.js} +0 -0
  383. /package/dist/web/assets/{hlsl-CRuQLBSa.js → hlsl-C5nMxnp9.js} +0 -0
  384. /package/dist/web/assets/{horizon-DtdQ6qjv.js → horizon-VAFvA6R6.js} +0 -0
  385. /package/dist/web/assets/{horizon-bright-BXSF_uKq.js → horizon-bright-BC0xn7T3.js} +0 -0
  386. /package/dist/web/assets/{houston-C6ASpUjT.js → houston-BxrUivmz.js} +0 -0
  387. /package/dist/web/assets/{hy-BrWBHtHY.js → hy-DLtOXoaH.js} +0 -0
  388. /package/dist/web/assets/{image-gallery-CGvlv8zR.js → image-gallery-Gnf7TdCR.js} +0 -0
  389. /package/dist/web/assets/{imba-C_JJXckG.js → imba-BdpFXM2W.js} +0 -0
  390. /package/dist/web/assets/{ini-DEE_vSHQ.js → ini-BInJO_T0.js} +0 -0
  391. /package/dist/web/assets/{java-CnmpcjcT.js → java-Dxuddnkb.js} +0 -0
  392. /package/dist/web/assets/{javascript-C-M7sa2e.js → javascript-CVamJfLY.js} +0 -0
  393. /package/dist/web/assets/{json-BjZ3dAk6.js → json-BLZ0ozYk.js} +0 -0
  394. /package/dist/web/assets/{json5-BQ2vpqjp.js → json5-BnXzmMKs.js} +0 -0
  395. /package/dist/web/assets/{jsonc-C5MjoWGx.js → jsonc-CSgkSga7.js} +0 -0
  396. /package/dist/web/assets/{jsonl-JvhrmQJI.js → jsonl-CY5W2nF2.js} +0 -0
  397. /package/dist/web/assets/{jsonnet-C5pdZVuo.js → jsonnet-CEJYH3sF.js} +0 -0
  398. /package/dist/web/assets/{jssm-Db17uybX.js → jssm-CsJc7Uhk.js} +0 -0
  399. /package/dist/web/assets/{jsx-tJp2Cyqu.js → jsx-jCiRaHU7.js} +0 -0
  400. /package/dist/web/assets/{kanagawa-dragon-BculT_Y1.js → kanagawa-dragon-DfoA_GxX.js} +0 -0
  401. /package/dist/web/assets/{kanagawa-lotus-yQgHUGwU.js → kanagawa-lotus-BOLYJpWd.js} +0 -0
  402. /package/dist/web/assets/{kanagawa-wave-CyGoWN4d.js → kanagawa-wave-DfKlbT1G.js} +0 -0
  403. /package/dist/web/assets/{kdl-Bn8R1REF.js → kdl-CmssIFTi.js} +0 -0
  404. /package/dist/web/assets/{kotlin-DWughK73.js → kotlin-BRsNgp6x.js} +0 -0
  405. /package/dist/web/assets/{kusto--serPb0x.js → kusto-T8X9jUab.js} +0 -0
  406. /package/dist/web/assets/{laserwave-DfAPJ1tt.js → laserwave-DkJMVJ8Z.js} +0 -0
  407. /package/dist/web/assets/{lean-UAm1HOKl.js → lean-C65KGVPq.js} +0 -0
  408. /package/dist/web/assets/{less-Xj6Ka0fF.js → less-exIPdDlf.js} +0 -0
  409. /package/dist/web/assets/{lib-DgNcCtj3.js → lib-mC1NZfuw.js} +0 -0
  410. /package/dist/web/assets/{libesm-CPh1Av0r.js → libesm-DSutUtl1.js} +0 -0
  411. /package/dist/web/assets/{light-plus-BfS7gPcj.js → light-plus-DiHUXAZt.js} +0 -0
  412. /package/dist/web/assets/{llvm-DvWiVwvU.js → llvm-CJBnEzFM.js} +0 -0
  413. /package/dist/web/assets/{log-Bo5z9bNz.js → log-DxMyUMuP.js} +0 -0
  414. /package/dist/web/assets/{logo-CrIjcMZT.js → logo-CC9NKzca.js} +0 -0
  415. /package/dist/web/assets/{luau-C9TsYwNt.js → luau-Bw10I6zf.js} +0 -0
  416. /package/dist/web/assets/{make-GYq4qVbx.js → make-C_6M90m6.js} +0 -0
  417. /package/dist/web/assets/{markdown-p5mNledS.js → markdown-bR9_R-LF.js} +0 -0
  418. /package/dist/web/assets/{material-theme-CWYOVxsP.js → material-theme-BUx2Qujn.js} +0 -0
  419. /package/dist/web/assets/{material-theme-darker-BDGty7YH.js → material-theme-darker-CRJrPgKm.js} +0 -0
  420. /package/dist/web/assets/{material-theme-lighter-JbgOgV3n.js → material-theme-lighter-CUAYppPa.js} +0 -0
  421. /package/dist/web/assets/{material-theme-ocean-EMOpLpa2.js → material-theme-ocean-DuINF1fg.js} +0 -0
  422. /package/dist/web/assets/{material-theme-palenight-CY5hgm7h.js → material-theme-palenight-W6_icGCj.js} +0 -0
  423. /package/dist/web/assets/{matlab-C-He_NTH.js → matlab-rfqn_b3z.js} +0 -0
  424. /package/dist/web/assets/{mdx-Cr2TR5fj.js → mdx-Bh1B_YOJ.js} +0 -0
  425. /package/dist/web/assets/{mermaid-BYc0-B0U.js → mermaid-Dxf6Ya2k.js} +0 -0
  426. /package/dist/web/assets/{min-dark-CMJwqJqB.js → min-dark-CivZ2L0h.js} +0 -0
  427. /package/dist/web/assets/{min-light-Cx6vFiEX.js → min-light-B1Ykqtma.js} +0 -0
  428. /package/dist/web/assets/{mipsasm-Bjer5HwK.js → mipsasm-DynHaM0d.js} +0 -0
  429. /package/dist/web/assets/{mojo-t90PR-Y2.js → mojo-Clw5PbGH.js} +0 -0
  430. /package/dist/web/assets/{monokai-dci_PdCm.js → monokai-DFIooFZT.js} +0 -0
  431. /package/dist/web/assets/{moonbit-AAzI-Hd-.js → moonbit-DnBSZWGM.js} +0 -0
  432. /package/dist/web/assets/{move-kwBhnhrG.js → move-CCcL2PfL.js} +0 -0
  433. /package/dist/web/assets/{narrat-CXww2YQL.js → narrat-BDarg5Lk.js} +0 -0
  434. /package/dist/web/assets/{nextflow-groovy-CJXsuXGB.js → nextflow-groovy-DrZOeCNW.js} +0 -0
  435. /package/dist/web/assets/{night-owl-_GD204Wr.js → night-owl-BnZZCK7v.js} +0 -0
  436. /package/dist/web/assets/{night-owl-light-DNgkw3kl.js → night-owl-light-CEwBsVHS.js} +0 -0
  437. /package/dist/web/assets/{nix-BgiorKFd.js → nix-amCzOPMR.js} +0 -0
  438. /package/dist/web/assets/{nord-CaBmcxFC.js → nord-BIs2BC6q.js} +0 -0
  439. /package/dist/web/assets/{nushell-DUh4UGx1.js → nushell-Y02fo4yw.js} +0 -0
  440. /package/dist/web/assets/{objective-c-Cl9KU86S.js → objective-c-7xOZtWW1.js} +0 -0
  441. /package/dist/web/assets/{objective-cpp-DVkIA8A0.js → objective-cpp-eVtjUvVB.js} +0 -0
  442. /package/dist/web/assets/{ocaml-vvoHTak0.js → ocaml-Bi6ZwqG4.js} +0 -0
  443. /package/dist/web/assets/{odin-Cyjw8woZ.js → odin-8xf1Y0S9.js} +0 -0
  444. /package/dist/web/assets/{one-dark-pro-B1cviILi.js → one-dark-pro-hVv-_y_b.js} +0 -0
  445. /package/dist/web/assets/{one-light-BPGUJeYI.js → one-light-CJJ3MtHt.js} +0 -0
  446. /package/dist/web/assets/{openscad-BLMdTUU8.js → openscad-B2HcywLk.js} +0 -0
  447. /package/dist/web/assets/{pascal-i5niy3e7.js → pascal-C7fllV_7.js} +0 -0
  448. /package/dist/web/assets/{pkl-CuOV7SsU.js → pkl-qvLC1IWP.js} +0 -0
  449. /package/dist/web/assets/{plastic-Bf_zE5KL.js → plastic-BT1wHZv2.js} +0 -0
  450. /package/dist/web/assets/{plsql-cfqEtMD3.js → plsql-1MsmdmJD.js} +0 -0
  451. /package/dist/web/assets/{plus-BM-Ty0fp.js → plus-BhMZqFsN.js} +0 -0
  452. /package/dist/web/assets/{po-CFJcWgjr.js → po-BigskytD.js} +0 -0
  453. /package/dist/web/assets/{poimandres-G5YoaIFf.js → poimandres-DuklniF7.js} +0 -0
  454. /package/dist/web/assets/{polar-rcjs3i9R.js → polar-e2pjN_sp.js} +0 -0
  455. /package/dist/web/assets/{postcss-CBKY1FTZ.js → postcss-DtAeYjWw.js} +0 -0
  456. /package/dist/web/assets/{powerquery-Db7SXLbO.js → powerquery-Cr2PtehI.js} +0 -0
  457. /package/dist/web/assets/{powershell-LFy3MUTP.js → powershell-BxFTGLJ4.js} +0 -0
  458. /package/dist/web/assets/{prisma-BE8GR1lH.js → prisma-COWJiwdZ.js} +0 -0
  459. /package/dist/web/assets/{prolog-DOn5lR1e.js → prolog-DFvGKRx6.js} +0 -0
  460. /package/dist/web/assets/{proto-wr-TpAK_.js → proto-CcK80lFt.js} +0 -0
  461. /package/dist/web/assets/{puppet-D2Dkv62u.js → puppet-BF60bZ4F.js} +0 -0
  462. /package/dist/web/assets/{purescript-DvgJgPdy.js → purescript-zL_69MzU.js} +0 -0
  463. /package/dist/web/assets/{python-C7TlkHhK.js → python-CIwKhfb_.js} +0 -0
  464. /package/dist/web/assets/{qmldir-CtZMwhcW.js → qmldir-CXNe04Lo.js} +0 -0
  465. /package/dist/web/assets/{qss-dNZ2btnl.js → qss-C8lAWe6G.js} +0 -0
  466. /package/dist/web/assets/{r-BlqnNkHS.js → r-CL5ZVL3_.js} +0 -0
  467. /package/dist/web/assets/{racket-CzRQrGc4.js → racket-BBfh0uh0.js} +0 -0
  468. /package/dist/web/assets/{raku-BwutWhBF.js → raku-o6E8R5Q3.js} +0 -0
  469. /package/dist/web/assets/{react-I_EwPIZi.js → react-CBTnT4sY.js} +0 -0
  470. /package/dist/web/assets/{red-BMXMywmL.js → red-GomRF2Xp.js} +0 -0
  471. /package/dist/web/assets/{reg-BqOKrIOw.js → reg-_ffDIvx9.js} +0 -0
  472. /package/dist/web/assets/{regexp-Bero1BN2.js → regexp-Bl5sF65W.js} +0 -0
  473. /package/dist/web/assets/{rel-BXKWIElA.js → rel-DgMdqDuj.js} +0 -0
  474. /package/dist/web/assets/{resolve-theme-B9ABAH_3.js → resolve-theme-CRt_7wpd.js} +0 -0
  475. /package/dist/web/assets/{riscv-BbbBYJBo.js → riscv-8b3-Ye4X.js} +0 -0
  476. /package/dist/web/assets/{ron-BtVTWW4b.js → ron-DrmU1KHP.js} +0 -0
  477. /package/dist/web/assets/{rose-pine-hvkvQzvU.js → rose-pine-C_-E2tF1.js} +0 -0
  478. /package/dist/web/assets/{rose-pine-dawn-D7lwhUei.js → rose-pine-dawn-DEfhNlFH.js} +0 -0
  479. /package/dist/web/assets/{rose-pine-moon-CoHDmsIw.js → rose-pine-moon-BdvX3gdn.js} +0 -0
  480. /package/dist/web/assets/{rosmsg-CdaZFgI8.js → rosmsg-B6GhGpd5.js} +0 -0
  481. /package/dist/web/assets/{rust-Dy2qsphD.js → rust-DmC97M1-.js} +0 -0
  482. /package/dist/web/assets/{sass-Bz7NVxDb.js → sass-B0tJOHLM.js} +0 -0
  483. /package/dist/web/assets/{save-C4z1p51e.js → save-CtIGOjmx.js} +0 -0
  484. /package/dist/web/assets/{scala-sXSwsNyq.js → scala-n8zaFOXv.js} +0 -0
  485. /package/dist/web/assets/{scheme-DS7TUbN7.js → scheme-BKD9ztBU.js} +0 -0
  486. /package/dist/web/assets/{sdbl-iISFvIep.js → sdbl-D8gB5-rS.js} +0 -0
  487. /package/dist/web/assets/{shellscript-BkIl4ApC.js → shellscript-BfXlf_Ao.js} +0 -0
  488. /package/dist/web/assets/{shield-check-C5laObJv.js → shield-check-B0iGUiOK.js} +0 -0
  489. /package/dist/web/assets/{shield-off-DULFtyLS.js → shield-off-BNLWBhcq.js} +0 -0
  490. /package/dist/web/assets/{slack-dark-B1eg0_m2.js → slack-dark-CylEddse.js} +0 -0
  491. /package/dist/web/assets/{slack-ochin-mdkc1ldu.js → slack-ochin-w8wg8vuC.js} +0 -0
  492. /package/dist/web/assets/{smalltalk-CORtd03t.js → smalltalk-hiAXA64u.js} +0 -0
  493. /package/dist/web/assets/{snazzy-light-Bc6Q2G89.js → snazzy-light-BwlV3Xty.js} +0 -0
  494. /package/dist/web/assets/{solarized-dark-CF83zRXM.js → solarized-dark-vmNGdykz.js} +0 -0
  495. /package/dist/web/assets/{solarized-light-BoKQZaYU.js → solarized-light-DGv_0JXq.js} +0 -0
  496. /package/dist/web/assets/{solidity-DOgi1N4w.js → solidity-Y7QSH0B1.js} +0 -0
  497. /package/dist/web/assets/{sparkles-Dqsf3hq6.js → sparkles-Dh-_J2Rd.js} +0 -0
  498. /package/dist/web/assets/{splunk-BXfw5ZLy.js → splunk-BtgpLjHi.js} +0 -0
  499. /package/dist/web/assets/{sql-BcVs-eX4.js → sql-CRHYhOia.js} +0 -0
  500. /package/dist/web/assets/{ssh-config-CLCtNkkd.js → ssh-config-DOqSs3au.js} +0 -0
  501. /package/dist/web/assets/{stylus-DdP992aO.js → stylus-crCAEaBT.js} +0 -0
  502. /package/dist/web/assets/{swift-BnGb6Lgc.js → swift-eE3rT7TC.js} +0 -0
  503. /package/dist/web/assets/{synthwave-84-cg9264l9.js → synthwave-84-BWy14LBX.js} +0 -0
  504. /package/dist/web/assets/{system-verilog-GbHpszs3.js → system-verilog-DC0-DZM4.js} +0 -0
  505. /package/dist/web/assets/{systemd-Dz-bNsDQ.js → systemd-to5p6N8I.js} +0 -0
  506. /package/dist/web/assets/{table-CHmxuh6M.js → table-Bbc783ko.js} +0 -0
  507. /package/dist/web/assets/{talonscript-CFIidoBA.js → talonscript-DoTcU8wm.js} +0 -0
  508. /package/dist/web/assets/{tasl-Cu-TRTKx.js → tasl-cNZvUs95.js} +0 -0
  509. /package/dist/web/assets/{tcl-DwCHCB1K.js → tcl-mZE8sZH8.js} +0 -0
  510. /package/dist/web/assets/{terraform-BzZw4T1z.js → terraform-CqHPpIfu.js} +0 -0
  511. /package/dist/web/assets/{tokyo-night-RKsj2-tv.js → tokyo-night-Tp2rTIZd.js} +0 -0
  512. /package/dist/web/assets/{toml-CirbOgDP.js → toml-CU_vscgn.js} +0 -0
  513. /package/dist/web/assets/{tsv-CraRcWdU.js → tsv-ik7iFB9D.js} +0 -0
  514. /package/dist/web/assets/{tsx-CjFg0lgw.js → tsx-BMvvMKiv.js} +0 -0
  515. /package/dist/web/assets/{turtle-B-WBIOa6.js → turtle-DBqKCq9o.js} +0 -0
  516. /package/dist/web/assets/{typescript-MpLarYn1.js → typescript-DXJDmMZZ.js} +0 -0
  517. /package/dist/web/assets/{typespec-B7QlHMZ_.js → typespec-CBseCMtZ.js} +0 -0
  518. /package/dist/web/assets/{typst-CcHSKFZj.js → typst-4oY25U9y.js} +0 -0
  519. /package/dist/web/assets/{use-is-mobile-BXGVvczu.js → use-is-mobile-D1weanbj.js} +0 -0
  520. /package/dist/web/assets/{utils-DoY4yTP-.js → utils-BNRH507E.js} +0 -0
  521. /package/dist/web/assets/{v-xTGhWZuD.js → v-BXaZ_1oy.js} +0 -0
  522. /package/dist/web/assets/{vala-DwebjH3H.js → vala-BImWJE7z.js} +0 -0
  523. /package/dist/web/assets/{vb-BxJT2RAy.js → vb-CLfj2_sy.js} +0 -0
  524. /package/dist/web/assets/{vendor-xterm-CU6zIYMB.js → vendor-xterm-_yyu5n32.js} +0 -0
  525. /package/dist/web/assets/{verilog-CvV6RHPD.js → verilog-BWa8Ed2b.js} +0 -0
  526. /package/dist/web/assets/{vesper-CY3qd7E_.js → vesper-BGj1cg6m.js} +0 -0
  527. /package/dist/web/assets/{vhdl-B9ZX-sUL.js → vhdl-mByK7mlx.js} +0 -0
  528. /package/dist/web/assets/{viml-Y42h_ExQ.js → viml-CugmlW5g.js} +0 -0
  529. /package/dist/web/assets/{vitesse-black-DkXP6Sv-.js → vitesse-black-vPdpy9TL.js} +0 -0
  530. /package/dist/web/assets/{vitesse-dark-B9CkIB6r.js → vitesse-dark-BuQK3dUh.js} +0 -0
  531. /package/dist/web/assets/{vitesse-light-C7DHrJCK.js → vitesse-light-B3nz1XL9.js} +0 -0
  532. /package/dist/web/assets/{vyper-Cnd9s5j-.js → vyper-DH_GTIHG.js} +0 -0
  533. /package/dist/web/assets/{wasm-DQE71XTB.js → wasm-C-LF9GjX.js} +0 -0
  534. /package/dist/web/assets/{wasm-iWe7Fzjc.js → wasm-DfVbVJlW.js} +0 -0
  535. /package/dist/web/assets/{wenyan-Bc5Pnm9l.js → wenyan-CzQkHyHx.js} +0 -0
  536. /package/dist/web/assets/{wgsl-D-YUAWkP.js → wgsl-Du_M1DW9.js} +0 -0
  537. /package/dist/web/assets/{wikitext-DYQDUYf2.js → wikitext-BWN_w5S7.js} +0 -0
  538. /package/dist/web/assets/{wit-P6u7mfwy.js → wit-BR13v5HD.js} +0 -0
  539. /package/dist/web/assets/{wolfram-6SXLUqao.js → wolfram-BoXxp_Xl.js} +0 -0
  540. /package/dist/web/assets/{x-BcqfTY_7.js → x-nhriOX9o.js} +0 -0
  541. /package/dist/web/assets/{yaml-CQiMLVcZ.js → yaml-DpR_EF-d.js} +0 -0
  542. /package/dist/web/assets/{zenscript-DFMywo_P.js → zenscript-C-EdUtUd.js} +0 -0
  543. /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 (document.visibilityState === "visible") checkConnection();
412
+ if (hostDoc.visibilityState === "visible") checkConnection();
405
413
  };
406
- document.addEventListener("visibilitychange", onVisibility);
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
- document.removeEventListener("visibilitychange", onVisibility);
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: cleanedPanels,
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
- if (newTabs.length === 0 && gridPanelCount > 1 && pid !== DOCK_PANEL_ID) {
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
- if (fromTabs.length === 0 && gridPanelCount > 1 && fromPanelId !== DOCK_PANEL_ID) {
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
+ }