@hienlh/ppm 0.18.9 → 0.18.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (596) hide show
  1. package/.spike/cdp-client.ts +116 -0
  2. package/.spike/cleanup-ppm-workspace.mjs +44 -0
  3. package/.spike/group-protected-probe.ts +21 -0
  4. package/.spike/pip-eval.ts +17 -0
  5. package/.spike/pip-page-helpers.js +119 -0
  6. package/.spike/pip-results-editor-glue.json +105 -0
  7. package/.spike/pip-results-editor.json +158 -0
  8. package/.spike/pip-results-input-isolation.json +28 -0
  9. package/.spike/pip-results-key-probe.json +58 -0
  10. package/.spike/pip-results-listener-survival.json +98 -0
  11. package/.spike/pip-results-listeners.json +36 -0
  12. package/.spike/pip-results-pagehide.json +92 -0
  13. package/.spike/pip-results-resize.json +104 -0
  14. package/.spike/pip-results-terminal-debug.json +99 -0
  15. package/.spike/pip-results-terminal-v2.json +191 -0
  16. package/.spike/pip-results-terminal.json +220 -0
  17. package/.spike/pip-results-xterm-trace.json +73 -0
  18. package/.spike/pip-spike-common.ts +83 -0
  19. package/.spike/pip-spike-editor-glue.ts +82 -0
  20. package/.spike/pip-spike-editor.ts +129 -0
  21. package/.spike/pip-spike-input-isolation.ts +38 -0
  22. package/.spike/pip-spike-key-probe.ts +34 -0
  23. package/.spike/pip-spike-listener-survival.ts +54 -0
  24. package/.spike/pip-spike-listeners.ts +19 -0
  25. package/.spike/pip-spike-pagehide.ts +59 -0
  26. package/.spike/pip-spike-resize.ts +42 -0
  27. package/.spike/pip-spike-setup.ts +63 -0
  28. package/.spike/pip-spike-terminal-debug.ts +81 -0
  29. package/.spike/pip-spike-terminal-v2.ts +139 -0
  30. package/.spike/pip-spike-terminal.ts +169 -0
  31. package/.spike/pip-spike-xterm-trace.ts +36 -0
  32. package/.spike/probe-drag-memo-error.mjs +67 -0
  33. package/.spike/read-dev-db.ts +15 -0
  34. package/.spike/scratch-editor-target.ts +7 -0
  35. package/.spike/smoke-unified-chrome-pip.mjs +353 -0
  36. package/.spike/tunnel.err +63 -42
  37. package/.spike/vite-restart.err +663 -0
  38. package/.spike/w.err +569 -94
  39. package/CHANGELOG.md +25 -0
  40. package/assets/skills/ppm/SKILL.md +1 -1
  41. package/assets/skills/ppm/references/http-api.md +1 -1
  42. package/dist/web/assets/adaptive-context-menu-DGCKKeTy.js +1 -0
  43. package/dist/web/assets/ai-resource-editor-BOHHTTe7.js +1 -0
  44. package/dist/web/assets/ai-settings-section-BigC_nZR.js +1 -0
  45. package/dist/web/assets/{angular-html-Ctz0zN01.js → angular-html-BYPaydvh.js} +1 -1
  46. package/dist/web/assets/{angular-ts-QXHpgB1C.js → angular-ts-Bb4AMKlk.js} +1 -1
  47. package/dist/web/assets/api-client-DTZEgjBQ.js +1 -0
  48. package/dist/web/assets/{api-settings-kQHV6pYZ.js → api-settings-Bd3M4YpI.js} +1 -1
  49. package/dist/web/assets/api-settings-kd1j4iR8.js +1 -0
  50. package/dist/web/assets/{api-themes-CrK0tkW_.js → api-themes-Cpx419SL.js} +1 -1
  51. package/dist/web/assets/{apl-b9KVk-O4.js → apl-DB2VjFCS.js} +1 -1
  52. package/dist/web/assets/architecture-PBZL5I3N-8dCMT9r7.js +1 -0
  53. package/dist/web/assets/{astro-BlFEeGYr.js → astro-BeoJdVpk.js} +1 -1
  54. package/dist/web/assets/{audio-preview-CZLmhf__.js → audio-preview-BgFuTn-0.js} +1 -1
  55. package/dist/web/assets/{blade-CGkj2MUI.js → blade-Cf2q1sPf.js} +1 -1
  56. package/dist/web/assets/{bsl-CVsbb6ap.js → bsl-W1kOaNpu.js} +1 -1
  57. package/dist/web/assets/{button-BA_fJOtX.js → button-5zTrkEoN.js} +1 -1
  58. package/dist/web/assets/{cairo-BbIHl2iE.js → cairo-BoAZFcje.js} +1 -1
  59. package/dist/web/assets/chat-tab-E3bf_V8X.js +15 -0
  60. package/dist/web/assets/chevron-down-Dp0rpHb8.js +1 -0
  61. package/dist/web/assets/clipboard-7fw0Shic.js +1 -0
  62. package/dist/web/assets/{cobol-BWSGjmWb.js → cobol-B0Nm7RXj.js} +1 -1
  63. package/dist/web/assets/code-editor-BUlM2gXk.js +10 -0
  64. package/dist/web/assets/{coffee-CWGNOxds.js → coffee-BakMn3on.js} +1 -1
  65. package/dist/web/assets/{conflict-editor-CdH_h0vD.js → conflict-editor-BUs5k9q_.js} +4 -4
  66. package/dist/web/assets/context-menu-Bq92km4s.js +1 -0
  67. package/dist/web/assets/{cpp-DHGV24J2.js → cpp-BRAJQHK2.js} +1 -1
  68. package/dist/web/assets/{crystal-Vlwf2UMP.js → crystal-kqqO3zkK.js} +1 -1
  69. package/dist/web/assets/{csv-preview-CY_454vd.js → csv-preview-ByoDgLAZ.js} +1 -1
  70. package/dist/web/assets/{data-grid-overlay-editor-D9il5DZS.js → data-grid-overlay-editor-Brkf9z41.js} +1 -1
  71. package/dist/web/assets/database-viewer-Btc3h8Yu.js +1 -0
  72. package/dist/web/assets/dialog-DwtGlowE.js +1 -0
  73. package/dist/web/assets/diff-viewer-CZaDnR4w.js +4 -0
  74. package/dist/web/assets/docx-preview-DAD_vg59.js +12 -0
  75. package/dist/web/assets/{edge-Bhqk64zS.js → edge-Cq1ZKZuE.js} +1 -1
  76. package/dist/web/assets/{edit-diff-preview-gq6ALf2B.js → edit-diff-preview-B_VE7ppQ.js} +1 -1
  77. package/dist/web/assets/{elixir-D466WCFm.js → elixir-BM_JoJRk.js} +1 -1
  78. package/dist/web/assets/{elm-Bfs2qNPR.js → elm-Dw7oO08Y.js} +1 -1
  79. package/dist/web/assets/{erb-WI7jUaB6.js → erb-CfKOGAfk.js} +1 -1
  80. package/dist/web/assets/{erlang-BCBe8nCc.js → erlang-DlDmGVeE.js} +1 -1
  81. package/dist/web/assets/{esm-CZs9WVDO.js → esm-DGAP0GFh.js} +1 -1
  82. package/dist/web/assets/explorer-body-9aBmyVpZ.js +2 -0
  83. package/dist/web/assets/explorer-window-content-DRtqoSPA.js +1 -0
  84. package/dist/web/assets/extension-store-Cpfh2vMm.js +1 -0
  85. package/dist/web/assets/{extension-webview-CuOQrHIS.js → extension-webview-B2OnjuCu.js} +2 -2
  86. package/dist/web/assets/external-link-B8BynhvY.js +1 -0
  87. package/dist/web/assets/file-store-aOERIEo-.js +1 -0
  88. package/dist/web/assets/folder-symlink-B8XrtvQK.js +1 -0
  89. package/dist/web/assets/format-bytes-WVcFxJuT.js +1 -0
  90. package/dist/web/assets/{fortran-fixed-form-CXLIv8Ox.js → fortran-fixed-form-XnAhQWxS.js} +1 -1
  91. package/dist/web/assets/{fsharp-CZsYmiw9.js → fsharp-CdNvy0PG.js} +1 -1
  92. package/dist/web/assets/{gdresource-BGRvoWfC.js → gdresource-DxuG5i8i.js} +1 -1
  93. package/dist/web/assets/{git-commit-DH6mY3Km.js → git-commit-3lMonsur.js} +1 -1
  94. package/dist/web/assets/git-log-panel-Co0PBPHC.js +1 -0
  95. package/dist/web/assets/{git-rebase-C5Gql6Ma.js → git-rebase-N8Z9kIMf.js} +1 -1
  96. package/dist/web/assets/gitGraph-HDMCJU4V-2e_8dfbs.js +1 -0
  97. package/dist/web/assets/{glide-data-grid-Cehfgrzc.js → glide-data-grid-C4_zIneN.js} +8 -8
  98. package/dist/web/assets/{glimmer-js-1-6JMJlj.js → glimmer-js-Dp9OXiib.js} +1 -1
  99. package/dist/web/assets/{glimmer-ts-C_Njj0nK.js → glimmer-ts-CDVKBcDj.js} +1 -1
  100. package/dist/web/assets/{glsl-DbkxE1TN.js → glsl-DPJxI4us.js} +1 -1
  101. package/dist/web/assets/{graphql-BK75fiXl.js → graphql-BrFhaQQl.js} +1 -1
  102. package/dist/web/assets/group-chat-tab-rOd8J8GC.js +1 -0
  103. package/dist/web/assets/{hack-DG151vit.js → hack-BzXbDMlA.js} +1 -1
  104. package/dist/web/assets/{haml-DKeIPQWM.js → haml-CPpkX0s5.js} +1 -1
  105. package/dist/web/assets/{handlebars-398uCI13.js → handlebars-BqrApy52.js} +1 -1
  106. package/dist/web/assets/{html-NLWdst5q.js → html-DmjUl-OA.js} +1 -1
  107. package/dist/web/assets/{html-derivative-CJf_Le2z.js → html-derivative-Cnd6XFR5.js} +1 -1
  108. package/dist/web/assets/{http-G1K2FozA.js → http-DMLWYun2.js} +1 -1
  109. package/dist/web/assets/{hurl-WDC6sSBz.js → hurl-CKkCVxbj.js} +1 -1
  110. package/dist/web/assets/{hxml-Dc3jBXuf.js → hxml-CAx19TtQ.js} +1 -1
  111. package/dist/web/assets/image-preview-DHUoylQ1.js +1 -0
  112. package/dist/web/assets/index-BImUaigO.js +52 -0
  113. package/dist/web/assets/index-CSfi6DSU.css +2 -0
  114. package/dist/web/assets/info-3K5VOQVL-BZi1Gha1.js +1 -0
  115. package/dist/web/assets/input-DcEk7mA3.js +1 -0
  116. package/dist/web/assets/{jinja-CWsQj2y0.js → jinja-BmB9YN9l.js} +1 -1
  117. package/dist/web/assets/{jison-CciJg2NW.js → jison-BaVsKKpw.js} +1 -1
  118. package/dist/web/assets/{julia-IOQNJAB7.js → julia-BgVBLveX.js} +1 -1
  119. package/dist/web/assets/{just-BGdHchwS.js → just-C2ENIbl9.js} +1 -1
  120. package/dist/web/assets/keybindings-store-BGIyqXHI.js +1 -0
  121. package/dist/web/assets/keybindings-store-CzV2sPls.js +1 -0
  122. package/dist/web/assets/{latex-D6TOl-L2.js → latex-BiDIWxKL.js} +1 -1
  123. package/dist/web/assets/{liquid-CVSvu_Wn.js → liquid-NxpapreE.js} +1 -1
  124. package/dist/web/assets/loader-circle-gSPVxfvH.js +1 -0
  125. package/dist/web/assets/lock-Did-87UV.js +1 -0
  126. package/dist/web/assets/{lua-CcKiU6HW.js → lua-DVepQvwH.js} +1 -1
  127. package/dist/web/assets/markdown-renderer-CcbR33VG.js +1 -0
  128. package/dist/web/assets/{markdown-renderer-pVzBdkpl.js → markdown-renderer-DlcDhgrF.js} +3 -3
  129. package/dist/web/assets/{marko--UOicMGo.js → marko-CJ2606Xl.js} +1 -1
  130. package/dist/web/assets/{mdc-D690aU2C.js → mdc-D2bjqclE.js} +1 -1
  131. package/dist/web/assets/{media-url-CylYQld1.js → media-url-H17XJF-I.js} +1 -1
  132. package/dist/web/assets/mobile-bottom-sheet-g-r2hCFa.js +1 -0
  133. package/dist/web/assets/mobile-explorer-sheet-SIwQXlwA.js +1 -0
  134. package/dist/web/assets/monitor-Dv8vn_6O.js +1 -0
  135. package/dist/web/assets/{nextflow-DR8PhpF8.js → nextflow-BtJwUbfF.js} +1 -1
  136. package/dist/web/assets/{nginx-Qb9pUk1g.js → nginx-j4gyIhHE.js} +1 -1
  137. package/dist/web/assets/{nim-DLa8R3NS.js → nim-ClH_gjP5.js} +1 -1
  138. package/dist/web/assets/notification-store-DV5QtUTg.js +1 -0
  139. package/dist/web/assets/{number-overlay-editor-D9SkFg1Y.js → number-overlay-editor-C1EqJnWq.js} +1 -1
  140. package/dist/web/assets/overview-panel-vTeeJYVZ.js +1 -0
  141. package/dist/web/assets/packet-RMMSAZCW-o5htEcin.js +1 -0
  142. package/dist/web/assets/panel-store-BSnkjgHt.js +1 -0
  143. package/dist/web/assets/pdf-preview-CqFGRY0Z.js +1 -0
  144. package/dist/web/assets/pencil-BlIIg6RH.js +1 -0
  145. package/dist/web/assets/{perl-AMNGIneF.js → perl-C9H7X7CT.js} +1 -1
  146. package/dist/web/assets/{php-CDsOOxXn.js → php-Bx2U-cQ_.js} +1 -1
  147. package/dist/web/assets/pie-UPGHQEXC-BXAIFSAD.js +1 -0
  148. package/dist/web/assets/play-4MZi1Axp.js +1 -0
  149. package/dist/web/assets/portal-container-context-Cm5HipFr.js +1 -0
  150. package/dist/web/assets/{postgres-viewer-CR6VpTrX.js → postgres-viewer-DHwcQucn.js} +3 -3
  151. package/dist/web/assets/process-table-BGRJNlpn.js +1 -0
  152. package/dist/web/assets/{project-store-B8BkHXy5.js → project-store--nvQiy75.js} +1 -1
  153. package/dist/web/assets/{pug-C2kdkhQ6.js → pug-Cw74sKsE.js} +1 -1
  154. package/dist/web/assets/{qml-DRDkUp75.js → qml-BXD94Eqz.js} +1 -1
  155. package/dist/web/assets/radar-KQ55EAFF-Dbt2Aebl.js +1 -0
  156. package/dist/web/assets/{razor-wY_6wUeC.js → razor-DZ0-Ge0S.js} +1 -1
  157. package/dist/web/assets/refresh-cw-B06yaBrW.js +1 -0
  158. package/dist/web/assets/resolve-theme-CRt_7wpd.js +1 -0
  159. package/dist/web/assets/rotate-ccw-COXu_9oj.js +1 -0
  160. package/dist/web/assets/{rst-BRpofyNs.js → rst-Dtdh0QUj.js} +1 -1
  161. package/dist/web/assets/{ruby-ieATBhWm.js → ruby-BC51BW2Q.js} +1 -1
  162. package/dist/web/assets/{run-in-terminal-CyS5Itj-.js → run-in-terminal-Sd3KyjN4.js} +1 -1
  163. package/dist/web/assets/{sas-CoOOEbOO.js → sas-BN8i4qOU.js} +1 -1
  164. package/dist/web/assets/scroll-area-0gljZ6lF.js +1 -0
  165. package/dist/web/assets/{scss-_nWV0bsb.js → scss-H-QtA7Rz.js} +1 -1
  166. package/dist/web/assets/send-BlyNJAzy.js +1 -0
  167. package/dist/web/assets/{send-to-chat-BcO39BDR.js → send-to-chat-u6m8l-rH.js} +1 -1
  168. package/dist/web/assets/{settings-store-C20lqh0G.js → settings-store-CHY6Kzin.js} +2 -2
  169. package/dist/web/assets/settings-tab-Dic6TKkU.js +1 -0
  170. package/dist/web/assets/settings-tab-IY6K1MiZ.js +3 -0
  171. package/dist/web/assets/{shaderlab-XkqfIfO8.js → shaderlab-CalNsj_x.js} +1 -1
  172. package/dist/web/assets/shallow-DYo6goJ4.js +1 -0
  173. package/dist/web/assets/{shellsession-BKBIqTlM.js → shellsession-BFrcoR8x.js} +1 -1
  174. package/dist/web/assets/{soy-oVDnPzzh.js → soy-CNbku7vP.js} +1 -1
  175. package/dist/web/assets/{sparql-N2VclEsF.js → sparql-BN_orcVp.js} +1 -1
  176. package/dist/web/assets/{sql-query-editor-BPYsJDsn.js → sql-query-editor-C6pC3I8l.js} +1 -1
  177. package/dist/web/assets/sqlite-viewer-DTr5PzUb.js +1 -0
  178. package/dist/web/assets/{stata-BuuClVDg.js → stata-C6a5Ijzq.js} +1 -1
  179. package/dist/web/assets/{surrealql-DE5_63MS.js → surrealql-ClplI_HY.js} +1 -1
  180. package/dist/web/assets/{svelte--YWjlOrK.js → svelte-DNm-UNXB.js} +1 -1
  181. package/dist/web/assets/switch-DKvKya9y.js +1 -0
  182. package/dist/web/assets/system-monitor-body-iwGiCns9.js +2 -0
  183. package/dist/web/assets/system-monitor-tab-DdXQhEel.js +1 -0
  184. package/dist/web/assets/system-monitor-window-content-BUqRsPK2.js +1 -0
  185. package/dist/web/assets/tab-host-window-content-BnqGPu8a.js +1 -0
  186. package/dist/web/assets/{tab-store-DAsvpx4t.js → tab-store-CJuJRapl.js} +1 -1
  187. package/dist/web/assets/team-member-sheet-LkAFSCvb.js +2 -0
  188. package/dist/web/assets/team-member-window-content-T4Q5JI-G.js +1 -0
  189. package/dist/web/assets/{templ-MlpvJx4a.js → templ-CSdqVobu.js} +1 -1
  190. package/dist/web/assets/terminal-tab-Bb2rZegQ.js +3 -0
  191. package/dist/web/assets/{tex-0loAoXJG.js → tex-DzSJ4kcZ.js} +1 -1
  192. package/dist/web/assets/text-wrap-CBT4Gxtg.js +1 -0
  193. package/dist/web/assets/tool-cards-lhqhrDTT.js +8 -0
  194. package/dist/web/assets/trash-2-Bk4yYlck.js +1 -0
  195. package/dist/web/assets/treemap-KZPCXAKY-DUbnl9dz.js +1 -0
  196. package/dist/web/assets/triangle-alert-B8EYecpe.js +1 -0
  197. package/dist/web/assets/{ts-tags-pt-Ug0hK.js → ts-tags-C28w3bTg.js} +1 -1
  198. package/dist/web/assets/{twig-DOePpLOL.js → twig-i5jY3QXB.js} +1 -1
  199. package/dist/web/assets/upload-BNlX8D07.js +1 -0
  200. package/dist/web/assets/{use-blob-url-BKyVxOZw.js → use-blob-url-Dsq9OjTh.js} +1 -1
  201. package/dist/web/assets/{use-monaco-theme-CGucu3fb.js → use-monaco-theme-BZvlsoBv.js} +1 -1
  202. package/dist/web/assets/use-open-team-member-DkiEjFYE.js +1 -0
  203. package/dist/web/assets/{use-websocket-C-Rxv8JN.js → use-websocket-B8R50f7f.js} +1 -1
  204. package/dist/web/assets/{vendor-mermaid-DrwG0NYt.js → vendor-mermaid-By4AVvJY.js} +1 -1
  205. package/dist/web/assets/video-preview-m0-3p7QZ.js +1 -0
  206. package/dist/web/assets/{vue-D6f-rprj.js → vue-Ceyet_lv.js} +1 -1
  207. package/dist/web/assets/{vue-html-DEYRkS1V.js → vue-html-GuU7g_hg.js} +1 -1
  208. package/dist/web/assets/{vue-vine-CxSG2ojf.js → vue-vine-CxXoaJr2.js} +1 -1
  209. package/dist/web/assets/window-store-CsEW6jiE.js +1 -0
  210. package/dist/web/assets/{xml-DhrxbATj.js → xml-CbqOVhkP.js} +1 -1
  211. package/dist/web/assets/{xsl-CU0ZndUO.js → xsl-KfAmCauy.js} +1 -1
  212. package/dist/web/index.html +56 -27
  213. package/dist/web/sw.js +1 -1
  214. package/docs/code-standards.md +8 -0
  215. package/docs/codebase-summary.md +19 -5
  216. package/docs/design-guidelines.md +13 -2
  217. package/docs/project-roadmap.md +9 -0
  218. package/docs/system-architecture.md +83 -6
  219. package/package.json +1 -1
  220. package/src/web/components/chat/file-picker.tsx +5 -2
  221. package/src/web/components/chat/mode-selector.tsx +5 -2
  222. package/src/web/components/chat/model-selector.tsx +5 -2
  223. package/src/web/components/chat/model-thinking-selector.tsx +5 -2
  224. package/src/web/components/chat/provider-selector.tsx +5 -2
  225. package/src/web/components/chat/slash-command-picker.tsx +5 -2
  226. package/src/web/components/editor/code-editor.tsx +13 -3
  227. package/src/web/components/editor/conflict-editor.tsx +9 -0
  228. package/src/web/components/editor/diff-viewer.tsx +9 -0
  229. package/src/web/components/floating-window/floating-window.tsx +23 -15
  230. package/src/web/components/floating-window/pip/pip-caption-button.tsx +108 -0
  231. package/src/web/components/floating-window/pip/pip-focus-target.ts +58 -0
  232. package/src/web/components/floating-window/pip/pip-geometry.ts +46 -0
  233. package/src/web/components/floating-window/pip/pip-host.ts +156 -0
  234. package/src/web/components/floating-window/pip/pip-key-forward.ts +59 -0
  235. package/src/web/components/floating-window/pip/pip-resize-signal.ts +33 -0
  236. package/src/web/components/floating-window/pip/pip-style-copy.ts +108 -0
  237. package/src/web/components/floating-window/pip/pip-support.ts +33 -0
  238. package/src/web/components/floating-window/tab-host-window-content.tsx +80 -0
  239. package/src/web/components/floating-window/use-window-body-element.ts +67 -0
  240. package/src/web/components/floating-window/use-window-drag.ts +5 -0
  241. package/src/web/components/floating-window/use-window-gesture-context.ts +14 -0
  242. package/src/web/components/floating-window/use-window-resize.ts +5 -0
  243. package/src/web/components/floating-window/window-content-registry.ts +4 -16
  244. package/src/web/components/floating-window/window-layer.tsx +1 -2
  245. package/src/web/components/floating-window/window-persistence.ts +9 -2
  246. package/src/web/components/floating-window/window-pip-placeholder.tsx +31 -0
  247. package/src/web/components/floating-window/window-pip-registry.ts +69 -0
  248. package/src/web/components/floating-window/window-skin-chrome.tsx +21 -0
  249. package/src/web/components/floating-window/window-store-types.ts +8 -2
  250. package/src/web/components/layout/reparenting-tab.tsx +136 -0
  251. package/src/web/components/layout/tab-bar.tsx +2 -0
  252. package/src/web/components/layout/tab-pool-collect.ts +38 -2
  253. package/src/web/components/layout/tab-pool-registry.ts +48 -0
  254. package/src/web/components/layout/tab-pool.tsx +54 -168
  255. package/src/web/components/layout/tab-pop-out-menu-item.tsx +42 -0
  256. package/src/web/components/layout/use-window-panel-reconcile.ts +48 -0
  257. package/src/web/components/os-explorer/skins/macos-window-chrome.tsx +16 -7
  258. package/src/web/components/os-explorer/skins/windows-window-chrome.tsx +14 -8
  259. package/src/web/components/system/build-kill-request.ts +28 -1
  260. package/src/web/components/system/chart-scale.ts +3 -3
  261. package/src/web/components/system/kill-confirm-dialog.tsx +44 -28
  262. package/src/web/components/system/metric-chart-canvas.tsx +1 -2
  263. package/src/web/components/system/process-columns-grid.ts +39 -29
  264. package/src/web/components/system/process-group-row.tsx +31 -8
  265. package/src/web/components/system/process-row.tsx +6 -7
  266. package/src/web/components/system/process-table-model.ts +4 -22
  267. package/src/web/components/system/process-table-toolbar.tsx +12 -43
  268. package/src/web/components/system/process-table.tsx +22 -63
  269. package/src/web/components/system/sortable-header.tsx +33 -8
  270. package/src/web/components/system/system-monitor-body.tsx +1 -1
  271. package/src/web/components/system/use-column-widths.ts +91 -0
  272. package/src/web/components/system/use-process-kill.ts +100 -0
  273. package/src/web/components/ui/context-menu.tsx +10 -3
  274. package/src/web/components/ui/dialog.tsx +10 -1
  275. package/src/web/components/ui/dropdown-menu.tsx +10 -3
  276. package/src/web/components/ui/mobile-bottom-sheet.tsx +7 -4
  277. package/src/web/components/ui/portal-container-context.tsx +40 -0
  278. package/src/web/components/ui/select.tsx +3 -1
  279. package/src/web/components/ui/tooltip.tsx +3 -1
  280. package/src/web/hooks/use-terminal.ts +24 -3
  281. package/src/web/stores/panel-store.ts +72 -7
  282. package/src/web/stores/panel-utils.ts +36 -0
  283. package/src/web/stores/window-panel-actions.ts +211 -0
  284. package/src/web/stores/window-panel-persistence.ts +115 -0
  285. package/src/web/stores/window-panel-reconcile.ts +97 -0
  286. package/src/web/styles/globals.css +5 -3
  287. package/src/web/theme/builtin/aurora.ts +8 -5
  288. package/dist/web/assets/ai-resource-editor-DFCuNe-P.js +0 -1
  289. package/dist/web/assets/api-client-CzABTreM.js +0 -1
  290. package/dist/web/assets/api-settings-nblja3Rk.js +0 -1
  291. package/dist/web/assets/architecture-PBZL5I3N-C7ra20CE.js +0 -1
  292. package/dist/web/assets/chat-tab-flMPLoKb.js +0 -15
  293. package/dist/web/assets/code-editor-C2VQbXzw.js +0 -10
  294. package/dist/web/assets/context-menu-Cq0u3SK9.js +0 -1
  295. package/dist/web/assets/database-viewer-BCZOTrPT.js +0 -1
  296. package/dist/web/assets/diff-viewer-BwfMN-nW.js +0 -4
  297. package/dist/web/assets/docx-preview-D3Sdh_aT.js +0 -12
  298. package/dist/web/assets/explorer-body-BKOMM566.js +0 -2
  299. package/dist/web/assets/explorer-window-content-Bbzijk8t.js +0 -1
  300. package/dist/web/assets/format-bytes-Dk7B73B7.js +0 -1
  301. package/dist/web/assets/git-log-panel-DcV7PhqW.js +0 -1
  302. package/dist/web/assets/gitGraph-HDMCJU4V-D4hYLNJU.js +0 -1
  303. package/dist/web/assets/group-chat-tab-BVPYxjz-.js +0 -1
  304. package/dist/web/assets/image-preview-D-Ok10eZ.js +0 -1
  305. package/dist/web/assets/index-CerSxGdf.js +0 -52
  306. package/dist/web/assets/index-DRA_OpWY.css +0 -2
  307. package/dist/web/assets/info-3K5VOQVL-lRlrTlkb.js +0 -1
  308. package/dist/web/assets/keybindings-store-aIY40k2o.js +0 -1
  309. package/dist/web/assets/markdown-renderer-I89kyQhe.js +0 -1
  310. package/dist/web/assets/mobile-bottom-sheet-BUOJgiaZ.js +0 -1
  311. package/dist/web/assets/mobile-explorer-sheet-5Uj9ZMM9.js +0 -1
  312. package/dist/web/assets/notification-store-DJ-OtAG3.js +0 -1
  313. package/dist/web/assets/overview-panel-Cgi3UPY1.js +0 -1
  314. package/dist/web/assets/packet-RMMSAZCW-BIhk1mvp.js +0 -1
  315. package/dist/web/assets/panel-store-DCD82zc1.js +0 -1
  316. package/dist/web/assets/pdf-preview-Di5xHFyT.js +0 -1
  317. package/dist/web/assets/pie-UPGHQEXC-SLS6i76l.js +0 -1
  318. package/dist/web/assets/process-table-DL6shbzt.js +0 -1
  319. package/dist/web/assets/radar-KQ55EAFF-JJ6O1Er_.js +0 -1
  320. package/dist/web/assets/resolve-theme-IdhSR-gx.js +0 -1
  321. package/dist/web/assets/settings-tab-jbiQwozX.js +0 -1
  322. package/dist/web/assets/sqlite-viewer-Bq9ZJA2y.js +0 -1
  323. package/dist/web/assets/system-monitor-body-CKEYWyN9.js +0 -2
  324. package/dist/web/assets/system-monitor-tab-WjhFFHyM.js +0 -1
  325. package/dist/web/assets/system-monitor-window-content-CMiISeoC.js +0 -1
  326. package/dist/web/assets/team-member-sheet-oY5EkH53.js +0 -2
  327. package/dist/web/assets/team-member-window-content-yCBeI_5X.js +0 -1
  328. package/dist/web/assets/terminal-tab-BxHtMR7h.js +0 -3
  329. package/dist/web/assets/tool-cards-BcGrk1zk.js +0 -8
  330. package/dist/web/assets/treemap-KZPCXAKY-Be3KNmns.js +0 -1
  331. package/dist/web/assets/use-open-team-member-DdrRXj-M.js +0 -1
  332. package/dist/web/assets/video-preview-DYAbbmd0.js +0 -1
  333. package/src/web/components/floating-window/default-window-chrome.tsx +0 -71
  334. package/src/web/components/os-explorer/skins/explorer-skin-chrome.tsx +0 -17
  335. package/src/web/components/system/sparkline-canvas.tsx +0 -63
  336. /package/dist/web/assets/{abap-MRbmsXOs.js → abap-C6nB04tn.js} +0 -0
  337. /package/dist/web/assets/{actionscript-3-BDDHKqa4.js → actionscript-3-Vx4rw2sC.js} +0 -0
  338. /package/dist/web/assets/{ada-DpuV9KwV.js → ada-Ccd8vM20.js} +0 -0
  339. /package/dist/web/assets/{andromeeda-D6qUCKJo.js → andromeeda-DnBX5xMg.js} +0 -0
  340. /package/dist/web/assets/{apache-CX1NU_Tl.js → apache-B-9_sx0g.js} +0 -0
  341. /package/dist/web/assets/{apex-B4-aoQ3K.js → apex-_wPVBYoL.js} +0 -0
  342. /package/dist/web/assets/{api-client-BSB14J4w.js → api-client-aQb5hHE5.js} +0 -0
  343. /package/dist/web/assets/{applescript-Dm9NI6KR.js → applescript-CcvD-qr0.js} +0 -0
  344. /package/dist/web/assets/{apply-theme-BH_d4amk.js → apply-theme-BeLRfsSu.js} +0 -0
  345. /package/dist/web/assets/{ara-BGN8GAYn.js → ara-C40Ztoms.js} +0 -0
  346. /package/dist/web/assets/{asciidoc-s_yVuR3t.js → asciidoc-CybYkJV4.js} +0 -0
  347. /package/dist/web/assets/{asm-BzQdSvTe.js → asm-9eOKwzR0.js} +0 -0
  348. /package/dist/web/assets/{aurora-x-BJTLETG_.js → aurora-x-B5ZH4t7t.js} +0 -0
  349. /package/dist/web/assets/{awk-BQEGWxvX.js → awk-Dqilob-2.js} +0 -0
  350. /package/dist/web/assets/{ayu-dark-CpTORmLc.js → ayu-dark-CPgRhf5r.js} +0 -0
  351. /package/dist/web/assets/{ayu-light-D8PVj-e6.js → ayu-light-Do06Q52f.js} +0 -0
  352. /package/dist/web/assets/{ayu-mirage-DyElQHtm.js → ayu-mirage-_BhxcrxY.js} +0 -0
  353. /package/dist/web/assets/{ballerina-C82NkRtj.js → ballerina-DDwK54QW.js} +0 -0
  354. /package/dist/web/assets/{bat-0X7DtGI-.js → bat-BGyGlzGk.js} +0 -0
  355. /package/dist/web/assets/{beancount-Xgvy6YRl.js → beancount-CRWBdapI.js} +0 -0
  356. /package/dist/web/assets/{berry-CCT2pZcQ.js → berry-DbSFn2gO.js} +0 -0
  357. /package/dist/web/assets/{bibtex-CpXgZ9M_.js → bibtex-QpsV9gm9.js} +0 -0
  358. /package/dist/web/assets/{bicep-fkeSA62l.js → bicep-CxS8CUve.js} +0 -0
  359. /package/dist/web/assets/{bird2-Co7SeAI8.js → bird2-CuZhQzYR.js} +0 -0
  360. /package/dist/web/assets/{bot-CunPuEdW.js → bot-D6sx11y0.js} +0 -0
  361. /package/dist/web/assets/{c-BpmrTvJh.js → c-9bnDqE3g.js} +0 -0
  362. /package/dist/web/assets/{c3-BZ_Z0RrR.js → c3-JMZTrOhA.js} +0 -0
  363. /package/dist/web/assets/{cadence-B0GBC8OF.js → cadence-DsDNayJS.js} +0 -0
  364. /package/dist/web/assets/{can-open-in-ppm-omBzUBBq.js → can-open-in-ppm-BJfpynya.js} +0 -0
  365. /package/dist/web/assets/{catppuccin-frappe-DIt_xR7m.js → catppuccin-frappe-DYIKXXBe.js} +0 -0
  366. /package/dist/web/assets/{catppuccin-latte-Dw40AcqA.js → catppuccin-latte-IYYOnUJ8.js} +0 -0
  367. /package/dist/web/assets/{catppuccin-macchiato-BJ7DfVEF.js → catppuccin-macchiato-BrJ_7mfS.js} +0 -0
  368. /package/dist/web/assets/{catppuccin-mocha-NI2lfXzU.js → catppuccin-mocha-gzSu7v7-.js} +0 -0
  369. /package/dist/web/assets/{chevron-right-BLOtX8Vy.js → chevron-right-De-Wz5Lz.js} +0 -0
  370. /package/dist/web/assets/{circle-hjUGru6R.js → circle-BCy0AUCo.js} +0 -0
  371. /package/dist/web/assets/{clarity-F39L0xMJ.js → clarity-DLzsC0Hb.js} +0 -0
  372. /package/dist/web/assets/{clock-CvhF4DJP.js → clock-C1CQUQPZ.js} +0 -0
  373. /package/dist/web/assets/{clojure-DloMkd8K.js → clojure-DS1BvoTt.js} +0 -0
  374. /package/dist/web/assets/{cmake-CwerJun_.js → cmake-CDvsJwYp.js} +0 -0
  375. /package/dist/web/assets/{code-DDPoqVri.js → code-DJgYrFzm.js} +0 -0
  376. /package/dist/web/assets/{codeowners-CQyVz4Qf.js → codeowners-BjsYiflJ.js} +0 -0
  377. /package/dist/web/assets/{codeql-Bb229zuY.js → codeql-CG-7ARat.js} +0 -0
  378. /package/dist/web/assets/{common-lisp-KMlIwq5I.js → common-lisp-DSO1Lbh9.js} +0 -0
  379. /package/dist/web/assets/{copy-DKn11Pye.js → copy-BewHj66E.js} +0 -0
  380. /package/dist/web/assets/{coq-DHX_3IIo.js → coq-DYdh3oP_.js} +0 -0
  381. /package/dist/web/assets/{csharp-CEmCZv9Q.js → csharp-DxEBz5s0.js} +0 -0
  382. /package/dist/web/assets/{css-CqZqBD05.js → css-dal3Q-8C.js} +0 -0
  383. /package/dist/web/assets/{csv-l1g_V5MV.js → csv-CpqjMGiA.js} +0 -0
  384. /package/dist/web/assets/{csv-parser-CnS0wqr6.js → csv-parser-3umBA4NY.js} +0 -0
  385. /package/dist/web/assets/{cue-BrxRmilg.js → cue-DinoJ_5k.js} +0 -0
  386. /package/dist/web/assets/{cypher-rZkKwqZc.js → cypher-DzxqmkUW.js} +0 -0
  387. /package/dist/web/assets/{d-BALR-QuP.js → d-BxNwJuEC.js} +0 -0
  388. /package/dist/web/assets/{dark-plus-Cj7rVwh-.js → dark-plus-Clmv3V-0.js} +0 -0
  389. /package/dist/web/assets/{dart-CWQcdkXk.js → dart-BWVtXD35.js} +0 -0
  390. /package/dist/web/assets/{data-grid-types-CYvF-xK5.js → data-grid-types-B4n51Fck.js} +0 -0
  391. /package/dist/web/assets/{database-BH0urvbs.js → database-Y3ESDK4-.js} +0 -0
  392. /package/dist/web/assets/{dax-BNHD-QBA.js → dax-DsImuWgJ.js} +0 -0
  393. /package/dist/web/assets/{desktop-CN0IXPrP.js → desktop-B0jJuG2r.js} +0 -0
  394. /package/dist/web/assets/{diff-BtOXapES.js → diff-CWqAAxoE.js} +0 -0
  395. /package/dist/web/assets/{dist-DB1Oaqcc.js → dist-B-EXdSYE.js} +0 -0
  396. /package/dist/web/assets/{dist-Di6G_5jU.js → dist-C0eNNfbt.js} +0 -0
  397. /package/dist/web/assets/{docker-DNsAo_qO.js → docker-CYFCJdIL.js} +0 -0
  398. /package/dist/web/assets/{dotenv-D6Pl6aOU.js → dotenv-CKDUjURg.js} +0 -0
  399. /package/dist/web/assets/{download-zCATy4x4.js → download-DG3_9xXy.js} +0 -0
  400. /package/dist/web/assets/{dracula-C3m-w12D.js → dracula-CSoPspHE.js} +0 -0
  401. /package/dist/web/assets/{dracula-soft-BYqvXm6Z.js → dracula-soft-BuFjw5L1.js} +0 -0
  402. /package/dist/web/assets/{dream-maker-DZAPbPTi.js → dream-maker-B6PdDRZu.js} +0 -0
  403. /package/dist/web/assets/{emacs-lisp-Ao5SW8ay.js → emacs-lisp-CMcXvD0G.js} +0 -0
  404. /package/dist/web/assets/{everforest-dark-uC8QYotQ.js → everforest-dark-cU8-wYzi.js} +0 -0
  405. /package/dist/web/assets/{everforest-light-CTgsVNMr.js → everforest-light-KhorllqK.js} +0 -0
  406. /package/dist/web/assets/{fennel-WuBw6IR1.js → fennel-BCELZK87.js} +0 -0
  407. /package/dist/web/assets/{file-exclamation-point-COAwgNGw.js → file-exclamation-point-CZ4DiR75.js} +0 -0
  408. /package/dist/web/assets/{fish-Byy9dusu.js → fish-BQc0y_jy.js} +0 -0
  409. /package/dist/web/assets/{fluent-CDxb_sgw.js → fluent-BTINnwF6.js} +0 -0
  410. /package/dist/web/assets/{fortran-free-form-DKWSTamT.js → fortran-free-form-BQim9wDz.js} +0 -0
  411. /package/dist/web/assets/{gdscript-prYHMgtD.js → gdscript-03w5u8un.js} +0 -0
  412. /package/dist/web/assets/{gdshader-D-RM-SQk.js → gdshader-Dp2daNzU.js} +0 -0
  413. /package/dist/web/assets/{genie-CowkJhej.js → genie-CoNcjPiD.js} +0 -0
  414. /package/dist/web/assets/{gherkin-CLFpoVYJ.js → gherkin-NrPOSPQL.js} +0 -0
  415. /package/dist/web/assets/{github-dark-default-BK_1Qgb8.js → github-dark-default-DOKw-1cI.js} +0 -0
  416. /package/dist/web/assets/{github-dark-dimmed-Cv9lj6f-.js → github-dark-dimmed-DJRNMkEA.js} +0 -0
  417. /package/dist/web/assets/{github-dark-high-contrast-CW5ZgIDh.js → github-dark-high-contrast-Bj7jJ_Gs.js} +0 -0
  418. /package/dist/web/assets/{github-dark-nW2F-RLd.js → github-dark-z4RE9ZqA.js} +0 -0
  419. /package/dist/web/assets/{github-light-D4PqBHGZ.js → github-light-B4k_yMFu.js} +0 -0
  420. /package/dist/web/assets/{github-light-default-B-cHtJJV.js → github-light-default-BHc-Uzhs.js} +0 -0
  421. /package/dist/web/assets/{github-light-high-contrast-Dt0HJq50.js → github-light-high-contrast-CHisIywL.js} +0 -0
  422. /package/dist/web/assets/{gleam-DwSyXJWP.js → gleam-CfbypZ4q.js} +0 -0
  423. /package/dist/web/assets/{gn-Cv5WEzHc.js → gn-YoAjyhJa.js} +0 -0
  424. /package/dist/web/assets/{gnuplot-D7bRdY_M.js → gnuplot-xVkc1f1c.js} +0 -0
  425. /package/dist/web/assets/{go-DiRVJ22U.js → go-GPCwP3Gu.js} +0 -0
  426. /package/dist/web/assets/{groovy-BHAgLTeO.js → groovy-Crh4Yww9.js} +0 -0
  427. /package/dist/web/assets/{gruvbox-dark-hard-C8QZ3gzY.js → gruvbox-dark-hard-BluUFuDS.js} +0 -0
  428. /package/dist/web/assets/{gruvbox-dark-medium-Dp1eeid2.js → gruvbox-dark-medium-Cxk1FWQp.js} +0 -0
  429. /package/dist/web/assets/{gruvbox-dark-soft-Cwq0dWVj.js → gruvbox-dark-soft-CHXMiFmj.js} +0 -0
  430. /package/dist/web/assets/{gruvbox-light-hard-CLQCq2-w.js → gruvbox-light-hard-B6eKPjAD.js} +0 -0
  431. /package/dist/web/assets/{gruvbox-light-medium-APHsh6Mo.js → gruvbox-light-medium-pDwMm1ut.js} +0 -0
  432. /package/dist/web/assets/{gruvbox-light-soft-CX-fYc64.js → gruvbox-light-soft-Cxu6kHqK.js} +0 -0
  433. /package/dist/web/assets/{haskell-C4Tw-TDa.js → haskell-C6JKHjbK.js} +0 -0
  434. /package/dist/web/assets/{haxe-B7fSduTQ.js → haxe-BuBNdF0a.js} +0 -0
  435. /package/dist/web/assets/{hcl-Bi3ho6yC.js → hcl-DZpDdGj2.js} +0 -0
  436. /package/dist/web/assets/{hjson-BXwae2M1.js → hjson-CBkhYRuo.js} +0 -0
  437. /package/dist/web/assets/{hlsl-CRuQLBSa.js → hlsl-C5nMxnp9.js} +0 -0
  438. /package/dist/web/assets/{horizon-DtdQ6qjv.js → horizon-VAFvA6R6.js} +0 -0
  439. /package/dist/web/assets/{horizon-bright-BXSF_uKq.js → horizon-bright-BC0xn7T3.js} +0 -0
  440. /package/dist/web/assets/{houston-C6ASpUjT.js → houston-BxrUivmz.js} +0 -0
  441. /package/dist/web/assets/{hy-BrWBHtHY.js → hy-DLtOXoaH.js} +0 -0
  442. /package/dist/web/assets/{image-gallery-CGvlv8zR.js → image-gallery-Gnf7TdCR.js} +0 -0
  443. /package/dist/web/assets/{imba-C_JJXckG.js → imba-BdpFXM2W.js} +0 -0
  444. /package/dist/web/assets/{ini-DEE_vSHQ.js → ini-BInJO_T0.js} +0 -0
  445. /package/dist/web/assets/{java-CnmpcjcT.js → java-Dxuddnkb.js} +0 -0
  446. /package/dist/web/assets/{javascript-C-M7sa2e.js → javascript-CVamJfLY.js} +0 -0
  447. /package/dist/web/assets/{json-BjZ3dAk6.js → json-BLZ0ozYk.js} +0 -0
  448. /package/dist/web/assets/{json5-BQ2vpqjp.js → json5-BnXzmMKs.js} +0 -0
  449. /package/dist/web/assets/{jsonc-C5MjoWGx.js → jsonc-CSgkSga7.js} +0 -0
  450. /package/dist/web/assets/{jsonl-JvhrmQJI.js → jsonl-CY5W2nF2.js} +0 -0
  451. /package/dist/web/assets/{jsonnet-C5pdZVuo.js → jsonnet-CEJYH3sF.js} +0 -0
  452. /package/dist/web/assets/{jssm-Db17uybX.js → jssm-CsJc7Uhk.js} +0 -0
  453. /package/dist/web/assets/{jsx-tJp2Cyqu.js → jsx-jCiRaHU7.js} +0 -0
  454. /package/dist/web/assets/{kanagawa-dragon-BculT_Y1.js → kanagawa-dragon-DfoA_GxX.js} +0 -0
  455. /package/dist/web/assets/{kanagawa-lotus-yQgHUGwU.js → kanagawa-lotus-BOLYJpWd.js} +0 -0
  456. /package/dist/web/assets/{kanagawa-wave-CyGoWN4d.js → kanagawa-wave-DfKlbT1G.js} +0 -0
  457. /package/dist/web/assets/{kdl-Bn8R1REF.js → kdl-CmssIFTi.js} +0 -0
  458. /package/dist/web/assets/{kotlin-DWughK73.js → kotlin-BRsNgp6x.js} +0 -0
  459. /package/dist/web/assets/{kusto--serPb0x.js → kusto-T8X9jUab.js} +0 -0
  460. /package/dist/web/assets/{laserwave-DfAPJ1tt.js → laserwave-DkJMVJ8Z.js} +0 -0
  461. /package/dist/web/assets/{lean-UAm1HOKl.js → lean-C65KGVPq.js} +0 -0
  462. /package/dist/web/assets/{less-Xj6Ka0fF.js → less-exIPdDlf.js} +0 -0
  463. /package/dist/web/assets/{lib-DgNcCtj3.js → lib-mC1NZfuw.js} +0 -0
  464. /package/dist/web/assets/{libesm-CPh1Av0r.js → libesm-DSutUtl1.js} +0 -0
  465. /package/dist/web/assets/{light-plus-BfS7gPcj.js → light-plus-DiHUXAZt.js} +0 -0
  466. /package/dist/web/assets/{llvm-DvWiVwvU.js → llvm-CJBnEzFM.js} +0 -0
  467. /package/dist/web/assets/{log-Bo5z9bNz.js → log-DxMyUMuP.js} +0 -0
  468. /package/dist/web/assets/{logo-CrIjcMZT.js → logo-CC9NKzca.js} +0 -0
  469. /package/dist/web/assets/{luau-C9TsYwNt.js → luau-Bw10I6zf.js} +0 -0
  470. /package/dist/web/assets/{make-GYq4qVbx.js → make-C_6M90m6.js} +0 -0
  471. /package/dist/web/assets/{markdown-p5mNledS.js → markdown-bR9_R-LF.js} +0 -0
  472. /package/dist/web/assets/{material-theme-CWYOVxsP.js → material-theme-BUx2Qujn.js} +0 -0
  473. /package/dist/web/assets/{material-theme-darker-BDGty7YH.js → material-theme-darker-CRJrPgKm.js} +0 -0
  474. /package/dist/web/assets/{material-theme-lighter-JbgOgV3n.js → material-theme-lighter-CUAYppPa.js} +0 -0
  475. /package/dist/web/assets/{material-theme-ocean-EMOpLpa2.js → material-theme-ocean-DuINF1fg.js} +0 -0
  476. /package/dist/web/assets/{material-theme-palenight-CY5hgm7h.js → material-theme-palenight-W6_icGCj.js} +0 -0
  477. /package/dist/web/assets/{matlab-C-He_NTH.js → matlab-rfqn_b3z.js} +0 -0
  478. /package/dist/web/assets/{mdx-Cr2TR5fj.js → mdx-Bh1B_YOJ.js} +0 -0
  479. /package/dist/web/assets/{mermaid-BYc0-B0U.js → mermaid-Dxf6Ya2k.js} +0 -0
  480. /package/dist/web/assets/{min-dark-CMJwqJqB.js → min-dark-CivZ2L0h.js} +0 -0
  481. /package/dist/web/assets/{min-light-Cx6vFiEX.js → min-light-B1Ykqtma.js} +0 -0
  482. /package/dist/web/assets/{mipsasm-Bjer5HwK.js → mipsasm-DynHaM0d.js} +0 -0
  483. /package/dist/web/assets/{mojo-t90PR-Y2.js → mojo-Clw5PbGH.js} +0 -0
  484. /package/dist/web/assets/{monokai-dci_PdCm.js → monokai-DFIooFZT.js} +0 -0
  485. /package/dist/web/assets/{moonbit-AAzI-Hd-.js → moonbit-DnBSZWGM.js} +0 -0
  486. /package/dist/web/assets/{move-kwBhnhrG.js → move-CCcL2PfL.js} +0 -0
  487. /package/dist/web/assets/{narrat-CXww2YQL.js → narrat-BDarg5Lk.js} +0 -0
  488. /package/dist/web/assets/{nextflow-groovy-CJXsuXGB.js → nextflow-groovy-DrZOeCNW.js} +0 -0
  489. /package/dist/web/assets/{night-owl-_GD204Wr.js → night-owl-BnZZCK7v.js} +0 -0
  490. /package/dist/web/assets/{night-owl-light-DNgkw3kl.js → night-owl-light-CEwBsVHS.js} +0 -0
  491. /package/dist/web/assets/{nix-BgiorKFd.js → nix-amCzOPMR.js} +0 -0
  492. /package/dist/web/assets/{nord-CaBmcxFC.js → nord-BIs2BC6q.js} +0 -0
  493. /package/dist/web/assets/{nushell-DUh4UGx1.js → nushell-Y02fo4yw.js} +0 -0
  494. /package/dist/web/assets/{objective-c-Cl9KU86S.js → objective-c-7xOZtWW1.js} +0 -0
  495. /package/dist/web/assets/{objective-cpp-DVkIA8A0.js → objective-cpp-eVtjUvVB.js} +0 -0
  496. /package/dist/web/assets/{ocaml-vvoHTak0.js → ocaml-Bi6ZwqG4.js} +0 -0
  497. /package/dist/web/assets/{odin-Cyjw8woZ.js → odin-8xf1Y0S9.js} +0 -0
  498. /package/dist/web/assets/{one-dark-pro-B1cviILi.js → one-dark-pro-hVv-_y_b.js} +0 -0
  499. /package/dist/web/assets/{one-light-BPGUJeYI.js → one-light-CJJ3MtHt.js} +0 -0
  500. /package/dist/web/assets/{openscad-BLMdTUU8.js → openscad-B2HcywLk.js} +0 -0
  501. /package/dist/web/assets/{pascal-i5niy3e7.js → pascal-C7fllV_7.js} +0 -0
  502. /package/dist/web/assets/{pkl-CuOV7SsU.js → pkl-qvLC1IWP.js} +0 -0
  503. /package/dist/web/assets/{plastic-Bf_zE5KL.js → plastic-BT1wHZv2.js} +0 -0
  504. /package/dist/web/assets/{plsql-cfqEtMD3.js → plsql-1MsmdmJD.js} +0 -0
  505. /package/dist/web/assets/{plus-BM-Ty0fp.js → plus-BhMZqFsN.js} +0 -0
  506. /package/dist/web/assets/{po-CFJcWgjr.js → po-BigskytD.js} +0 -0
  507. /package/dist/web/assets/{poimandres-G5YoaIFf.js → poimandres-DuklniF7.js} +0 -0
  508. /package/dist/web/assets/{polar-rcjs3i9R.js → polar-e2pjN_sp.js} +0 -0
  509. /package/dist/web/assets/{postcss-CBKY1FTZ.js → postcss-DtAeYjWw.js} +0 -0
  510. /package/dist/web/assets/{powerquery-Db7SXLbO.js → powerquery-Cr2PtehI.js} +0 -0
  511. /package/dist/web/assets/{powershell-LFy3MUTP.js → powershell-BxFTGLJ4.js} +0 -0
  512. /package/dist/web/assets/{prisma-BE8GR1lH.js → prisma-COWJiwdZ.js} +0 -0
  513. /package/dist/web/assets/{prolog-DOn5lR1e.js → prolog-DFvGKRx6.js} +0 -0
  514. /package/dist/web/assets/{proto-wr-TpAK_.js → proto-CcK80lFt.js} +0 -0
  515. /package/dist/web/assets/{puppet-D2Dkv62u.js → puppet-BF60bZ4F.js} +0 -0
  516. /package/dist/web/assets/{purescript-DvgJgPdy.js → purescript-zL_69MzU.js} +0 -0
  517. /package/dist/web/assets/{python-C7TlkHhK.js → python-CIwKhfb_.js} +0 -0
  518. /package/dist/web/assets/{qmldir-CtZMwhcW.js → qmldir-CXNe04Lo.js} +0 -0
  519. /package/dist/web/assets/{qss-dNZ2btnl.js → qss-C8lAWe6G.js} +0 -0
  520. /package/dist/web/assets/{r-BlqnNkHS.js → r-CL5ZVL3_.js} +0 -0
  521. /package/dist/web/assets/{racket-CzRQrGc4.js → racket-BBfh0uh0.js} +0 -0
  522. /package/dist/web/assets/{raku-BwutWhBF.js → raku-o6E8R5Q3.js} +0 -0
  523. /package/dist/web/assets/{react-I_EwPIZi.js → react-CBTnT4sY.js} +0 -0
  524. /package/dist/web/assets/{red-BMXMywmL.js → red-GomRF2Xp.js} +0 -0
  525. /package/dist/web/assets/{reg-BqOKrIOw.js → reg-_ffDIvx9.js} +0 -0
  526. /package/dist/web/assets/{regexp-Bero1BN2.js → regexp-Bl5sF65W.js} +0 -0
  527. /package/dist/web/assets/{rel-BXKWIElA.js → rel-DgMdqDuj.js} +0 -0
  528. /package/dist/web/assets/{riscv-BbbBYJBo.js → riscv-8b3-Ye4X.js} +0 -0
  529. /package/dist/web/assets/{ron-BtVTWW4b.js → ron-DrmU1KHP.js} +0 -0
  530. /package/dist/web/assets/{rose-pine-hvkvQzvU.js → rose-pine-C_-E2tF1.js} +0 -0
  531. /package/dist/web/assets/{rose-pine-dawn-D7lwhUei.js → rose-pine-dawn-DEfhNlFH.js} +0 -0
  532. /package/dist/web/assets/{rose-pine-moon-CoHDmsIw.js → rose-pine-moon-BdvX3gdn.js} +0 -0
  533. /package/dist/web/assets/{rosmsg-CdaZFgI8.js → rosmsg-B6GhGpd5.js} +0 -0
  534. /package/dist/web/assets/{rust-Dy2qsphD.js → rust-DmC97M1-.js} +0 -0
  535. /package/dist/web/assets/{sass-Bz7NVxDb.js → sass-B0tJOHLM.js} +0 -0
  536. /package/dist/web/assets/{save-C4z1p51e.js → save-CtIGOjmx.js} +0 -0
  537. /package/dist/web/assets/{scala-sXSwsNyq.js → scala-n8zaFOXv.js} +0 -0
  538. /package/dist/web/assets/{scheme-DS7TUbN7.js → scheme-BKD9ztBU.js} +0 -0
  539. /package/dist/web/assets/{sdbl-iISFvIep.js → sdbl-D8gB5-rS.js} +0 -0
  540. /package/dist/web/assets/{shellscript-BkIl4ApC.js → shellscript-BfXlf_Ao.js} +0 -0
  541. /package/dist/web/assets/{shield-check-C5laObJv.js → shield-check-B0iGUiOK.js} +0 -0
  542. /package/dist/web/assets/{shield-off-DULFtyLS.js → shield-off-BNLWBhcq.js} +0 -0
  543. /package/dist/web/assets/{slack-dark-B1eg0_m2.js → slack-dark-CylEddse.js} +0 -0
  544. /package/dist/web/assets/{slack-ochin-mdkc1ldu.js → slack-ochin-w8wg8vuC.js} +0 -0
  545. /package/dist/web/assets/{smalltalk-CORtd03t.js → smalltalk-hiAXA64u.js} +0 -0
  546. /package/dist/web/assets/{snazzy-light-Bc6Q2G89.js → snazzy-light-BwlV3Xty.js} +0 -0
  547. /package/dist/web/assets/{solarized-dark-CF83zRXM.js → solarized-dark-vmNGdykz.js} +0 -0
  548. /package/dist/web/assets/{solarized-light-BoKQZaYU.js → solarized-light-DGv_0JXq.js} +0 -0
  549. /package/dist/web/assets/{solidity-DOgi1N4w.js → solidity-Y7QSH0B1.js} +0 -0
  550. /package/dist/web/assets/{sparkles-Dqsf3hq6.js → sparkles-Dh-_J2Rd.js} +0 -0
  551. /package/dist/web/assets/{splunk-BXfw5ZLy.js → splunk-BtgpLjHi.js} +0 -0
  552. /package/dist/web/assets/{sql-BcVs-eX4.js → sql-CRHYhOia.js} +0 -0
  553. /package/dist/web/assets/{ssh-config-CLCtNkkd.js → ssh-config-DOqSs3au.js} +0 -0
  554. /package/dist/web/assets/{stylus-DdP992aO.js → stylus-crCAEaBT.js} +0 -0
  555. /package/dist/web/assets/{swift-BnGb6Lgc.js → swift-eE3rT7TC.js} +0 -0
  556. /package/dist/web/assets/{synthwave-84-cg9264l9.js → synthwave-84-BWy14LBX.js} +0 -0
  557. /package/dist/web/assets/{system-verilog-GbHpszs3.js → system-verilog-DC0-DZM4.js} +0 -0
  558. /package/dist/web/assets/{systemd-Dz-bNsDQ.js → systemd-to5p6N8I.js} +0 -0
  559. /package/dist/web/assets/{table-CHmxuh6M.js → table-Bbc783ko.js} +0 -0
  560. /package/dist/web/assets/{talonscript-CFIidoBA.js → talonscript-DoTcU8wm.js} +0 -0
  561. /package/dist/web/assets/{tasl-Cu-TRTKx.js → tasl-cNZvUs95.js} +0 -0
  562. /package/dist/web/assets/{tcl-DwCHCB1K.js → tcl-mZE8sZH8.js} +0 -0
  563. /package/dist/web/assets/{terraform-BzZw4T1z.js → terraform-CqHPpIfu.js} +0 -0
  564. /package/dist/web/assets/{tokyo-night-RKsj2-tv.js → tokyo-night-Tp2rTIZd.js} +0 -0
  565. /package/dist/web/assets/{toml-CirbOgDP.js → toml-CU_vscgn.js} +0 -0
  566. /package/dist/web/assets/{tsv-CraRcWdU.js → tsv-ik7iFB9D.js} +0 -0
  567. /package/dist/web/assets/{tsx-CjFg0lgw.js → tsx-BMvvMKiv.js} +0 -0
  568. /package/dist/web/assets/{turtle-B-WBIOa6.js → turtle-DBqKCq9o.js} +0 -0
  569. /package/dist/web/assets/{typescript-MpLarYn1.js → typescript-DXJDmMZZ.js} +0 -0
  570. /package/dist/web/assets/{typespec-B7QlHMZ_.js → typespec-CBseCMtZ.js} +0 -0
  571. /package/dist/web/assets/{typst-CcHSKFZj.js → typst-4oY25U9y.js} +0 -0
  572. /package/dist/web/assets/{use-is-mobile-BXGVvczu.js → use-is-mobile-D1weanbj.js} +0 -0
  573. /package/dist/web/assets/{utils-DoY4yTP-.js → utils-BNRH507E.js} +0 -0
  574. /package/dist/web/assets/{v-xTGhWZuD.js → v-BXaZ_1oy.js} +0 -0
  575. /package/dist/web/assets/{vala-DwebjH3H.js → vala-BImWJE7z.js} +0 -0
  576. /package/dist/web/assets/{vb-BxJT2RAy.js → vb-CLfj2_sy.js} +0 -0
  577. /package/dist/web/assets/{vendor-xterm-CU6zIYMB.js → vendor-xterm-_yyu5n32.js} +0 -0
  578. /package/dist/web/assets/{verilog-CvV6RHPD.js → verilog-BWa8Ed2b.js} +0 -0
  579. /package/dist/web/assets/{vesper-CY3qd7E_.js → vesper-BGj1cg6m.js} +0 -0
  580. /package/dist/web/assets/{vhdl-B9ZX-sUL.js → vhdl-mByK7mlx.js} +0 -0
  581. /package/dist/web/assets/{viml-Y42h_ExQ.js → viml-CugmlW5g.js} +0 -0
  582. /package/dist/web/assets/{vitesse-black-DkXP6Sv-.js → vitesse-black-vPdpy9TL.js} +0 -0
  583. /package/dist/web/assets/{vitesse-dark-B9CkIB6r.js → vitesse-dark-BuQK3dUh.js} +0 -0
  584. /package/dist/web/assets/{vitesse-light-C7DHrJCK.js → vitesse-light-B3nz1XL9.js} +0 -0
  585. /package/dist/web/assets/{vyper-Cnd9s5j-.js → vyper-DH_GTIHG.js} +0 -0
  586. /package/dist/web/assets/{wasm-DQE71XTB.js → wasm-C-LF9GjX.js} +0 -0
  587. /package/dist/web/assets/{wasm-iWe7Fzjc.js → wasm-DfVbVJlW.js} +0 -0
  588. /package/dist/web/assets/{wenyan-Bc5Pnm9l.js → wenyan-CzQkHyHx.js} +0 -0
  589. /package/dist/web/assets/{wgsl-D-YUAWkP.js → wgsl-Du_M1DW9.js} +0 -0
  590. /package/dist/web/assets/{wikitext-DYQDUYf2.js → wikitext-BWN_w5S7.js} +0 -0
  591. /package/dist/web/assets/{wit-P6u7mfwy.js → wit-BR13v5HD.js} +0 -0
  592. /package/dist/web/assets/{wolfram-6SXLUqao.js → wolfram-BoXxp_Xl.js} +0 -0
  593. /package/dist/web/assets/{x-BcqfTY_7.js → x-nhriOX9o.js} +0 -0
  594. /package/dist/web/assets/{yaml-CQiMLVcZ.js → yaml-DpR_EF-d.js} +0 -0
  595. /package/dist/web/assets/{zenscript-DFMywo_P.js → zenscript-C-EdUtUd.js} +0 -0
  596. /package/dist/web/assets/{zig-CtAjaIiF.js → zig-BD4eA5nU.js} +0 -0
@@ -0,0 +1,91 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { clampColumnWidth, columnWidthPx, type ColumnWidths, type ResizableColumnKey } from "./process-columns-grid";
3
+
4
+ /** One entry for the whole app: column widths are a per-device preference, not
5
+ * per-window state, so they survive reloads and apply to the mobile tab too. */
6
+ export const COLUMN_WIDTHS_STORAGE_KEY = "ppm-sysmon-col-widths";
7
+
8
+ function loadWidths(): ColumnWidths {
9
+ try {
10
+ const raw = localStorage.getItem(COLUMN_WIDTHS_STORAGE_KEY);
11
+ if (!raw) return {};
12
+ const parsed = JSON.parse(raw) as Record<string, unknown>;
13
+ const out: ColumnWidths = {};
14
+ for (const k of ["cpu", "ram", "disk", "gpu", "net"] as ResizableColumnKey[]) {
15
+ const v = parsed[k];
16
+ if (typeof v === "number" && Number.isFinite(v)) out[k] = clampColumnWidth(v);
17
+ }
18
+ return out;
19
+ } catch {
20
+ return {};
21
+ }
22
+ }
23
+
24
+ function saveWidths(widths: ColumnWidths): void {
25
+ try {
26
+ if (Object.keys(widths).length === 0) localStorage.removeItem(COLUMN_WIDTHS_STORAGE_KEY);
27
+ else localStorage.setItem(COLUMN_WIDTHS_STORAGE_KEY, JSON.stringify(widths));
28
+ } catch {
29
+ /* private mode / quota — widths just don't persist */
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Drag-to-resize state for the process table's fixed-width columns.
35
+ *
36
+ * `begin(key, event)` is wired to `pointerdown` on a header's right-edge handle;
37
+ * the drag then follows `pointermove`/`pointerup` on `window`, so the pointer may
38
+ * leave the handle (or the window body) without dropping the drag. Widths persist
39
+ * on release, not on every move. `reset(key)` (double-click) returns one column
40
+ * to its default.
41
+ */
42
+ export function useColumnWidths() {
43
+ const [widths, setWidths] = useState<ColumnWidths>(() => (typeof localStorage === "undefined" ? {} : loadWidths()));
44
+ const drag = useRef<{ key: ResizableColumnKey; startX: number; startWidth: number } | null>(null);
45
+
46
+ useEffect(() => {
47
+ const onMove = (e: PointerEvent) => {
48
+ const d = drag.current;
49
+ if (!d) return;
50
+ const next = clampColumnWidth(d.startWidth + (e.clientX - d.startX));
51
+ setWidths((prev) => (prev[d.key] === next ? prev : { ...prev, [d.key]: next }));
52
+ };
53
+ const onUp = () => {
54
+ if (!drag.current) return;
55
+ drag.current = null;
56
+ document.body.style.cursor = "";
57
+ setWidths((prev) => {
58
+ saveWidths(prev);
59
+ return prev;
60
+ });
61
+ };
62
+ window.addEventListener("pointermove", onMove);
63
+ window.addEventListener("pointerup", onUp);
64
+ window.addEventListener("pointercancel", onUp);
65
+ return () => {
66
+ window.removeEventListener("pointermove", onMove);
67
+ window.removeEventListener("pointerup", onUp);
68
+ window.removeEventListener("pointercancel", onUp);
69
+ };
70
+ }, []);
71
+
72
+ const begin = useCallback(
73
+ (key: ResizableColumnKey, e: { clientX: number; preventDefault: () => void }) => {
74
+ e.preventDefault(); // no text selection while dragging
75
+ drag.current = { key, startX: e.clientX, startWidth: columnWidthPx(key, widths) };
76
+ document.body.style.cursor = "col-resize";
77
+ },
78
+ [widths],
79
+ );
80
+
81
+ const reset = useCallback((key: ResizableColumnKey) => {
82
+ setWidths((prev) => {
83
+ if (!(key in prev)) return prev;
84
+ const { [key]: _dropped, ...rest } = prev;
85
+ saveWidths(rest);
86
+ return rest;
87
+ });
88
+ }, []);
89
+
90
+ return { widths, begin, reset };
91
+ }
@@ -0,0 +1,100 @@
1
+ import { useCallback, useMemo, useState } from "react";
2
+ import { toast } from "sonner";
3
+ import { getAuthToken } from "@/lib/api-client";
4
+ import { buildGroupKillRequests, buildKillRequest, isGroupProtected, type KillTarget } from "./build-kill-request";
5
+ import type {
6
+ KillProcessRequest,
7
+ KillProcessResult,
8
+ MetricsSnapshot,
9
+ ProcessGroup,
10
+ ProcessInfo,
11
+ } from "../../../types/system-metrics";
12
+
13
+ /** `api.post` (src/web/lib/api-client.ts) has no way to add a bespoke header, and the
14
+ * kill route requires `X-PPM-Request: 1` — CSRF hardening, since a cross-origin HTML
15
+ * form cannot set a custom header, so a preflight becomes mandatory. A raw fetch here
16
+ * mirrors `handleResponse`'s single-Error-on-any-failure contract exactly, so the
17
+ * caller still has exactly one catch path. */
18
+ export async function killProcess(request: KillProcessRequest): Promise<KillProcessResult> {
19
+ const token = getAuthToken();
20
+ const headers: Record<string, string> = {
21
+ "Content-Type": "application/json",
22
+ "X-PPM-Request": "1",
23
+ };
24
+ if (token) headers.Authorization = `Bearer ${token}`;
25
+
26
+ const res = await fetch("/api/system/resources/kill", {
27
+ method: "POST",
28
+ headers,
29
+ body: JSON.stringify(request),
30
+ });
31
+
32
+ let json: { ok: boolean; data?: KillProcessResult; error?: string };
33
+ try {
34
+ json = await res.json();
35
+ } catch {
36
+ throw new Error(res.ok ? "Empty response from server" : `Server error (HTTP ${res.status})`);
37
+ }
38
+ if (json.ok === false) throw new Error(json.error ?? `HTTP ${res.status}`);
39
+ return json.data as KillProcessResult;
40
+ }
41
+
42
+ /**
43
+ * Pending-kill state plus the confirm handler for single processes and whole app
44
+ * groups. Members are resolved against the CURRENT snapshot at click time, so a
45
+ * helper that exited since the row was drawn is simply not in the list.
46
+ */
47
+ export function useProcessKill(snapshot: MetricsSnapshot) {
48
+ const [pendingKill, setPendingKill] = useState<KillTarget | null>(null);
49
+
50
+ const membersOf = useCallback(
51
+ (group: ProcessGroup): ProcessInfo[] => {
52
+ const byPid = new Map(snapshot.processes.map((p) => [p.pid, p]));
53
+ return group.pids.map((pid) => byPid.get(pid)).filter((p): p is ProcessInfo => !!p);
54
+ },
55
+ [snapshot.processes],
56
+ );
57
+
58
+ /** group key → true when any member is refused by the guard (button disabled). */
59
+ const groupProtected = useMemo(
60
+ () => new Map(snapshot.groups.map((g) => [g.key, isGroupProtected(membersOf(g))])),
61
+ [snapshot.groups, membersOf],
62
+ );
63
+
64
+ const requestKillProcess = useCallback((proc: ProcessInfo) => setPendingKill({ kind: "process", proc }), []);
65
+ const requestKillGroup = useCallback(
66
+ (group: ProcessGroup) => setPendingKill({ kind: "group", group, members: membersOf(group) }),
67
+ [membersOf],
68
+ );
69
+ const cancelKill = useCallback(() => setPendingKill(null), []);
70
+
71
+ const confirmKill = useCallback(async (target: KillTarget, tree: boolean) => {
72
+ setPendingKill(null);
73
+ if (target.kind === "process") {
74
+ const { proc } = target;
75
+ try {
76
+ await killProcess(buildKillRequest(proc, tree));
77
+ toast.success(`Ended ${proc.name} (${proc.pid})`);
78
+ } catch (e) {
79
+ toast.error(e instanceof Error ? e.message : `Failed to end ${proc.name}`);
80
+ }
81
+ return;
82
+ }
83
+ // Whole app: one tree kill on the root when it exists, else one per member.
84
+ // Requests run sequentially so the guard's 403/409 for one member is reported,
85
+ // not lost in a Promise.all rejection.
86
+ const { group, members } = target;
87
+ const failures: string[] = [];
88
+ for (const req of buildGroupKillRequests(group, members)) {
89
+ try {
90
+ await killProcess(req);
91
+ } catch (e) {
92
+ failures.push(e instanceof Error ? e.message : `pid ${req.pid}`);
93
+ }
94
+ }
95
+ if (failures.length === 0) toast.success(`Ended ${group.label} (${members.length} processes)`);
96
+ else toast.error(`${group.label}: ${failures.length} of ${members.length} could not be ended — ${failures[0]}`);
97
+ }, []);
98
+
99
+ return { pendingKill, groupProtected, requestKillProcess, requestKillGroup, confirmKill, cancelKill };
100
+ }
@@ -3,6 +3,7 @@ import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
3
3
  import { ContextMenu as ContextMenuPrimitive } from "radix-ui"
4
4
 
5
5
  import { cn } from "@/lib/utils"
6
+ import { usePortalContainer } from "./portal-container-context"
6
7
 
7
8
  function ContextMenu({
8
9
  ...props
@@ -27,10 +28,16 @@ function ContextMenuGroup({
27
28
  }
28
29
 
29
30
  function ContextMenuPortal({
31
+ container,
30
32
  ...props
31
33
  }: React.ComponentProps<typeof ContextMenuPrimitive.Portal>) {
34
+ const contextContainer = usePortalContainer()
32
35
  return (
33
- <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
36
+ <ContextMenuPrimitive.Portal
37
+ data-slot="context-menu-portal"
38
+ container={container ?? contextContainer}
39
+ {...props}
40
+ />
34
41
  )
35
42
  }
36
43
 
@@ -96,7 +103,7 @@ function ContextMenuContent({
96
103
  ...props
97
104
  }: React.ComponentProps<typeof ContextMenuPrimitive.Content>) {
98
105
  return (
99
- <ContextMenuPrimitive.Portal>
106
+ <ContextMenuPortal>
100
107
  <ContextMenuPrimitive.Content
101
108
  data-slot="context-menu-content"
102
109
  className={cn(
@@ -105,7 +112,7 @@ function ContextMenuContent({
105
112
  )}
106
113
  {...props}
107
114
  />
108
- </ContextMenuPrimitive.Portal>
115
+ </ContextMenuPortal>
109
116
  )
110
117
  }
111
118
 
@@ -4,6 +4,7 @@ import { Dialog as DialogPrimitive } from "radix-ui"
4
4
 
5
5
  import { cn } from "@/lib/utils"
6
6
  import { Button } from "@/components/ui/button"
7
+ import { usePortalContainer } from "./portal-container-context"
7
8
 
8
9
  function Dialog({
9
10
  ...props
@@ -18,9 +19,17 @@ function DialogTrigger({
18
19
  }
19
20
 
20
21
  function DialogPortal({
22
+ container,
21
23
  ...props
22
24
  }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
23
- return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
25
+ const contextContainer = usePortalContainer()
26
+ return (
27
+ <DialogPrimitive.Portal
28
+ data-slot="dialog-portal"
29
+ container={container ?? contextContainer}
30
+ {...props}
31
+ />
32
+ )
24
33
  }
25
34
 
26
35
  function DialogClose({
@@ -5,6 +5,7 @@ import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"
5
5
  import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui"
6
6
 
7
7
  import { cn } from "@/lib/utils"
8
+ import { usePortalContainer } from "./portal-container-context"
8
9
 
9
10
  function DropdownMenu({
10
11
  ...props
@@ -13,10 +14,16 @@ function DropdownMenu({
13
14
  }
14
15
 
15
16
  function DropdownMenuPortal({
17
+ container,
16
18
  ...props
17
19
  }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
20
+ const contextContainer = usePortalContainer()
18
21
  return (
19
- <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
22
+ <DropdownMenuPrimitive.Portal
23
+ data-slot="dropdown-menu-portal"
24
+ container={container ?? contextContainer}
25
+ {...props}
26
+ />
20
27
  )
21
28
  }
22
29
 
@@ -37,7 +44,7 @@ function DropdownMenuContent({
37
44
  ...props
38
45
  }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
39
46
  return (
40
- <DropdownMenuPrimitive.Portal>
47
+ <DropdownMenuPortal>
41
48
  <DropdownMenuPrimitive.Content
42
49
  data-slot="dropdown-menu-content"
43
50
  sideOffset={sideOffset}
@@ -47,7 +54,7 @@ function DropdownMenuContent({
47
54
  )}
48
55
  {...props}
49
56
  />
50
- </DropdownMenuPrimitive.Portal>
57
+ </DropdownMenuPortal>
51
58
  )
52
59
  }
53
60
 
@@ -11,6 +11,7 @@ import { createPortal } from "react-dom";
11
11
  import { cn } from "@/lib/utils";
12
12
  import { useSwipeToDismiss } from "@/hooks/use-swipe-to-dismiss";
13
13
  import { useVisualViewport } from "@/hooks/use-visual-viewport";
14
+ import { usePortalContainer } from "./portal-container-context";
14
15
 
15
16
  /* ------------------------------------------------------------------ */
16
17
  /* Core BottomSheet — reusable everywhere */
@@ -33,6 +34,7 @@ interface BottomSheetProps {
33
34
  export function BottomSheet({ open, onClose, children, className, zIndex = 50 }: BottomSheetProps) {
34
35
  const { dragY, swipeHandlers, dragStyle, backdropOpacity, isDragging } =
35
36
  useSwipeToDismiss(onClose);
37
+ const portalContainer = usePortalContainer();
36
38
 
37
39
  // Keyboard-aware geometry. The backdrop deliberately keeps covering the whole
38
40
  // layout viewport while only the panel tracks the keyboard: if the two ever
@@ -89,7 +91,7 @@ export function BottomSheet({ open, onClose, children, className, zIndex = 50 }:
89
91
  {children}
90
92
  </div>
91
93
  </div>,
92
- sheetPortalTarget(),
94
+ sheetPortalTarget(portalContainer),
93
95
  );
94
96
  }
95
97
 
@@ -103,10 +105,11 @@ export function BottomSheet({ open, onClose, children, className, zIndex = 50 }:
103
105
  * the event fired on (`body`), finds no match, and drops the event — every
104
106
  * button inside a dock tab goes dead while native listeners still fire.
105
107
  * `#root` carries no styles, so keeping the portal inside it leaves stacking
106
- * order untouched.
108
+ * order untouched. A caller-supplied `container` (`PortalContainerProvider`)
109
+ * wins over both fallbacks.
107
110
  */
108
- function sheetPortalTarget(): HTMLElement {
109
- return document.getElementById("root") ?? document.body;
111
+ function sheetPortalTarget(container?: HTMLElement): HTMLElement {
112
+ return container ?? document.getElementById("root") ?? document.body;
110
113
  }
111
114
 
112
115
  /* ------------------------------------------------------------------ */
@@ -0,0 +1,40 @@
1
+ import { createContext, useContext, type ReactNode } from "react";
2
+
3
+ /**
4
+ * Shared portal target for every Radix/portal-based primitive under
5
+ * `components/ui/`. `undefined` means "the document's default target" — Radix
6
+ * primitives fall back to `document.body`, `mobile-bottom-sheet.tsx` falls
7
+ * back to `#root`. Never pass `null`: Radix's `container` prop only applies
8
+ * its own default when the value is `undefined`, and `null` renders no
9
+ * portal at all.
10
+ *
11
+ * With no provider mounted, `usePortalContainer()` returns `undefined` and
12
+ * every primitive behaves exactly as it did before this context existed.
13
+ */
14
+ const PortalContainerContext = createContext<HTMLElement | undefined>(
15
+ undefined,
16
+ );
17
+
18
+ /**
19
+ * Mounts a portal target for all descendant Radix primitives. Pass
20
+ * `undefined` to explicitly restore the document default (e.g. once a
21
+ * picture-in-picture window closes).
22
+ */
23
+ export function PortalContainerProvider({
24
+ container,
25
+ children,
26
+ }: {
27
+ container: HTMLElement | undefined;
28
+ children: ReactNode;
29
+ }) {
30
+ return (
31
+ <PortalContainerContext.Provider value={container}>
32
+ {children}
33
+ </PortalContainerContext.Provider>
34
+ );
35
+ }
36
+
37
+ /** The caller-supplied portal container, or `undefined` outside any provider. */
38
+ export function usePortalContainer(): HTMLElement | undefined {
39
+ return useContext(PortalContainerContext);
40
+ }
@@ -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?) => {