@hienlh/ppm 0.18.10 → 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.
Files changed (575) hide show
  1. package/.spike/cdp-client.ts +116 -0
  2. package/.spike/cleanup-ppm-workspace.mjs +44 -0
  3. package/.spike/pip-eval.ts +17 -0
  4. package/.spike/pip-page-helpers.js +119 -0
  5. package/.spike/pip-results-editor-glue.json +105 -0
  6. package/.spike/pip-results-editor.json +158 -0
  7. package/.spike/pip-results-input-isolation.json +28 -0
  8. package/.spike/pip-results-key-probe.json +58 -0
  9. package/.spike/pip-results-listener-survival.json +98 -0
  10. package/.spike/pip-results-listeners.json +36 -0
  11. package/.spike/pip-results-pagehide.json +92 -0
  12. package/.spike/pip-results-resize.json +104 -0
  13. package/.spike/pip-results-terminal-debug.json +99 -0
  14. package/.spike/pip-results-terminal-v2.json +191 -0
  15. package/.spike/pip-results-terminal.json +220 -0
  16. package/.spike/pip-results-xterm-trace.json +73 -0
  17. package/.spike/pip-spike-common.ts +83 -0
  18. package/.spike/pip-spike-editor-glue.ts +82 -0
  19. package/.spike/pip-spike-editor.ts +129 -0
  20. package/.spike/pip-spike-input-isolation.ts +38 -0
  21. package/.spike/pip-spike-key-probe.ts +34 -0
  22. package/.spike/pip-spike-listener-survival.ts +54 -0
  23. package/.spike/pip-spike-listeners.ts +19 -0
  24. package/.spike/pip-spike-pagehide.ts +59 -0
  25. package/.spike/pip-spike-resize.ts +42 -0
  26. package/.spike/pip-spike-setup.ts +63 -0
  27. package/.spike/pip-spike-terminal-debug.ts +81 -0
  28. package/.spike/pip-spike-terminal-v2.ts +139 -0
  29. package/.spike/pip-spike-terminal.ts +169 -0
  30. package/.spike/pip-spike-xterm-trace.ts +36 -0
  31. package/.spike/probe-drag-memo-error.mjs +67 -0
  32. package/.spike/read-dev-db.ts +15 -0
  33. package/.spike/scratch-editor-target.ts +7 -0
  34. package/.spike/smoke-unified-chrome-pip.mjs +353 -0
  35. package/.spike/tunnel.err +41 -0
  36. package/.spike/vite-restart.err +663 -0
  37. package/.spike/w.err +543 -0
  38. package/CHANGELOG.md +13 -0
  39. package/assets/skills/ppm/SKILL.md +1 -1
  40. package/assets/skills/ppm/references/http-api.md +1 -1
  41. package/dist/web/assets/adaptive-context-menu-DGCKKeTy.js +1 -0
  42. package/dist/web/assets/ai-resource-editor-BOHHTTe7.js +1 -0
  43. package/dist/web/assets/ai-settings-section-BigC_nZR.js +1 -0
  44. package/dist/web/assets/{angular-html-Ctz0zN01.js → angular-html-BYPaydvh.js} +1 -1
  45. package/dist/web/assets/{angular-ts-QXHpgB1C.js → angular-ts-Bb4AMKlk.js} +1 -1
  46. package/dist/web/assets/api-client-DTZEgjBQ.js +1 -0
  47. package/dist/web/assets/{api-settings-kQHV6pYZ.js → api-settings-Bd3M4YpI.js} +1 -1
  48. package/dist/web/assets/api-settings-kd1j4iR8.js +1 -0
  49. package/dist/web/assets/{api-themes-CrK0tkW_.js → api-themes-Cpx419SL.js} +1 -1
  50. package/dist/web/assets/{apl-b9KVk-O4.js → apl-DB2VjFCS.js} +1 -1
  51. package/dist/web/assets/architecture-PBZL5I3N-8dCMT9r7.js +1 -0
  52. package/dist/web/assets/{astro-BlFEeGYr.js → astro-BeoJdVpk.js} +1 -1
  53. package/dist/web/assets/{audio-preview-CZLmhf__.js → audio-preview-BgFuTn-0.js} +1 -1
  54. package/dist/web/assets/{blade-CGkj2MUI.js → blade-Cf2q1sPf.js} +1 -1
  55. package/dist/web/assets/{bsl-CVsbb6ap.js → bsl-W1kOaNpu.js} +1 -1
  56. package/dist/web/assets/{button-BA_fJOtX.js → button-5zTrkEoN.js} +1 -1
  57. package/dist/web/assets/{cairo-BbIHl2iE.js → cairo-BoAZFcje.js} +1 -1
  58. package/dist/web/assets/chat-tab-E3bf_V8X.js +15 -0
  59. package/dist/web/assets/chevron-down-Dp0rpHb8.js +1 -0
  60. package/dist/web/assets/clipboard-7fw0Shic.js +1 -0
  61. package/dist/web/assets/{cobol-BWSGjmWb.js → cobol-B0Nm7RXj.js} +1 -1
  62. package/dist/web/assets/code-editor-BUlM2gXk.js +10 -0
  63. package/dist/web/assets/{coffee-CWGNOxds.js → coffee-BakMn3on.js} +1 -1
  64. package/dist/web/assets/{conflict-editor-fRTU3f1o.js → conflict-editor-BUs5k9q_.js} +4 -4
  65. package/dist/web/assets/context-menu-Bq92km4s.js +1 -0
  66. package/dist/web/assets/{cpp-DHGV24J2.js → cpp-BRAJQHK2.js} +1 -1
  67. package/dist/web/assets/{crystal-Vlwf2UMP.js → crystal-kqqO3zkK.js} +1 -1
  68. package/dist/web/assets/{csv-preview-D1d0cxOJ.js → csv-preview-ByoDgLAZ.js} +1 -1
  69. package/dist/web/assets/{data-grid-overlay-editor-D9il5DZS.js → data-grid-overlay-editor-Brkf9z41.js} +1 -1
  70. package/dist/web/assets/database-viewer-Btc3h8Yu.js +1 -0
  71. package/dist/web/assets/dialog-DwtGlowE.js +1 -0
  72. package/dist/web/assets/diff-viewer-CZaDnR4w.js +4 -0
  73. package/dist/web/assets/docx-preview-DAD_vg59.js +12 -0
  74. package/dist/web/assets/{edge-Bhqk64zS.js → edge-Cq1ZKZuE.js} +1 -1
  75. package/dist/web/assets/{edit-diff-preview-gq6ALf2B.js → edit-diff-preview-B_VE7ppQ.js} +1 -1
  76. package/dist/web/assets/{elixir-D466WCFm.js → elixir-BM_JoJRk.js} +1 -1
  77. package/dist/web/assets/{elm-Bfs2qNPR.js → elm-Dw7oO08Y.js} +1 -1
  78. package/dist/web/assets/{erb-WI7jUaB6.js → erb-CfKOGAfk.js} +1 -1
  79. package/dist/web/assets/{erlang-BCBe8nCc.js → erlang-DlDmGVeE.js} +1 -1
  80. package/dist/web/assets/{esm-CZs9WVDO.js → esm-DGAP0GFh.js} +1 -1
  81. package/dist/web/assets/explorer-body-9aBmyVpZ.js +2 -0
  82. package/dist/web/assets/explorer-window-content-DRtqoSPA.js +1 -0
  83. package/dist/web/assets/extension-store-Cpfh2vMm.js +1 -0
  84. package/dist/web/assets/{extension-webview-BH_mWYMe.js → extension-webview-B2OnjuCu.js} +2 -2
  85. package/dist/web/assets/external-link-B8BynhvY.js +1 -0
  86. package/dist/web/assets/file-store-aOERIEo-.js +1 -0
  87. package/dist/web/assets/folder-symlink-B8XrtvQK.js +1 -0
  88. package/dist/web/assets/{fortran-fixed-form-CXLIv8Ox.js → fortran-fixed-form-XnAhQWxS.js} +1 -1
  89. package/dist/web/assets/{fsharp-CZsYmiw9.js → fsharp-CdNvy0PG.js} +1 -1
  90. package/dist/web/assets/{gdresource-BGRvoWfC.js → gdresource-DxuG5i8i.js} +1 -1
  91. package/dist/web/assets/{git-commit-DH6mY3Km.js → git-commit-3lMonsur.js} +1 -1
  92. package/dist/web/assets/git-log-panel-Co0PBPHC.js +1 -0
  93. package/dist/web/assets/{git-rebase-C5Gql6Ma.js → git-rebase-N8Z9kIMf.js} +1 -1
  94. package/dist/web/assets/gitGraph-HDMCJU4V-2e_8dfbs.js +1 -0
  95. package/dist/web/assets/{glide-data-grid-n4ox_uev.js → glide-data-grid-C4_zIneN.js} +8 -8
  96. package/dist/web/assets/{glimmer-js-1-6JMJlj.js → glimmer-js-Dp9OXiib.js} +1 -1
  97. package/dist/web/assets/{glimmer-ts-C_Njj0nK.js → glimmer-ts-CDVKBcDj.js} +1 -1
  98. package/dist/web/assets/{glsl-DbkxE1TN.js → glsl-DPJxI4us.js} +1 -1
  99. package/dist/web/assets/{graphql-BK75fiXl.js → graphql-BrFhaQQl.js} +1 -1
  100. package/dist/web/assets/group-chat-tab-rOd8J8GC.js +1 -0
  101. package/dist/web/assets/{hack-DG151vit.js → hack-BzXbDMlA.js} +1 -1
  102. package/dist/web/assets/{haml-DKeIPQWM.js → haml-CPpkX0s5.js} +1 -1
  103. package/dist/web/assets/{handlebars-398uCI13.js → handlebars-BqrApy52.js} +1 -1
  104. package/dist/web/assets/{html-NLWdst5q.js → html-DmjUl-OA.js} +1 -1
  105. package/dist/web/assets/{html-derivative-CJf_Le2z.js → html-derivative-Cnd6XFR5.js} +1 -1
  106. package/dist/web/assets/{http-G1K2FozA.js → http-DMLWYun2.js} +1 -1
  107. package/dist/web/assets/{hurl-WDC6sSBz.js → hurl-CKkCVxbj.js} +1 -1
  108. package/dist/web/assets/{hxml-Dc3jBXuf.js → hxml-CAx19TtQ.js} +1 -1
  109. package/dist/web/assets/image-preview-DHUoylQ1.js +1 -0
  110. package/dist/web/assets/index-BImUaigO.js +52 -0
  111. package/dist/web/assets/index-CSfi6DSU.css +2 -0
  112. package/dist/web/assets/info-3K5VOQVL-BZi1Gha1.js +1 -0
  113. package/dist/web/assets/input-DcEk7mA3.js +1 -0
  114. package/dist/web/assets/{jinja-CWsQj2y0.js → jinja-BmB9YN9l.js} +1 -1
  115. package/dist/web/assets/{jison-CciJg2NW.js → jison-BaVsKKpw.js} +1 -1
  116. package/dist/web/assets/{julia-IOQNJAB7.js → julia-BgVBLveX.js} +1 -1
  117. package/dist/web/assets/{just-BGdHchwS.js → just-C2ENIbl9.js} +1 -1
  118. package/dist/web/assets/keybindings-store-BGIyqXHI.js +1 -0
  119. package/dist/web/assets/keybindings-store-CzV2sPls.js +1 -0
  120. package/dist/web/assets/{latex-D6TOl-L2.js → latex-BiDIWxKL.js} +1 -1
  121. package/dist/web/assets/{liquid-CVSvu_Wn.js → liquid-NxpapreE.js} +1 -1
  122. package/dist/web/assets/loader-circle-gSPVxfvH.js +1 -0
  123. package/dist/web/assets/lock-Did-87UV.js +1 -0
  124. package/dist/web/assets/{lua-CcKiU6HW.js → lua-DVepQvwH.js} +1 -1
  125. package/dist/web/assets/markdown-renderer-CcbR33VG.js +1 -0
  126. package/dist/web/assets/{markdown-renderer-B317vEys.js → markdown-renderer-DlcDhgrF.js} +3 -3
  127. package/dist/web/assets/{marko--UOicMGo.js → marko-CJ2606Xl.js} +1 -1
  128. package/dist/web/assets/{mdc-D690aU2C.js → mdc-D2bjqclE.js} +1 -1
  129. package/dist/web/assets/{media-url-CylYQld1.js → media-url-H17XJF-I.js} +1 -1
  130. package/dist/web/assets/mobile-bottom-sheet-g-r2hCFa.js +1 -0
  131. package/dist/web/assets/mobile-explorer-sheet-SIwQXlwA.js +1 -0
  132. package/dist/web/assets/monitor-Dv8vn_6O.js +1 -0
  133. package/dist/web/assets/{nextflow-DR8PhpF8.js → nextflow-BtJwUbfF.js} +1 -1
  134. package/dist/web/assets/{nginx-Qb9pUk1g.js → nginx-j4gyIhHE.js} +1 -1
  135. package/dist/web/assets/{nim-DLa8R3NS.js → nim-ClH_gjP5.js} +1 -1
  136. package/dist/web/assets/notification-store-DV5QtUTg.js +1 -0
  137. package/dist/web/assets/{number-overlay-editor-D9SkFg1Y.js → number-overlay-editor-C1EqJnWq.js} +1 -1
  138. package/dist/web/assets/{overview-panel-BxDohIEa.js → overview-panel-vTeeJYVZ.js} +1 -1
  139. package/dist/web/assets/packet-RMMSAZCW-o5htEcin.js +1 -0
  140. package/dist/web/assets/panel-store-BSnkjgHt.js +1 -0
  141. package/dist/web/assets/pdf-preview-CqFGRY0Z.js +1 -0
  142. package/dist/web/assets/pencil-BlIIg6RH.js +1 -0
  143. package/dist/web/assets/{perl-AMNGIneF.js → perl-C9H7X7CT.js} +1 -1
  144. package/dist/web/assets/{php-CDsOOxXn.js → php-Bx2U-cQ_.js} +1 -1
  145. package/dist/web/assets/pie-UPGHQEXC-BXAIFSAD.js +1 -0
  146. package/dist/web/assets/play-4MZi1Axp.js +1 -0
  147. package/dist/web/assets/portal-container-context-Cm5HipFr.js +1 -0
  148. package/dist/web/assets/{postgres-viewer-BWZLW7kI.js → postgres-viewer-DHwcQucn.js} +3 -3
  149. package/dist/web/assets/process-table-BGRJNlpn.js +1 -0
  150. package/dist/web/assets/{project-store-B8BkHXy5.js → project-store--nvQiy75.js} +1 -1
  151. package/dist/web/assets/{pug-C2kdkhQ6.js → pug-Cw74sKsE.js} +1 -1
  152. package/dist/web/assets/{qml-DRDkUp75.js → qml-BXD94Eqz.js} +1 -1
  153. package/dist/web/assets/radar-KQ55EAFF-Dbt2Aebl.js +1 -0
  154. package/dist/web/assets/{razor-wY_6wUeC.js → razor-DZ0-Ge0S.js} +1 -1
  155. package/dist/web/assets/refresh-cw-B06yaBrW.js +1 -0
  156. package/dist/web/assets/rotate-ccw-COXu_9oj.js +1 -0
  157. package/dist/web/assets/{rst-BRpofyNs.js → rst-Dtdh0QUj.js} +1 -1
  158. package/dist/web/assets/{ruby-ieATBhWm.js → ruby-BC51BW2Q.js} +1 -1
  159. package/dist/web/assets/{run-in-terminal-CyS5Itj-.js → run-in-terminal-Sd3KyjN4.js} +1 -1
  160. package/dist/web/assets/{sas-CoOOEbOO.js → sas-BN8i4qOU.js} +1 -1
  161. package/dist/web/assets/scroll-area-0gljZ6lF.js +1 -0
  162. package/dist/web/assets/{scss-_nWV0bsb.js → scss-H-QtA7Rz.js} +1 -1
  163. package/dist/web/assets/send-BlyNJAzy.js +1 -0
  164. package/dist/web/assets/{send-to-chat-BcO39BDR.js → send-to-chat-u6m8l-rH.js} +1 -1
  165. package/dist/web/assets/{settings-store-C20lqh0G.js → settings-store-CHY6Kzin.js} +2 -2
  166. package/dist/web/assets/settings-tab-Dic6TKkU.js +1 -0
  167. package/dist/web/assets/settings-tab-IY6K1MiZ.js +3 -0
  168. package/dist/web/assets/{shaderlab-XkqfIfO8.js → shaderlab-CalNsj_x.js} +1 -1
  169. package/dist/web/assets/shallow-DYo6goJ4.js +1 -0
  170. package/dist/web/assets/{shellsession-BKBIqTlM.js → shellsession-BFrcoR8x.js} +1 -1
  171. package/dist/web/assets/{soy-oVDnPzzh.js → soy-CNbku7vP.js} +1 -1
  172. package/dist/web/assets/{sparql-N2VclEsF.js → sparql-BN_orcVp.js} +1 -1
  173. package/dist/web/assets/{sql-query-editor-BwPjEaP9.js → sql-query-editor-C6pC3I8l.js} +1 -1
  174. package/dist/web/assets/sqlite-viewer-DTr5PzUb.js +1 -0
  175. package/dist/web/assets/{stata-BuuClVDg.js → stata-C6a5Ijzq.js} +1 -1
  176. package/dist/web/assets/{surrealql-DE5_63MS.js → surrealql-ClplI_HY.js} +1 -1
  177. package/dist/web/assets/{svelte--YWjlOrK.js → svelte-DNm-UNXB.js} +1 -1
  178. package/dist/web/assets/switch-DKvKya9y.js +1 -0
  179. package/dist/web/assets/system-monitor-body-iwGiCns9.js +2 -0
  180. package/dist/web/assets/system-monitor-tab-DdXQhEel.js +1 -0
  181. package/dist/web/assets/system-monitor-window-content-BUqRsPK2.js +1 -0
  182. package/dist/web/assets/tab-host-window-content-BnqGPu8a.js +1 -0
  183. package/dist/web/assets/{tab-store-DAsvpx4t.js → tab-store-CJuJRapl.js} +1 -1
  184. package/dist/web/assets/team-member-sheet-LkAFSCvb.js +2 -0
  185. package/dist/web/assets/team-member-window-content-T4Q5JI-G.js +1 -0
  186. package/dist/web/assets/{templ-MlpvJx4a.js → templ-CSdqVobu.js} +1 -1
  187. package/dist/web/assets/terminal-tab-Bb2rZegQ.js +3 -0
  188. package/dist/web/assets/{tex-0loAoXJG.js → tex-DzSJ4kcZ.js} +1 -1
  189. package/dist/web/assets/text-wrap-CBT4Gxtg.js +1 -0
  190. package/dist/web/assets/tool-cards-lhqhrDTT.js +8 -0
  191. package/dist/web/assets/trash-2-Bk4yYlck.js +1 -0
  192. package/dist/web/assets/treemap-KZPCXAKY-DUbnl9dz.js +1 -0
  193. package/dist/web/assets/triangle-alert-B8EYecpe.js +1 -0
  194. package/dist/web/assets/{ts-tags-pt-Ug0hK.js → ts-tags-C28w3bTg.js} +1 -1
  195. package/dist/web/assets/{twig-DOePpLOL.js → twig-i5jY3QXB.js} +1 -1
  196. package/dist/web/assets/upload-BNlX8D07.js +1 -0
  197. package/dist/web/assets/{use-blob-url-BKyVxOZw.js → use-blob-url-Dsq9OjTh.js} +1 -1
  198. package/dist/web/assets/{use-monaco-theme-DSCdlrjO.js → use-monaco-theme-BZvlsoBv.js} +1 -1
  199. package/dist/web/assets/use-open-team-member-DkiEjFYE.js +1 -0
  200. package/dist/web/assets/{use-websocket-iJfc7EbK.js → use-websocket-B8R50f7f.js} +1 -1
  201. package/dist/web/assets/{vendor-mermaid-DrwG0NYt.js → vendor-mermaid-By4AVvJY.js} +1 -1
  202. package/dist/web/assets/video-preview-m0-3p7QZ.js +1 -0
  203. package/dist/web/assets/{vue-D6f-rprj.js → vue-Ceyet_lv.js} +1 -1
  204. package/dist/web/assets/{vue-html-DEYRkS1V.js → vue-html-GuU7g_hg.js} +1 -1
  205. package/dist/web/assets/{vue-vine-CxSG2ojf.js → vue-vine-CxXoaJr2.js} +1 -1
  206. package/dist/web/assets/window-store-CsEW6jiE.js +1 -0
  207. package/dist/web/assets/{xml-DhrxbATj.js → xml-CbqOVhkP.js} +1 -1
  208. package/dist/web/assets/{xsl-CU0ZndUO.js → xsl-KfAmCauy.js} +1 -1
  209. package/dist/web/index.html +56 -27
  210. package/dist/web/sw.js +1 -1
  211. package/docs/code-standards.md +8 -0
  212. package/docs/codebase-summary.md +19 -5
  213. package/docs/design-guidelines.md +13 -2
  214. package/docs/project-roadmap.md +9 -0
  215. package/docs/system-architecture.md +83 -6
  216. package/package.json +1 -1
  217. package/src/web/components/chat/file-picker.tsx +5 -2
  218. package/src/web/components/chat/mode-selector.tsx +5 -2
  219. package/src/web/components/chat/model-selector.tsx +5 -2
  220. package/src/web/components/chat/model-thinking-selector.tsx +5 -2
  221. package/src/web/components/chat/provider-selector.tsx +5 -2
  222. package/src/web/components/chat/slash-command-picker.tsx +5 -2
  223. package/src/web/components/editor/code-editor.tsx +13 -3
  224. package/src/web/components/editor/conflict-editor.tsx +9 -0
  225. package/src/web/components/editor/diff-viewer.tsx +9 -0
  226. package/src/web/components/floating-window/floating-window.tsx +23 -15
  227. package/src/web/components/floating-window/pip/pip-caption-button.tsx +108 -0
  228. package/src/web/components/floating-window/pip/pip-focus-target.ts +58 -0
  229. package/src/web/components/floating-window/pip/pip-geometry.ts +46 -0
  230. package/src/web/components/floating-window/pip/pip-host.ts +156 -0
  231. package/src/web/components/floating-window/pip/pip-key-forward.ts +59 -0
  232. package/src/web/components/floating-window/pip/pip-resize-signal.ts +33 -0
  233. package/src/web/components/floating-window/pip/pip-style-copy.ts +108 -0
  234. package/src/web/components/floating-window/pip/pip-support.ts +33 -0
  235. package/src/web/components/floating-window/tab-host-window-content.tsx +80 -0
  236. package/src/web/components/floating-window/use-window-body-element.ts +67 -0
  237. package/src/web/components/floating-window/use-window-drag.ts +5 -0
  238. package/src/web/components/floating-window/use-window-gesture-context.ts +14 -0
  239. package/src/web/components/floating-window/use-window-resize.ts +5 -0
  240. package/src/web/components/floating-window/window-content-registry.ts +4 -16
  241. package/src/web/components/floating-window/window-layer.tsx +1 -2
  242. package/src/web/components/floating-window/window-persistence.ts +9 -2
  243. package/src/web/components/floating-window/window-pip-placeholder.tsx +31 -0
  244. package/src/web/components/floating-window/window-pip-registry.ts +69 -0
  245. package/src/web/components/floating-window/window-skin-chrome.tsx +21 -0
  246. package/src/web/components/floating-window/window-store-types.ts +8 -2
  247. package/src/web/components/layout/reparenting-tab.tsx +136 -0
  248. package/src/web/components/layout/tab-bar.tsx +2 -0
  249. package/src/web/components/layout/tab-pool-collect.ts +38 -2
  250. package/src/web/components/layout/tab-pool-registry.ts +48 -0
  251. package/src/web/components/layout/tab-pool.tsx +54 -168
  252. package/src/web/components/layout/tab-pop-out-menu-item.tsx +42 -0
  253. package/src/web/components/layout/use-window-panel-reconcile.ts +48 -0
  254. package/src/web/components/os-explorer/skins/macos-window-chrome.tsx +16 -7
  255. package/src/web/components/os-explorer/skins/windows-window-chrome.tsx +14 -8
  256. package/src/web/components/ui/context-menu.tsx +10 -3
  257. package/src/web/components/ui/dialog.tsx +10 -1
  258. package/src/web/components/ui/dropdown-menu.tsx +10 -3
  259. package/src/web/components/ui/mobile-bottom-sheet.tsx +7 -4
  260. package/src/web/components/ui/portal-container-context.tsx +40 -0
  261. package/src/web/components/ui/select.tsx +3 -1
  262. package/src/web/components/ui/tooltip.tsx +3 -1
  263. package/src/web/hooks/use-terminal.ts +24 -3
  264. package/src/web/stores/panel-store.ts +72 -7
  265. package/src/web/stores/panel-utils.ts +36 -0
  266. package/src/web/stores/window-panel-actions.ts +211 -0
  267. package/src/web/stores/window-panel-persistence.ts +115 -0
  268. package/src/web/stores/window-panel-reconcile.ts +97 -0
  269. package/dist/web/assets/ai-resource-editor-mdDKG-rw.js +0 -1
  270. package/dist/web/assets/api-client-CzABTreM.js +0 -1
  271. package/dist/web/assets/api-settings-nblja3Rk.js +0 -1
  272. package/dist/web/assets/architecture-PBZL5I3N-C7ra20CE.js +0 -1
  273. package/dist/web/assets/chat-tab-C060A94y.js +0 -15
  274. package/dist/web/assets/code-editor-WELegzdp.js +0 -10
  275. package/dist/web/assets/context-menu-Cq0u3SK9.js +0 -1
  276. package/dist/web/assets/database-viewer-DevnWTV4.js +0 -1
  277. package/dist/web/assets/diff-viewer-DGxVg1pD.js +0 -4
  278. package/dist/web/assets/docx-preview-Cx-zLwAw.js +0 -12
  279. package/dist/web/assets/explorer-body-j_4hVc34.js +0 -2
  280. package/dist/web/assets/explorer-window-content-DdrGwk3w.js +0 -1
  281. package/dist/web/assets/git-log-panel-CfpXRJcP.js +0 -1
  282. package/dist/web/assets/gitGraph-HDMCJU4V-D4hYLNJU.js +0 -1
  283. package/dist/web/assets/group-chat-tab-dYuuknLN.js +0 -1
  284. package/dist/web/assets/image-preview-Ss38ex8g.js +0 -1
  285. package/dist/web/assets/index-BiTiXgBZ.css +0 -2
  286. package/dist/web/assets/index-Ch8l9de-.js +0 -52
  287. package/dist/web/assets/info-3K5VOQVL-lRlrTlkb.js +0 -1
  288. package/dist/web/assets/keybindings-store-CDfTjwZX.js +0 -1
  289. package/dist/web/assets/markdown-renderer-CpRlpLHw.js +0 -1
  290. package/dist/web/assets/mobile-bottom-sheet-BUOJgiaZ.js +0 -1
  291. package/dist/web/assets/mobile-explorer-sheet-D1Bv9UCT.js +0 -1
  292. package/dist/web/assets/notification-store-KwTAZT8b.js +0 -1
  293. package/dist/web/assets/packet-RMMSAZCW-BIhk1mvp.js +0 -1
  294. package/dist/web/assets/panel-store-DCD82zc1.js +0 -1
  295. package/dist/web/assets/pdf-preview-dwRe54ht.js +0 -1
  296. package/dist/web/assets/pie-UPGHQEXC-SLS6i76l.js +0 -1
  297. package/dist/web/assets/process-table-CI-fnVsy.js +0 -1
  298. package/dist/web/assets/radar-KQ55EAFF-JJ6O1Er_.js +0 -1
  299. package/dist/web/assets/settings-tab-mPxrKkfm.js +0 -1
  300. package/dist/web/assets/sqlite-viewer-Cs-_D942.js +0 -1
  301. package/dist/web/assets/system-monitor-body-CV7-0hZG.js +0 -2
  302. package/dist/web/assets/system-monitor-tab-Ce-8Axhh.js +0 -1
  303. package/dist/web/assets/system-monitor-window-content-CetwYOQy.js +0 -1
  304. package/dist/web/assets/team-member-sheet-CjgaQjsZ.js +0 -2
  305. package/dist/web/assets/team-member-window-content-DNJiYWS7.js +0 -1
  306. package/dist/web/assets/terminal-tab-DF7521sT.js +0 -3
  307. package/dist/web/assets/tool-cards-DCAXGDJI.js +0 -8
  308. package/dist/web/assets/treemap-KZPCXAKY-Be3KNmns.js +0 -1
  309. package/dist/web/assets/use-open-team-member-H4k74HnV.js +0 -1
  310. package/dist/web/assets/video-preview-B0ZWpX0F.js +0 -1
  311. package/src/web/components/floating-window/default-window-chrome.tsx +0 -71
  312. package/src/web/components/os-explorer/skins/explorer-skin-chrome.tsx +0 -17
  313. /package/dist/web/assets/{abap-MRbmsXOs.js → abap-C6nB04tn.js} +0 -0
  314. /package/dist/web/assets/{actionscript-3-BDDHKqa4.js → actionscript-3-Vx4rw2sC.js} +0 -0
  315. /package/dist/web/assets/{ada-DpuV9KwV.js → ada-Ccd8vM20.js} +0 -0
  316. /package/dist/web/assets/{andromeeda-D6qUCKJo.js → andromeeda-DnBX5xMg.js} +0 -0
  317. /package/dist/web/assets/{apache-CX1NU_Tl.js → apache-B-9_sx0g.js} +0 -0
  318. /package/dist/web/assets/{apex-B4-aoQ3K.js → apex-_wPVBYoL.js} +0 -0
  319. /package/dist/web/assets/{api-client-BSB14J4w.js → api-client-aQb5hHE5.js} +0 -0
  320. /package/dist/web/assets/{applescript-Dm9NI6KR.js → applescript-CcvD-qr0.js} +0 -0
  321. /package/dist/web/assets/{apply-theme-BH_d4amk.js → apply-theme-BeLRfsSu.js} +0 -0
  322. /package/dist/web/assets/{ara-BGN8GAYn.js → ara-C40Ztoms.js} +0 -0
  323. /package/dist/web/assets/{asciidoc-s_yVuR3t.js → asciidoc-CybYkJV4.js} +0 -0
  324. /package/dist/web/assets/{asm-BzQdSvTe.js → asm-9eOKwzR0.js} +0 -0
  325. /package/dist/web/assets/{aurora-x-BJTLETG_.js → aurora-x-B5ZH4t7t.js} +0 -0
  326. /package/dist/web/assets/{awk-BQEGWxvX.js → awk-Dqilob-2.js} +0 -0
  327. /package/dist/web/assets/{ayu-dark-CpTORmLc.js → ayu-dark-CPgRhf5r.js} +0 -0
  328. /package/dist/web/assets/{ayu-light-D8PVj-e6.js → ayu-light-Do06Q52f.js} +0 -0
  329. /package/dist/web/assets/{ayu-mirage-DyElQHtm.js → ayu-mirage-_BhxcrxY.js} +0 -0
  330. /package/dist/web/assets/{ballerina-C82NkRtj.js → ballerina-DDwK54QW.js} +0 -0
  331. /package/dist/web/assets/{bat-0X7DtGI-.js → bat-BGyGlzGk.js} +0 -0
  332. /package/dist/web/assets/{beancount-Xgvy6YRl.js → beancount-CRWBdapI.js} +0 -0
  333. /package/dist/web/assets/{berry-CCT2pZcQ.js → berry-DbSFn2gO.js} +0 -0
  334. /package/dist/web/assets/{bibtex-CpXgZ9M_.js → bibtex-QpsV9gm9.js} +0 -0
  335. /package/dist/web/assets/{bicep-fkeSA62l.js → bicep-CxS8CUve.js} +0 -0
  336. /package/dist/web/assets/{bird2-Co7SeAI8.js → bird2-CuZhQzYR.js} +0 -0
  337. /package/dist/web/assets/{bot-CunPuEdW.js → bot-D6sx11y0.js} +0 -0
  338. /package/dist/web/assets/{c-BpmrTvJh.js → c-9bnDqE3g.js} +0 -0
  339. /package/dist/web/assets/{c3-BZ_Z0RrR.js → c3-JMZTrOhA.js} +0 -0
  340. /package/dist/web/assets/{cadence-B0GBC8OF.js → cadence-DsDNayJS.js} +0 -0
  341. /package/dist/web/assets/{can-open-in-ppm-omBzUBBq.js → can-open-in-ppm-BJfpynya.js} +0 -0
  342. /package/dist/web/assets/{catppuccin-frappe-DIt_xR7m.js → catppuccin-frappe-DYIKXXBe.js} +0 -0
  343. /package/dist/web/assets/{catppuccin-latte-Dw40AcqA.js → catppuccin-latte-IYYOnUJ8.js} +0 -0
  344. /package/dist/web/assets/{catppuccin-macchiato-BJ7DfVEF.js → catppuccin-macchiato-BrJ_7mfS.js} +0 -0
  345. /package/dist/web/assets/{catppuccin-mocha-NI2lfXzU.js → catppuccin-mocha-gzSu7v7-.js} +0 -0
  346. /package/dist/web/assets/{chevron-right-BLOtX8Vy.js → chevron-right-De-Wz5Lz.js} +0 -0
  347. /package/dist/web/assets/{circle-hjUGru6R.js → circle-BCy0AUCo.js} +0 -0
  348. /package/dist/web/assets/{clarity-F39L0xMJ.js → clarity-DLzsC0Hb.js} +0 -0
  349. /package/dist/web/assets/{clock-CvhF4DJP.js → clock-C1CQUQPZ.js} +0 -0
  350. /package/dist/web/assets/{clojure-DloMkd8K.js → clojure-DS1BvoTt.js} +0 -0
  351. /package/dist/web/assets/{cmake-CwerJun_.js → cmake-CDvsJwYp.js} +0 -0
  352. /package/dist/web/assets/{code-DDPoqVri.js → code-DJgYrFzm.js} +0 -0
  353. /package/dist/web/assets/{codeowners-CQyVz4Qf.js → codeowners-BjsYiflJ.js} +0 -0
  354. /package/dist/web/assets/{codeql-Bb229zuY.js → codeql-CG-7ARat.js} +0 -0
  355. /package/dist/web/assets/{common-lisp-KMlIwq5I.js → common-lisp-DSO1Lbh9.js} +0 -0
  356. /package/dist/web/assets/{copy-DKn11Pye.js → copy-BewHj66E.js} +0 -0
  357. /package/dist/web/assets/{coq-DHX_3IIo.js → coq-DYdh3oP_.js} +0 -0
  358. /package/dist/web/assets/{csharp-CEmCZv9Q.js → csharp-DxEBz5s0.js} +0 -0
  359. /package/dist/web/assets/{css-CqZqBD05.js → css-dal3Q-8C.js} +0 -0
  360. /package/dist/web/assets/{csv-l1g_V5MV.js → csv-CpqjMGiA.js} +0 -0
  361. /package/dist/web/assets/{csv-parser-CnS0wqr6.js → csv-parser-3umBA4NY.js} +0 -0
  362. /package/dist/web/assets/{cue-BrxRmilg.js → cue-DinoJ_5k.js} +0 -0
  363. /package/dist/web/assets/{cypher-rZkKwqZc.js → cypher-DzxqmkUW.js} +0 -0
  364. /package/dist/web/assets/{d-BALR-QuP.js → d-BxNwJuEC.js} +0 -0
  365. /package/dist/web/assets/{dark-plus-Cj7rVwh-.js → dark-plus-Clmv3V-0.js} +0 -0
  366. /package/dist/web/assets/{dart-CWQcdkXk.js → dart-BWVtXD35.js} +0 -0
  367. /package/dist/web/assets/{data-grid-types-CYvF-xK5.js → data-grid-types-B4n51Fck.js} +0 -0
  368. /package/dist/web/assets/{database-BH0urvbs.js → database-Y3ESDK4-.js} +0 -0
  369. /package/dist/web/assets/{dax-BNHD-QBA.js → dax-DsImuWgJ.js} +0 -0
  370. /package/dist/web/assets/{desktop-CN0IXPrP.js → desktop-B0jJuG2r.js} +0 -0
  371. /package/dist/web/assets/{diff-BtOXapES.js → diff-CWqAAxoE.js} +0 -0
  372. /package/dist/web/assets/{dist-DB1Oaqcc.js → dist-B-EXdSYE.js} +0 -0
  373. /package/dist/web/assets/{dist-Di6G_5jU.js → dist-C0eNNfbt.js} +0 -0
  374. /package/dist/web/assets/{docker-DNsAo_qO.js → docker-CYFCJdIL.js} +0 -0
  375. /package/dist/web/assets/{dotenv-D6Pl6aOU.js → dotenv-CKDUjURg.js} +0 -0
  376. /package/dist/web/assets/{download-zCATy4x4.js → download-DG3_9xXy.js} +0 -0
  377. /package/dist/web/assets/{dracula-C3m-w12D.js → dracula-CSoPspHE.js} +0 -0
  378. /package/dist/web/assets/{dracula-soft-BYqvXm6Z.js → dracula-soft-BuFjw5L1.js} +0 -0
  379. /package/dist/web/assets/{dream-maker-DZAPbPTi.js → dream-maker-B6PdDRZu.js} +0 -0
  380. /package/dist/web/assets/{emacs-lisp-Ao5SW8ay.js → emacs-lisp-CMcXvD0G.js} +0 -0
  381. /package/dist/web/assets/{everforest-dark-uC8QYotQ.js → everforest-dark-cU8-wYzi.js} +0 -0
  382. /package/dist/web/assets/{everforest-light-CTgsVNMr.js → everforest-light-KhorllqK.js} +0 -0
  383. /package/dist/web/assets/{fennel-WuBw6IR1.js → fennel-BCELZK87.js} +0 -0
  384. /package/dist/web/assets/{file-exclamation-point-COAwgNGw.js → file-exclamation-point-CZ4DiR75.js} +0 -0
  385. /package/dist/web/assets/{fish-Byy9dusu.js → fish-BQc0y_jy.js} +0 -0
  386. /package/dist/web/assets/{fluent-CDxb_sgw.js → fluent-BTINnwF6.js} +0 -0
  387. /package/dist/web/assets/{format-bytes-BE_W3UBg.js → format-bytes-WVcFxJuT.js} +0 -0
  388. /package/dist/web/assets/{fortran-free-form-DKWSTamT.js → fortran-free-form-BQim9wDz.js} +0 -0
  389. /package/dist/web/assets/{gdscript-prYHMgtD.js → gdscript-03w5u8un.js} +0 -0
  390. /package/dist/web/assets/{gdshader-D-RM-SQk.js → gdshader-Dp2daNzU.js} +0 -0
  391. /package/dist/web/assets/{genie-CowkJhej.js → genie-CoNcjPiD.js} +0 -0
  392. /package/dist/web/assets/{gherkin-CLFpoVYJ.js → gherkin-NrPOSPQL.js} +0 -0
  393. /package/dist/web/assets/{github-dark-default-BK_1Qgb8.js → github-dark-default-DOKw-1cI.js} +0 -0
  394. /package/dist/web/assets/{github-dark-dimmed-Cv9lj6f-.js → github-dark-dimmed-DJRNMkEA.js} +0 -0
  395. /package/dist/web/assets/{github-dark-high-contrast-CW5ZgIDh.js → github-dark-high-contrast-Bj7jJ_Gs.js} +0 -0
  396. /package/dist/web/assets/{github-dark-nW2F-RLd.js → github-dark-z4RE9ZqA.js} +0 -0
  397. /package/dist/web/assets/{github-light-D4PqBHGZ.js → github-light-B4k_yMFu.js} +0 -0
  398. /package/dist/web/assets/{github-light-default-B-cHtJJV.js → github-light-default-BHc-Uzhs.js} +0 -0
  399. /package/dist/web/assets/{github-light-high-contrast-Dt0HJq50.js → github-light-high-contrast-CHisIywL.js} +0 -0
  400. /package/dist/web/assets/{gleam-DwSyXJWP.js → gleam-CfbypZ4q.js} +0 -0
  401. /package/dist/web/assets/{gn-Cv5WEzHc.js → gn-YoAjyhJa.js} +0 -0
  402. /package/dist/web/assets/{gnuplot-D7bRdY_M.js → gnuplot-xVkc1f1c.js} +0 -0
  403. /package/dist/web/assets/{go-DiRVJ22U.js → go-GPCwP3Gu.js} +0 -0
  404. /package/dist/web/assets/{groovy-BHAgLTeO.js → groovy-Crh4Yww9.js} +0 -0
  405. /package/dist/web/assets/{gruvbox-dark-hard-C8QZ3gzY.js → gruvbox-dark-hard-BluUFuDS.js} +0 -0
  406. /package/dist/web/assets/{gruvbox-dark-medium-Dp1eeid2.js → gruvbox-dark-medium-Cxk1FWQp.js} +0 -0
  407. /package/dist/web/assets/{gruvbox-dark-soft-Cwq0dWVj.js → gruvbox-dark-soft-CHXMiFmj.js} +0 -0
  408. /package/dist/web/assets/{gruvbox-light-hard-CLQCq2-w.js → gruvbox-light-hard-B6eKPjAD.js} +0 -0
  409. /package/dist/web/assets/{gruvbox-light-medium-APHsh6Mo.js → gruvbox-light-medium-pDwMm1ut.js} +0 -0
  410. /package/dist/web/assets/{gruvbox-light-soft-CX-fYc64.js → gruvbox-light-soft-Cxu6kHqK.js} +0 -0
  411. /package/dist/web/assets/{haskell-C4Tw-TDa.js → haskell-C6JKHjbK.js} +0 -0
  412. /package/dist/web/assets/{haxe-B7fSduTQ.js → haxe-BuBNdF0a.js} +0 -0
  413. /package/dist/web/assets/{hcl-Bi3ho6yC.js → hcl-DZpDdGj2.js} +0 -0
  414. /package/dist/web/assets/{hjson-BXwae2M1.js → hjson-CBkhYRuo.js} +0 -0
  415. /package/dist/web/assets/{hlsl-CRuQLBSa.js → hlsl-C5nMxnp9.js} +0 -0
  416. /package/dist/web/assets/{horizon-DtdQ6qjv.js → horizon-VAFvA6R6.js} +0 -0
  417. /package/dist/web/assets/{horizon-bright-BXSF_uKq.js → horizon-bright-BC0xn7T3.js} +0 -0
  418. /package/dist/web/assets/{houston-C6ASpUjT.js → houston-BxrUivmz.js} +0 -0
  419. /package/dist/web/assets/{hy-BrWBHtHY.js → hy-DLtOXoaH.js} +0 -0
  420. /package/dist/web/assets/{image-gallery-CGvlv8zR.js → image-gallery-Gnf7TdCR.js} +0 -0
  421. /package/dist/web/assets/{imba-C_JJXckG.js → imba-BdpFXM2W.js} +0 -0
  422. /package/dist/web/assets/{ini-DEE_vSHQ.js → ini-BInJO_T0.js} +0 -0
  423. /package/dist/web/assets/{java-CnmpcjcT.js → java-Dxuddnkb.js} +0 -0
  424. /package/dist/web/assets/{javascript-C-M7sa2e.js → javascript-CVamJfLY.js} +0 -0
  425. /package/dist/web/assets/{json-BjZ3dAk6.js → json-BLZ0ozYk.js} +0 -0
  426. /package/dist/web/assets/{json5-BQ2vpqjp.js → json5-BnXzmMKs.js} +0 -0
  427. /package/dist/web/assets/{jsonc-C5MjoWGx.js → jsonc-CSgkSga7.js} +0 -0
  428. /package/dist/web/assets/{jsonl-JvhrmQJI.js → jsonl-CY5W2nF2.js} +0 -0
  429. /package/dist/web/assets/{jsonnet-C5pdZVuo.js → jsonnet-CEJYH3sF.js} +0 -0
  430. /package/dist/web/assets/{jssm-Db17uybX.js → jssm-CsJc7Uhk.js} +0 -0
  431. /package/dist/web/assets/{jsx-tJp2Cyqu.js → jsx-jCiRaHU7.js} +0 -0
  432. /package/dist/web/assets/{kanagawa-dragon-BculT_Y1.js → kanagawa-dragon-DfoA_GxX.js} +0 -0
  433. /package/dist/web/assets/{kanagawa-lotus-yQgHUGwU.js → kanagawa-lotus-BOLYJpWd.js} +0 -0
  434. /package/dist/web/assets/{kanagawa-wave-CyGoWN4d.js → kanagawa-wave-DfKlbT1G.js} +0 -0
  435. /package/dist/web/assets/{kdl-Bn8R1REF.js → kdl-CmssIFTi.js} +0 -0
  436. /package/dist/web/assets/{kotlin-DWughK73.js → kotlin-BRsNgp6x.js} +0 -0
  437. /package/dist/web/assets/{kusto--serPb0x.js → kusto-T8X9jUab.js} +0 -0
  438. /package/dist/web/assets/{laserwave-DfAPJ1tt.js → laserwave-DkJMVJ8Z.js} +0 -0
  439. /package/dist/web/assets/{lean-UAm1HOKl.js → lean-C65KGVPq.js} +0 -0
  440. /package/dist/web/assets/{less-Xj6Ka0fF.js → less-exIPdDlf.js} +0 -0
  441. /package/dist/web/assets/{lib-DgNcCtj3.js → lib-mC1NZfuw.js} +0 -0
  442. /package/dist/web/assets/{libesm-CPh1Av0r.js → libesm-DSutUtl1.js} +0 -0
  443. /package/dist/web/assets/{light-plus-BfS7gPcj.js → light-plus-DiHUXAZt.js} +0 -0
  444. /package/dist/web/assets/{llvm-DvWiVwvU.js → llvm-CJBnEzFM.js} +0 -0
  445. /package/dist/web/assets/{log-Bo5z9bNz.js → log-DxMyUMuP.js} +0 -0
  446. /package/dist/web/assets/{logo-CrIjcMZT.js → logo-CC9NKzca.js} +0 -0
  447. /package/dist/web/assets/{luau-C9TsYwNt.js → luau-Bw10I6zf.js} +0 -0
  448. /package/dist/web/assets/{make-GYq4qVbx.js → make-C_6M90m6.js} +0 -0
  449. /package/dist/web/assets/{markdown-p5mNledS.js → markdown-bR9_R-LF.js} +0 -0
  450. /package/dist/web/assets/{material-theme-CWYOVxsP.js → material-theme-BUx2Qujn.js} +0 -0
  451. /package/dist/web/assets/{material-theme-darker-BDGty7YH.js → material-theme-darker-CRJrPgKm.js} +0 -0
  452. /package/dist/web/assets/{material-theme-lighter-JbgOgV3n.js → material-theme-lighter-CUAYppPa.js} +0 -0
  453. /package/dist/web/assets/{material-theme-ocean-EMOpLpa2.js → material-theme-ocean-DuINF1fg.js} +0 -0
  454. /package/dist/web/assets/{material-theme-palenight-CY5hgm7h.js → material-theme-palenight-W6_icGCj.js} +0 -0
  455. /package/dist/web/assets/{matlab-C-He_NTH.js → matlab-rfqn_b3z.js} +0 -0
  456. /package/dist/web/assets/{mdx-Cr2TR5fj.js → mdx-Bh1B_YOJ.js} +0 -0
  457. /package/dist/web/assets/{mermaid-BYc0-B0U.js → mermaid-Dxf6Ya2k.js} +0 -0
  458. /package/dist/web/assets/{min-dark-CMJwqJqB.js → min-dark-CivZ2L0h.js} +0 -0
  459. /package/dist/web/assets/{min-light-Cx6vFiEX.js → min-light-B1Ykqtma.js} +0 -0
  460. /package/dist/web/assets/{mipsasm-Bjer5HwK.js → mipsasm-DynHaM0d.js} +0 -0
  461. /package/dist/web/assets/{mojo-t90PR-Y2.js → mojo-Clw5PbGH.js} +0 -0
  462. /package/dist/web/assets/{monokai-dci_PdCm.js → monokai-DFIooFZT.js} +0 -0
  463. /package/dist/web/assets/{moonbit-AAzI-Hd-.js → moonbit-DnBSZWGM.js} +0 -0
  464. /package/dist/web/assets/{move-kwBhnhrG.js → move-CCcL2PfL.js} +0 -0
  465. /package/dist/web/assets/{narrat-CXww2YQL.js → narrat-BDarg5Lk.js} +0 -0
  466. /package/dist/web/assets/{nextflow-groovy-CJXsuXGB.js → nextflow-groovy-DrZOeCNW.js} +0 -0
  467. /package/dist/web/assets/{night-owl-_GD204Wr.js → night-owl-BnZZCK7v.js} +0 -0
  468. /package/dist/web/assets/{night-owl-light-DNgkw3kl.js → night-owl-light-CEwBsVHS.js} +0 -0
  469. /package/dist/web/assets/{nix-BgiorKFd.js → nix-amCzOPMR.js} +0 -0
  470. /package/dist/web/assets/{nord-CaBmcxFC.js → nord-BIs2BC6q.js} +0 -0
  471. /package/dist/web/assets/{nushell-DUh4UGx1.js → nushell-Y02fo4yw.js} +0 -0
  472. /package/dist/web/assets/{objective-c-Cl9KU86S.js → objective-c-7xOZtWW1.js} +0 -0
  473. /package/dist/web/assets/{objective-cpp-DVkIA8A0.js → objective-cpp-eVtjUvVB.js} +0 -0
  474. /package/dist/web/assets/{ocaml-vvoHTak0.js → ocaml-Bi6ZwqG4.js} +0 -0
  475. /package/dist/web/assets/{odin-Cyjw8woZ.js → odin-8xf1Y0S9.js} +0 -0
  476. /package/dist/web/assets/{one-dark-pro-B1cviILi.js → one-dark-pro-hVv-_y_b.js} +0 -0
  477. /package/dist/web/assets/{one-light-BPGUJeYI.js → one-light-CJJ3MtHt.js} +0 -0
  478. /package/dist/web/assets/{openscad-BLMdTUU8.js → openscad-B2HcywLk.js} +0 -0
  479. /package/dist/web/assets/{pascal-i5niy3e7.js → pascal-C7fllV_7.js} +0 -0
  480. /package/dist/web/assets/{pkl-CuOV7SsU.js → pkl-qvLC1IWP.js} +0 -0
  481. /package/dist/web/assets/{plastic-Bf_zE5KL.js → plastic-BT1wHZv2.js} +0 -0
  482. /package/dist/web/assets/{plsql-cfqEtMD3.js → plsql-1MsmdmJD.js} +0 -0
  483. /package/dist/web/assets/{plus-BM-Ty0fp.js → plus-BhMZqFsN.js} +0 -0
  484. /package/dist/web/assets/{po-CFJcWgjr.js → po-BigskytD.js} +0 -0
  485. /package/dist/web/assets/{poimandres-G5YoaIFf.js → poimandres-DuklniF7.js} +0 -0
  486. /package/dist/web/assets/{polar-rcjs3i9R.js → polar-e2pjN_sp.js} +0 -0
  487. /package/dist/web/assets/{postcss-CBKY1FTZ.js → postcss-DtAeYjWw.js} +0 -0
  488. /package/dist/web/assets/{powerquery-Db7SXLbO.js → powerquery-Cr2PtehI.js} +0 -0
  489. /package/dist/web/assets/{powershell-LFy3MUTP.js → powershell-BxFTGLJ4.js} +0 -0
  490. /package/dist/web/assets/{prisma-BE8GR1lH.js → prisma-COWJiwdZ.js} +0 -0
  491. /package/dist/web/assets/{prolog-DOn5lR1e.js → prolog-DFvGKRx6.js} +0 -0
  492. /package/dist/web/assets/{proto-wr-TpAK_.js → proto-CcK80lFt.js} +0 -0
  493. /package/dist/web/assets/{puppet-D2Dkv62u.js → puppet-BF60bZ4F.js} +0 -0
  494. /package/dist/web/assets/{purescript-DvgJgPdy.js → purescript-zL_69MzU.js} +0 -0
  495. /package/dist/web/assets/{python-C7TlkHhK.js → python-CIwKhfb_.js} +0 -0
  496. /package/dist/web/assets/{qmldir-CtZMwhcW.js → qmldir-CXNe04Lo.js} +0 -0
  497. /package/dist/web/assets/{qss-dNZ2btnl.js → qss-C8lAWe6G.js} +0 -0
  498. /package/dist/web/assets/{r-BlqnNkHS.js → r-CL5ZVL3_.js} +0 -0
  499. /package/dist/web/assets/{racket-CzRQrGc4.js → racket-BBfh0uh0.js} +0 -0
  500. /package/dist/web/assets/{raku-BwutWhBF.js → raku-o6E8R5Q3.js} +0 -0
  501. /package/dist/web/assets/{react-I_EwPIZi.js → react-CBTnT4sY.js} +0 -0
  502. /package/dist/web/assets/{red-BMXMywmL.js → red-GomRF2Xp.js} +0 -0
  503. /package/dist/web/assets/{reg-BqOKrIOw.js → reg-_ffDIvx9.js} +0 -0
  504. /package/dist/web/assets/{regexp-Bero1BN2.js → regexp-Bl5sF65W.js} +0 -0
  505. /package/dist/web/assets/{rel-BXKWIElA.js → rel-DgMdqDuj.js} +0 -0
  506. /package/dist/web/assets/{resolve-theme-B9ABAH_3.js → resolve-theme-CRt_7wpd.js} +0 -0
  507. /package/dist/web/assets/{riscv-BbbBYJBo.js → riscv-8b3-Ye4X.js} +0 -0
  508. /package/dist/web/assets/{ron-BtVTWW4b.js → ron-DrmU1KHP.js} +0 -0
  509. /package/dist/web/assets/{rose-pine-hvkvQzvU.js → rose-pine-C_-E2tF1.js} +0 -0
  510. /package/dist/web/assets/{rose-pine-dawn-D7lwhUei.js → rose-pine-dawn-DEfhNlFH.js} +0 -0
  511. /package/dist/web/assets/{rose-pine-moon-CoHDmsIw.js → rose-pine-moon-BdvX3gdn.js} +0 -0
  512. /package/dist/web/assets/{rosmsg-CdaZFgI8.js → rosmsg-B6GhGpd5.js} +0 -0
  513. /package/dist/web/assets/{rust-Dy2qsphD.js → rust-DmC97M1-.js} +0 -0
  514. /package/dist/web/assets/{sass-Bz7NVxDb.js → sass-B0tJOHLM.js} +0 -0
  515. /package/dist/web/assets/{save-C4z1p51e.js → save-CtIGOjmx.js} +0 -0
  516. /package/dist/web/assets/{scala-sXSwsNyq.js → scala-n8zaFOXv.js} +0 -0
  517. /package/dist/web/assets/{scheme-DS7TUbN7.js → scheme-BKD9ztBU.js} +0 -0
  518. /package/dist/web/assets/{sdbl-iISFvIep.js → sdbl-D8gB5-rS.js} +0 -0
  519. /package/dist/web/assets/{shellscript-BkIl4ApC.js → shellscript-BfXlf_Ao.js} +0 -0
  520. /package/dist/web/assets/{shield-check-C5laObJv.js → shield-check-B0iGUiOK.js} +0 -0
  521. /package/dist/web/assets/{shield-off-DULFtyLS.js → shield-off-BNLWBhcq.js} +0 -0
  522. /package/dist/web/assets/{slack-dark-B1eg0_m2.js → slack-dark-CylEddse.js} +0 -0
  523. /package/dist/web/assets/{slack-ochin-mdkc1ldu.js → slack-ochin-w8wg8vuC.js} +0 -0
  524. /package/dist/web/assets/{smalltalk-CORtd03t.js → smalltalk-hiAXA64u.js} +0 -0
  525. /package/dist/web/assets/{snazzy-light-Bc6Q2G89.js → snazzy-light-BwlV3Xty.js} +0 -0
  526. /package/dist/web/assets/{solarized-dark-CF83zRXM.js → solarized-dark-vmNGdykz.js} +0 -0
  527. /package/dist/web/assets/{solarized-light-BoKQZaYU.js → solarized-light-DGv_0JXq.js} +0 -0
  528. /package/dist/web/assets/{solidity-DOgi1N4w.js → solidity-Y7QSH0B1.js} +0 -0
  529. /package/dist/web/assets/{sparkles-Dqsf3hq6.js → sparkles-Dh-_J2Rd.js} +0 -0
  530. /package/dist/web/assets/{splunk-BXfw5ZLy.js → splunk-BtgpLjHi.js} +0 -0
  531. /package/dist/web/assets/{sql-BcVs-eX4.js → sql-CRHYhOia.js} +0 -0
  532. /package/dist/web/assets/{ssh-config-CLCtNkkd.js → ssh-config-DOqSs3au.js} +0 -0
  533. /package/dist/web/assets/{stylus-DdP992aO.js → stylus-crCAEaBT.js} +0 -0
  534. /package/dist/web/assets/{swift-BnGb6Lgc.js → swift-eE3rT7TC.js} +0 -0
  535. /package/dist/web/assets/{synthwave-84-cg9264l9.js → synthwave-84-BWy14LBX.js} +0 -0
  536. /package/dist/web/assets/{system-verilog-GbHpszs3.js → system-verilog-DC0-DZM4.js} +0 -0
  537. /package/dist/web/assets/{systemd-Dz-bNsDQ.js → systemd-to5p6N8I.js} +0 -0
  538. /package/dist/web/assets/{table-CHmxuh6M.js → table-Bbc783ko.js} +0 -0
  539. /package/dist/web/assets/{talonscript-CFIidoBA.js → talonscript-DoTcU8wm.js} +0 -0
  540. /package/dist/web/assets/{tasl-Cu-TRTKx.js → tasl-cNZvUs95.js} +0 -0
  541. /package/dist/web/assets/{tcl-DwCHCB1K.js → tcl-mZE8sZH8.js} +0 -0
  542. /package/dist/web/assets/{terraform-BzZw4T1z.js → terraform-CqHPpIfu.js} +0 -0
  543. /package/dist/web/assets/{tokyo-night-RKsj2-tv.js → tokyo-night-Tp2rTIZd.js} +0 -0
  544. /package/dist/web/assets/{toml-CirbOgDP.js → toml-CU_vscgn.js} +0 -0
  545. /package/dist/web/assets/{tsv-CraRcWdU.js → tsv-ik7iFB9D.js} +0 -0
  546. /package/dist/web/assets/{tsx-CjFg0lgw.js → tsx-BMvvMKiv.js} +0 -0
  547. /package/dist/web/assets/{turtle-B-WBIOa6.js → turtle-DBqKCq9o.js} +0 -0
  548. /package/dist/web/assets/{typescript-MpLarYn1.js → typescript-DXJDmMZZ.js} +0 -0
  549. /package/dist/web/assets/{typespec-B7QlHMZ_.js → typespec-CBseCMtZ.js} +0 -0
  550. /package/dist/web/assets/{typst-CcHSKFZj.js → typst-4oY25U9y.js} +0 -0
  551. /package/dist/web/assets/{use-is-mobile-BXGVvczu.js → use-is-mobile-D1weanbj.js} +0 -0
  552. /package/dist/web/assets/{utils-DoY4yTP-.js → utils-BNRH507E.js} +0 -0
  553. /package/dist/web/assets/{v-xTGhWZuD.js → v-BXaZ_1oy.js} +0 -0
  554. /package/dist/web/assets/{vala-DwebjH3H.js → vala-BImWJE7z.js} +0 -0
  555. /package/dist/web/assets/{vb-BxJT2RAy.js → vb-CLfj2_sy.js} +0 -0
  556. /package/dist/web/assets/{vendor-xterm-CU6zIYMB.js → vendor-xterm-_yyu5n32.js} +0 -0
  557. /package/dist/web/assets/{verilog-CvV6RHPD.js → verilog-BWa8Ed2b.js} +0 -0
  558. /package/dist/web/assets/{vesper-CY3qd7E_.js → vesper-BGj1cg6m.js} +0 -0
  559. /package/dist/web/assets/{vhdl-B9ZX-sUL.js → vhdl-mByK7mlx.js} +0 -0
  560. /package/dist/web/assets/{viml-Y42h_ExQ.js → viml-CugmlW5g.js} +0 -0
  561. /package/dist/web/assets/{vitesse-black-DkXP6Sv-.js → vitesse-black-vPdpy9TL.js} +0 -0
  562. /package/dist/web/assets/{vitesse-dark-B9CkIB6r.js → vitesse-dark-BuQK3dUh.js} +0 -0
  563. /package/dist/web/assets/{vitesse-light-C7DHrJCK.js → vitesse-light-B3nz1XL9.js} +0 -0
  564. /package/dist/web/assets/{vyper-Cnd9s5j-.js → vyper-DH_GTIHG.js} +0 -0
  565. /package/dist/web/assets/{wasm-DQE71XTB.js → wasm-C-LF9GjX.js} +0 -0
  566. /package/dist/web/assets/{wasm-iWe7Fzjc.js → wasm-DfVbVJlW.js} +0 -0
  567. /package/dist/web/assets/{wenyan-Bc5Pnm9l.js → wenyan-CzQkHyHx.js} +0 -0
  568. /package/dist/web/assets/{wgsl-D-YUAWkP.js → wgsl-Du_M1DW9.js} +0 -0
  569. /package/dist/web/assets/{wikitext-DYQDUYf2.js → wikitext-BWN_w5S7.js} +0 -0
  570. /package/dist/web/assets/{wit-P6u7mfwy.js → wit-BR13v5HD.js} +0 -0
  571. /package/dist/web/assets/{wolfram-6SXLUqao.js → wolfram-BoXxp_Xl.js} +0 -0
  572. /package/dist/web/assets/{x-BcqfTY_7.js → x-nhriOX9o.js} +0 -0
  573. /package/dist/web/assets/{yaml-CQiMLVcZ.js → yaml-DpR_EF-d.js} +0 -0
  574. /package/dist/web/assets/{zenscript-DFMywo_P.js → zenscript-C-EdUtUd.js} +0 -0
  575. /package/dist/web/assets/{zig-CtAjaIiF.js → zig-BD4eA5nU.js} +0 -0
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import { clampRect, type Bounds, type Rect } from "./window-geometry";
10
+ import { WINDOW_KINDS } from "./window-store-types";
10
11
  import type { WindowKind, WindowRuntimeState, WindowVisualState } from "./window-store-types";
11
12
 
12
13
  const STORAGE_KEY = "ppm-windows";
@@ -20,7 +21,13 @@ export interface PersistedWindow {
20
21
  payload?: Record<string, unknown>;
21
22
  }
22
23
 
23
- const KINDS: WindowKind[] = ["explorer", "system-monitor"];
24
+ /**
25
+ * Kinds that may come back after a reload. Derived from WINDOW_KINDS so a new kind is
26
+ * restorable by default; `team-member` is the one exclusion, because its body streams a
27
+ * live subagent session that no longer exists after a reload — restoring it would open
28
+ * an empty shell the user never asked for.
29
+ */
30
+ const RESTORABLE_KINDS: readonly WindowKind[] = WINDOW_KINDS.filter((k) => k !== "team-member");
24
31
  const STATES: WindowVisualState[] = ["normal", "maximized", "minimized"];
25
32
 
26
33
  function isRect(v: unknown): v is Rect {
@@ -79,7 +86,7 @@ export function loadWindowRects(bounds: Bounds): PersistedWindow[] {
79
86
  for (const item of parsed) {
80
87
  if (!item || typeof item !== "object") continue;
81
88
  const w = item as Record<string, unknown>;
82
- if (typeof w.id !== "string" || !KINDS.includes(w.kind as WindowKind)) continue;
89
+ if (typeof w.id !== "string" || !RESTORABLE_KINDS.includes(w.kind as WindowKind)) continue;
83
90
  if (!isRect(w.rect) || !isSerialisable(w.payload)) continue;
84
91
  const state = STATES.includes(w.state as WindowVisualState)
85
92
  ? (w.state as WindowVisualState)
@@ -0,0 +1,31 @@
1
+ /**
2
+ * What a floating window shows while its body is playing in a picture-in-picture window.
3
+ *
4
+ * It takes the body's place in the frame's flex column — the body element is physically gone
5
+ * from here, so the two never fight over the space — and it stays in the MAIN document on
6
+ * purpose: it is the way back. An empty frame would just read as lost content.
7
+ */
8
+
9
+ import { cn } from "@/lib/utils";
10
+ import type { PipHandle } from "./pip/pip-host";
11
+
12
+ export function WindowPipPlaceholder({ pip, minimized }: { pip: PipHandle; minimized: boolean }) {
13
+ return (
14
+ <div
15
+ className={cn(
16
+ "relative flex-1 min-h-0 flex flex-col items-center justify-center gap-3",
17
+ "rounded-b-[8px] bg-panel text-center px-4",
18
+ minimized && "hidden",
19
+ )}
20
+ >
21
+ <span className="text-xs text-text-2">Playing in picture-in-picture</span>
22
+ <button
23
+ type="button"
24
+ onClick={() => pip.detach()}
25
+ className="min-h-11 min-w-11 px-4 rounded-md border border-border bg-surface-elevated text-sm text-text can-hover:hover:bg-panel-2 transition-colors"
26
+ >
27
+ Bring back
28
+ </button>
29
+ </div>
30
+ );
31
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The one piece of state a floating window's chrome and its body must agree on, for every
3
+ * window kind.
4
+ *
5
+ * The titlebar and the body are DOM siblings rendered by the window frame, not parent and
6
+ * child, so React context cannot bridge them: the titlebar needs the body element to hand it
7
+ * to the PiP host, and the frame needs the resulting handle to show its placeholder. Both
8
+ * live here, keyed by WINDOW id, and both are dropped in the frame's layout cleanup.
9
+ *
10
+ * A tab is a third party — TabPool renders it through a portal into a slot inside the body,
11
+ * so it reads the handle from here too (by panel id) to point its Radix portals at the PiP
12
+ * document instead of the main one.
13
+ */
14
+
15
+ import { useCallback, useSyncExternalStore } from "react";
16
+ import { windowIdFromPanelId } from "@/stores/panel-utils";
17
+ import type { PipHandle } from "./pip/pip-host";
18
+
19
+ const slots = new Map<string, HTMLElement>();
20
+ const handles = new Map<string, PipHandle>();
21
+ const listeners = new Set<() => void>();
22
+
23
+ /** Publish (or, with `null`, retract) the body element a window would pop out. */
24
+ export function publishWindowSlot(windowId: string, el: HTMLElement | null): void {
25
+ if (el) slots.set(windowId, el);
26
+ else slots.delete(windowId);
27
+ }
28
+
29
+ /** The body element of a mounted window, or null. */
30
+ export function windowSlot(windowId: string): HTMLElement | null {
31
+ return slots.get(windowId) ?? null;
32
+ }
33
+
34
+ /** Record the PiP handle a window's body is currently living in (`null` clears it). */
35
+ export function setWindowPip(windowId: string, handle: PipHandle | null): void {
36
+ const current = handles.get(windowId) ?? null;
37
+ if (current === handle) return;
38
+ if (handle) handles.set(windowId, handle);
39
+ else handles.delete(windowId);
40
+ for (const notify of listeners) notify();
41
+ }
42
+
43
+ /** The PiP handle for a window, or null when its body is docked in the window. */
44
+ export function windowPip(windowId: string | null | undefined): PipHandle | null {
45
+ return windowId ? (handles.get(windowId) ?? null) : null;
46
+ }
47
+
48
+ function subscribe(onChange: () => void): () => void {
49
+ listeners.add(onChange);
50
+ return () => {
51
+ listeners.delete(onChange);
52
+ };
53
+ }
54
+
55
+ /** Re-renders when the window's PiP handle appears or goes away. */
56
+ export function useWindowPip(windowId: string | null | undefined): PipHandle | null {
57
+ const snapshot = useCallback(() => windowPip(windowId), [windowId]);
58
+ return useSyncExternalStore(subscribe, snapshot);
59
+ }
60
+
61
+ /**
62
+ * Portal target for a tab rendered into `panelId`: the PiP document's body while that
63
+ * panel's window is popped out, otherwise `undefined` (the document default). Never `null` —
64
+ * Radix reads `null` as "render no portal at all".
65
+ */
66
+ export function usePipPortalContainer(panelId: string): HTMLElement | undefined {
67
+ const handle = useWindowPip(windowIdFromPanelId(panelId));
68
+ return handle?.pipWindow.document.body;
69
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The single titlebar every floating window wears, whatever its kind.
3
+ *
4
+ * It resolves the active OS skin (Settings override, otherwise the host platform) and
5
+ * delegates to that skin's chrome, so an explorer, a system monitor, a team-member session
6
+ * and a detached tab are visually the same window — the complaint that produced this file
7
+ * was two kinds shipping two different titlebars.
8
+ *
9
+ * `FloatingWindow` renders the chrome directly with no `<Suspense>` around it, so this entry
10
+ * point cannot be `lazy()` the way a window body is: it has to resolve synchronously, which
11
+ * is exactly what a small wrapper component (rather than a whole feature body) affords.
12
+ */
13
+
14
+ import { useExplorerSkin } from "@/components/os-explorer/skins/use-explorer-skin";
15
+ import type { WindowChromeProps } from "./window-chrome-contract";
16
+
17
+ export function WindowSkinChrome(props: WindowChromeProps) {
18
+ const skin = useExplorerSkin();
19
+ const Chrome = skin.chrome;
20
+ return <Chrome {...props} />;
21
+ }
@@ -2,8 +2,14 @@
2
2
 
3
3
  import type { Rect } from "./window-geometry";
4
4
 
5
- /** Content families the layer can host. The registry maps each kind to its body component. */
6
- export type WindowKind = "explorer" | "team-member" | "system-monitor";
5
+ /**
6
+ * Content families the layer can host. The registry maps each kind to its body component.
7
+ * Single source of truth: the persistence layer filters this list instead of repeating it,
8
+ * so a new kind can never be silently dropped on reload.
9
+ */
10
+ export const WINDOW_KINDS = ["explorer", "team-member", "system-monitor", "tab-host"] as const;
11
+
12
+ export type WindowKind = (typeof WINDOW_KINDS)[number];
7
13
 
8
14
  export type WindowVisualState = "normal" | "maximized" | "minimized";
9
15
 
@@ -0,0 +1,136 @@
1
+ /**
2
+ * ReparentingTab — one tab component, mounted once, physically moved between panel slots.
3
+ *
4
+ * The wrapper element is created imperatively and never re-created, and the tab renders
5
+ * into it through a portal. That is what makes the node portable: React attaches its
6
+ * event listeners to the portal container itself, so they keep working after the wrapper
7
+ * is moved into a panel slot — including a slot that lives in another document, where
8
+ * the app root's delegated listeners would never match.
9
+ *
10
+ * The wrapper's placement is owned here (hidden container ⇄ slot); its children are owned
11
+ * by React. Nothing outside may re-create the wrapper: a new container element would
12
+ * remount the tab and destroy exactly the state (xterm buffer, Monaco undo stack, chat
13
+ * scroll) this component exists to preserve.
14
+ */
15
+ import { useLayoutEffect, useRef, Suspense, type LazyExoticComponent, type ComponentType } from "react";
16
+ import { createPortal } from "react-dom";
17
+ import { Loader2 } from "lucide-react";
18
+ import { usePanelStore } from "@/stores/panel-store";
19
+ import { DOCK_PANEL_ID, isWindowPanelId } from "@/stores/panel-utils";
20
+ import { PortalContainerProvider } from "@/components/ui/portal-container-context";
21
+ import { usePipPortalContainer } from "@/components/floating-window/window-pip-registry";
22
+ import { slotRegistry } from "./tab-pool-registry";
23
+
24
+ export interface ReparentingTabProps {
25
+ tabId: string;
26
+ panelId: string;
27
+ component: LazyExoticComponent<ComponentType<{ metadata?: Record<string, unknown>; tabId?: string }>>;
28
+ metadata?: Record<string, unknown>;
29
+ isActive: boolean;
30
+ /** Off-screen parent the wrapper lives in whenever its panel has no slot mounted. */
31
+ hiddenContainer: HTMLDivElement;
32
+ }
33
+
34
+ export function ReparentingTab({
35
+ tabId,
36
+ panelId,
37
+ component: Component,
38
+ metadata,
39
+ isActive,
40
+ hiddenContainer,
41
+ }: ReparentingTabProps) {
42
+ const wrapperRef = useRef<HTMLDivElement | null>(null);
43
+ if (!wrapperRef.current) {
44
+ const el = document.createElement("div");
45
+ el.className = "absolute inset-0";
46
+ el.dataset.tabPoolId = tabId;
47
+ wrapperRef.current = el;
48
+ }
49
+ const wrapper = wrapperRef.current;
50
+
51
+ // Written during render, before any effect, so the click listener below always reads
52
+ // the panel the tab lives in NOW — a re-docked tab must focus its new panel.
53
+ const panelIdRef = useRef(panelId);
54
+ panelIdRef.current = panelId;
55
+
56
+ // Mount the wrapper and own its removal. The listener is native and capturing because
57
+ // the tab content is DOM-reparented out of the panel's fiber subtree: the panel never
58
+ // sees clicks on the content body, so focus is set here, where the panel is known.
59
+ useLayoutEffect(() => {
60
+ if (!wrapper.parentElement) hiddenContainer.appendChild(wrapper);
61
+ const onMouseDown = () => {
62
+ const pid = panelIdRef.current;
63
+ // Off-grid panels are skipped: focus decides where the next tab opens, and it may
64
+ // never land in the dock or inside a floating window.
65
+ if (pid === DOCK_PANEL_ID || isWindowPanelId(pid)) return;
66
+ usePanelStore.getState().setFocusedPanel(pid);
67
+ };
68
+ wrapper.addEventListener("mousedown", onMouseDown, true);
69
+ return () => {
70
+ wrapper.removeEventListener("mousedown", onMouseDown, true);
71
+ wrapper.remove();
72
+ };
73
+ }, [wrapper, hiddenContainer]);
74
+
75
+ useLayoutEffect(() => {
76
+ wrapper.style.display = isActive ? "" : "none";
77
+ }, [wrapper, isActive]);
78
+
79
+ // Imperatively move the wrapper into the correct panel slot.
80
+ // appendChild on an already-mounted node moves it (DOM spec — no clone/destroy).
81
+ // useLayoutEffect runs before paint, so the user never sees the off-screen state.
82
+ // No deps — must run every render because React's reconciliation may call
83
+ // insertBefore() to reorder keyed children, moving reparented nodes back
84
+ // to the hidden container. The early-return guard keeps this cheap.
85
+ useLayoutEffect(() => {
86
+ const slot = slotRegistry.get(panelId);
87
+
88
+ // Panel slot not mounted (e.g., mobile renders only the focused panel).
89
+ // Move wrapper back to hidden container so it doesn't overlap in the wrong slot.
90
+ if (!slot) {
91
+ if (wrapper.parentElement !== hiddenContainer) hiddenContainer.appendChild(wrapper);
92
+ return;
93
+ }
94
+
95
+ if (wrapper.parentElement === slot) return;
96
+
97
+ // Save scroll positions — appendChild resets them during the DOM move
98
+ const scrollables: { el: Element; top: number; left: number }[] = [];
99
+ wrapper.querySelectorAll("*").forEach((el) => {
100
+ if (el.scrollTop || el.scrollLeft) {
101
+ scrollables.push({ el, top: el.scrollTop, left: el.scrollLeft });
102
+ }
103
+ });
104
+
105
+ slot.appendChild(wrapper);
106
+
107
+ // Restore scroll positions synchronously before paint
108
+ for (const { el, top, left } of scrollables) {
109
+ el.scrollTop = top;
110
+ el.scrollLeft = left;
111
+ }
112
+ });
113
+
114
+ // Portal target for the tab's own dropdowns, tooltips and sheets. It belongs here and
115
+ // not in the floating-window body: the wrapper's React parent is this component, so a
116
+ // provider mounted around the window body would never reach the tab's primitives, and
117
+ // a menu opened in a picture-in-picture window would render in the main one — off
118
+ // screen, unreachable, and stealing the click. `undefined` while docked, which is the
119
+ // document default.
120
+ const portalContainer = usePipPortalContainer(panelId);
121
+
122
+ return createPortal(
123
+ <PortalContainerProvider container={portalContainer}>
124
+ <Suspense
125
+ fallback={
126
+ <div className="flex items-center justify-center h-full">
127
+ <Loader2 className="size-6 animate-spin text-primary" />
128
+ </div>
129
+ }
130
+ >
131
+ <Component metadata={metadata} tabId={tabId} />
132
+ </Suspense>
133
+ </PortalContainerProvider>,
134
+ wrapper,
135
+ );
136
+ }
@@ -40,6 +40,7 @@ import { useTabOverflow, getHiddenUnreadDirection } from "@/hooks/use-tab-overfl
40
40
  import { useSettingsStore } from "@/stores/settings-store";
41
41
  import { tabRowClass, tabAddButtonClass } from "@/lib/tab-bar-style";
42
42
  import { DraggableTab } from "./draggable-tab";
43
+ import { TabPopOutMenuItem } from "./tab-pop-out-menu-item";
43
44
  import { cn } from "@/lib/utils";
44
45
  import type { Tab } from "@/stores/tab-store";
45
46
  import { downloadFile } from "@/lib/file-download";
@@ -394,6 +395,7 @@ export const TabBar = memo(function TabBar({ panelId }: TabBarProps) {
394
395
  tagColor={sessionId ? sessionTagMap[sessionId]?.color : undefined}
395
396
  extraMenuContent={
396
397
  <>
398
+ <TabPopOutMenuItem tab={tab} panelId={effectivePanelId} />
397
399
  {dockMoveMenuItems(tab)}
398
400
  {compareMenuItems(tab)}
399
401
  {sessionId && !notiType && (
@@ -11,7 +11,7 @@
11
11
  * characterization test proves it by asserting the same outputs.
12
12
  */
13
13
  import type { Panel } from "@/stores/panel-utils";
14
- import { DOCK_PANEL_ID } from "@/stores/panel-utils";
14
+ import { DOCK_PANEL_ID, isWindowPanelId } from "@/stores/panel-utils";
15
15
  import type { TabType } from "@/stores/tab-store";
16
16
 
17
17
  export interface TabEntry {
@@ -98,6 +98,38 @@ export function collectFromDock(
98
98
  }
99
99
  }
100
100
 
101
+ /**
102
+ * Collect tab entries from the off-grid panels that host detached tabs (`__win__:*`),
103
+ * deduplicating via seenTabs.
104
+ *
105
+ * Without this pass a popped-out tab is in neither a grid nor the dock, so TabPool would
106
+ * mount it nowhere and the floating window would stay empty.
107
+ *
108
+ * WHY no projectId filter: like the dock, a window panel is global — a detached tab stays
109
+ * visible across a project switch, because a window the user pulled out explicitly
110
+ * vanishing on switch reads as data loss.
111
+ */
112
+ export function collectFromWindowPanels(
113
+ panels: Record<string, Panel>,
114
+ seenTabs: Set<string>,
115
+ tabEntries: TabEntry[],
116
+ ): void {
117
+ for (const [panelId, panel] of Object.entries(panels)) {
118
+ if (!isWindowPanelId(panelId)) continue;
119
+ for (const tab of panel.tabs) {
120
+ if (seenTabs.has(tab.id)) continue;
121
+ seenTabs.add(tab.id);
122
+ tabEntries.push({
123
+ tabId: tab.id,
124
+ panelId,
125
+ type: tab.type,
126
+ metadata: tab.metadata,
127
+ isActive: tab.id === panel.activeTabId,
128
+ });
129
+ }
130
+ }
131
+ }
132
+
101
133
  /**
102
134
  * Collect all tab entries across active and non-active projects, returning
103
135
  * the full deduplicated list (sorted by tabId for stable ordering).
@@ -105,7 +137,7 @@ export function collectFromDock(
105
137
  * Collection order (intentional — determines dedup precedence):
106
138
  * 1. Active project's live grid (highest priority)
107
139
  * 2. Non-active projects' snapshotted grids (keep-alive)
108
- * 3. Dock panel (__dock__) (lowest priority — grid wins on collision)
140
+ * 3. Window panels (__win__:*) and the dock panel (__dock__) (grid wins on collision)
109
141
  *
110
142
  * This mirrors what TabPool does before passing entries to ReparentingTab.
111
143
  */
@@ -127,6 +159,10 @@ export function collectTabEntries(
127
159
  collectFromGrid(projectGrid, projectName, false, panels, seenTabs, tabEntries);
128
160
  }
129
161
 
162
+ // Off-grid panels last, so a tab that is briefly in both a grid panel and an off-grid
163
+ // one (mid-move) renders in the grid slot the user just dropped it into.
164
+ collectFromWindowPanels(panels, seenTabs, tabEntries);
165
+
130
166
  // Dock panel — collected last so grid tabs always win dedup.
131
167
  // Missing __dock__ (e.g. legacy state, tests without dock) is safe to skip.
132
168
  const dockPanel = panels[DOCK_PANEL_ID];
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Slot registry — panels publish the element their tab content should live in.
3
+ *
4
+ * Split out of tab-pool.tsx so the pool and the reparenting wrapper can both reach it
5
+ * without importing each other.
6
+ *
7
+ * Registering an element is a subscription event, not a render input: TabPool subscribes
8
+ * through useSyncExternalStore, so a panel mounting late still gets its tab moved in.
9
+ */
10
+ type SlotListener = () => void;
11
+
12
+ class SlotRegistry {
13
+ private slots = new Map<string, HTMLDivElement>();
14
+ private listeners = new Set<SlotListener>();
15
+ private version = 0;
16
+
17
+ register(panelId: string, el: HTMLDivElement | null) {
18
+ if (el) {
19
+ if (this.slots.get(panelId) === el) return;
20
+ this.slots.set(panelId, el);
21
+ } else {
22
+ if (!this.slots.has(panelId)) return;
23
+ this.slots.delete(panelId);
24
+ }
25
+ this.version++;
26
+ this.listeners.forEach((fn) => fn());
27
+ }
28
+
29
+ get(panelId: string): HTMLDivElement | undefined {
30
+ return this.slots.get(panelId);
31
+ }
32
+
33
+ subscribe(fn: SlotListener): () => void {
34
+ this.listeners.add(fn);
35
+ return () => this.listeners.delete(fn);
36
+ }
37
+
38
+ getVersion(): number {
39
+ return this.version;
40
+ }
41
+ }
42
+
43
+ export const slotRegistry = new SlotRegistry();
44
+
45
+ /** Called by a panel (grid, dock or floating window) to register its content slot. */
46
+ export function registerPanelSlot(panelId: string, el: HTMLDivElement | null) {
47
+ slotRegistry.register(panelId, el);
48
+ }