@hienlh/ppm 0.23.6 → 0.23.7

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 (701) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/CLAUDE.md +21 -1
  3. package/Dockerfile.test +8 -1
  4. package/assets/skills/ppm/SKILL.md +1 -1
  5. package/assets/skills/ppm/references/cli-reference.md +4 -4
  6. package/assets/skills/ppm/references/http-api.md +29 -1
  7. package/dist/web/assets/accounts-settings-section-BYWnY9hH.js +1 -0
  8. package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.br +0 -0
  9. package/dist/web/assets/accounts-settings-section-BYWnY9hH.js.gz +0 -0
  10. package/dist/web/assets/{ai-resource-editor-Dn_wB-o5.js → ai-resource-editor-CY4n_Ccv.js} +1 -1
  11. package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.br +0 -0
  12. package/dist/web/assets/ai-resource-editor-CY4n_Ccv.js.gz +0 -0
  13. package/dist/web/assets/ai-settings-section-Bs3iUW4j.js +1 -0
  14. package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.br +0 -0
  15. package/dist/web/assets/ai-settings-section-Bs3iUW4j.js.gz +0 -0
  16. package/dist/web/assets/ai-settings-section-DDs11XV4.js +1 -0
  17. package/dist/web/assets/api-client-CJPnCOG-.js +1 -0
  18. package/dist/web/assets/{api-client-c8YOpTlT.js → api-client-D-SMbdiH.js} +1 -1
  19. package/dist/web/assets/api-client-D-SMbdiH.js.br +0 -0
  20. package/dist/web/assets/api-client-D-SMbdiH.js.gz +0 -0
  21. package/dist/web/assets/api-settings-BDkkhFMq.js +1 -0
  22. package/dist/web/assets/{api-settings-BmvNoCbn.js → api-settings-Bv9mLCty.js} +1 -1
  23. package/dist/web/assets/api-settings-Bv9mLCty.js.br +0 -0
  24. package/dist/web/assets/api-settings-Bv9mLCty.js.gz +0 -0
  25. package/dist/web/assets/{api-themes-6fOQJgM9.js → api-themes-3wW-zLzU.js} +1 -1
  26. package/dist/web/assets/appearance-settings-section-C0BoIBmz.js +1 -0
  27. package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.br +0 -0
  28. package/dist/web/assets/appearance-settings-section-C0BoIBmz.js.gz +0 -0
  29. package/dist/web/assets/apps-panel-DXAFsveZ.js +1 -0
  30. package/dist/web/assets/apps-panel-DXAFsveZ.js.br +0 -0
  31. package/dist/web/assets/apps-panel-DXAFsveZ.js.gz +0 -0
  32. package/dist/web/assets/{audio-preview-vaG2cB-k.js → audio-preview-BfES4Cx5.js} +1 -1
  33. package/dist/web/assets/audio-preview-BfES4Cx5.js.br +0 -0
  34. package/dist/web/assets/audio-preview-BfES4Cx5.js.gz +0 -0
  35. package/dist/web/assets/branch-review-tab-CA8hPSX9.js +1 -0
  36. package/dist/web/assets/branch-review-tab-CA8hPSX9.js.br +0 -0
  37. package/dist/web/assets/branch-review-tab-CA8hPSX9.js.gz +0 -0
  38. package/dist/web/assets/{button-Ci9EUgqd.js → button-DeAyLH9U.js} +1 -1
  39. package/dist/web/assets/button-DeAyLH9U.js.br +0 -0
  40. package/dist/web/assets/button-DeAyLH9U.js.gz +0 -0
  41. package/dist/web/assets/{chat-preparation-cache-BSIQGiWx.js → chat-preparation-cache-CcCd2g7A.js} +1 -1
  42. package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.br +0 -0
  43. package/dist/web/assets/chat-preparation-cache-CcCd2g7A.js.gz +0 -0
  44. package/dist/web/assets/chat-tab-BWi_bUzA.js +1 -0
  45. package/dist/web/assets/chat-tab-BWi_bUzA.js.br +0 -0
  46. package/dist/web/assets/chat-tab-BWi_bUzA.js.gz +0 -0
  47. package/dist/web/assets/chat-tab-BvJhIaVE.js +15 -0
  48. package/dist/web/assets/chat-tab-BvJhIaVE.js.br +0 -0
  49. package/dist/web/assets/chat-tab-BvJhIaVE.js.gz +0 -0
  50. package/dist/web/assets/code-editor-OJUdLVnn.js +7 -0
  51. package/dist/web/assets/code-editor-OJUdLVnn.js.br +0 -0
  52. package/dist/web/assets/code-editor-OJUdLVnn.js.gz +0 -0
  53. package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js +1 -0
  54. package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.br +0 -0
  55. package/dist/web/assets/codex-reset-credit-button-Dgxy_VNp.js.gz +0 -0
  56. package/dist/web/assets/{conflict-editor-BA3y-qSH.js → conflict-editor-BpKW_vbL.js} +1 -1
  57. package/dist/web/assets/conflict-editor-BpKW_vbL.js.br +0 -0
  58. package/dist/web/assets/conflict-editor-BpKW_vbL.js.gz +0 -0
  59. package/dist/web/assets/context-menu-7OX80HDB.js +1 -0
  60. package/dist/web/assets/context-menu-7OX80HDB.js.br +0 -0
  61. package/dist/web/assets/context-menu-7OX80HDB.js.gz +0 -0
  62. package/dist/web/assets/{csv-preview-BioxkrQF.js → csv-preview-COYdTABa.js} +1 -1
  63. package/dist/web/assets/csv-preview-COYdTABa.js.br +0 -0
  64. package/dist/web/assets/csv-preview-COYdTABa.js.gz +0 -0
  65. package/dist/web/assets/{data-grid-overlay-editor-CQRVKr7y.js → data-grid-overlay-editor-CeZoduke.js} +1 -1
  66. package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.br +0 -0
  67. package/dist/web/assets/data-grid-overlay-editor-CeZoduke.js.gz +0 -0
  68. package/dist/web/assets/{database-viewer-BSoJ0E6p.js → database-viewer-BQcBqCKm.js} +1 -1
  69. package/dist/web/assets/database-viewer-BQcBqCKm.js.br +0 -0
  70. package/dist/web/assets/database-viewer-BQcBqCKm.js.gz +0 -0
  71. package/dist/web/assets/{design-export-client-ChMcMoqW.js → design-export-client-OrnGCSwu.js} +1 -1
  72. package/dist/web/assets/design-export-client-OrnGCSwu.js.br +0 -0
  73. package/dist/web/assets/design-export-client-OrnGCSwu.js.gz +0 -0
  74. package/dist/web/assets/{design-responsive-dialog-DNBhJJLf.js → design-responsive-dialog-vJjQrC4n.js} +1 -1
  75. package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.br +0 -0
  76. package/dist/web/assets/design-responsive-dialog-vJjQrC4n.js.gz +0 -0
  77. package/dist/web/assets/design-tab-BbmFk38H.js +33 -0
  78. package/dist/web/assets/design-tab-BbmFk38H.js.br +0 -0
  79. package/dist/web/assets/design-tab-BbmFk38H.js.gz +0 -0
  80. package/dist/web/assets/{designs-sidebar-panel-DHh5QsH9.js → designs-sidebar-panel-D2kXwB8B.js} +1 -1
  81. package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.br +0 -0
  82. package/dist/web/assets/designs-sidebar-panel-D2kXwB8B.js.gz +0 -0
  83. package/dist/web/assets/dialog-Bocc0Fgb.js +1 -0
  84. package/dist/web/assets/dialog-Bocc0Fgb.js.br +0 -0
  85. package/dist/web/assets/dialog-Bocc0Fgb.js.gz +0 -0
  86. package/dist/web/assets/{diff-viewer-lctWoSmG.js → diff-viewer-Bj4DT6Mj.js} +1 -1
  87. package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.br +0 -0
  88. package/dist/web/assets/diff-viewer-Bj4DT6Mj.js.gz +0 -0
  89. package/dist/web/assets/{docx-preview-C9XdKEj1.js → docx-preview-C2QqNGRE.js} +1 -1
  90. package/dist/web/assets/docx-preview-C2QqNGRE.js.br +0 -0
  91. package/dist/web/assets/docx-preview-C2QqNGRE.js.gz +0 -0
  92. package/dist/web/assets/editor-language-service-COqB2tuv.js +1 -0
  93. package/dist/web/assets/editor-language-service-COqB2tuv.js.br +3 -0
  94. package/dist/web/assets/editor-language-service-COqB2tuv.js.gz +0 -0
  95. package/dist/web/assets/explorer-body-DGrYajDN.js +2 -0
  96. package/dist/web/assets/explorer-body-DGrYajDN.js.br +0 -0
  97. package/dist/web/assets/explorer-body-DGrYajDN.js.gz +0 -0
  98. package/dist/web/assets/explorer-window-content-DLzkODTP.js +1 -0
  99. package/dist/web/assets/explorer-window-content-DLzkODTP.js.br +0 -0
  100. package/dist/web/assets/explorer-window-content-DLzkODTP.js.gz +0 -0
  101. package/dist/web/assets/{extension-manager-section-rbkXsZVR.js → extension-manager-section-Bu0qcB2i.js} +1 -1
  102. package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.br +0 -0
  103. package/dist/web/assets/extension-manager-section-Bu0qcB2i.js.gz +0 -0
  104. package/dist/web/assets/{extension-webview-uPO0WgCq.js → extension-webview-G_WJ0N52.js} +1 -1
  105. package/dist/web/assets/extension-webview-G_WJ0N52.js.br +0 -0
  106. package/dist/web/assets/extension-webview-G_WJ0N52.js.gz +0 -0
  107. package/dist/web/assets/{file-icons-gx_FBOXY.js → file-icons-l7fNOmdS.js} +1 -1
  108. package/dist/web/assets/file-icons-l7fNOmdS.js.br +0 -0
  109. package/dist/web/assets/file-icons-l7fNOmdS.js.gz +0 -0
  110. package/dist/web/assets/{file-store-D9KE0kQC.js → file-store-B0e7sLag.js} +1 -1
  111. package/dist/web/assets/file-store-B0e7sLag.js.br +0 -0
  112. package/dist/web/assets/file-store-B0e7sLag.js.gz +0 -0
  113. package/dist/web/assets/{files-settings-section-CT7mDb0L.js → files-settings-section-ChZ_CynX.js} +1 -1
  114. package/dist/web/assets/files-settings-section-ChZ_CynX.js.br +0 -0
  115. package/dist/web/assets/files-settings-section-ChZ_CynX.js.gz +0 -0
  116. package/dist/web/assets/format-bytes-__396eCN.js +1 -0
  117. package/dist/web/assets/{format-file-meta-mQwA6SuY.js → format-file-meta-o1XBuoKS.js} +1 -1
  118. package/dist/web/assets/format-file-meta-o1XBuoKS.js.br +0 -0
  119. package/dist/web/assets/format-file-meta-o1XBuoKS.js.gz +0 -0
  120. package/dist/web/assets/{fs-api-DL36slbd.js → fs-api-CeHKwx95.js} +1 -1
  121. package/dist/web/assets/fs-api-CeHKwx95.js.br +0 -0
  122. package/dist/web/assets/fs-api-CeHKwx95.js.gz +0 -0
  123. package/dist/web/assets/{general-settings-section-DANPfMRN.js → general-settings-section-MSvDEbFa.js} +1 -1
  124. package/dist/web/assets/general-settings-section-MSvDEbFa.js.br +0 -0
  125. package/dist/web/assets/general-settings-section-MSvDEbFa.js.gz +0 -0
  126. package/dist/web/assets/{git-log-panel-BJPkLiEw.js → git-log-panel-gw5_a6j3.js} +1 -1
  127. package/dist/web/assets/git-log-panel-gw5_a6j3.js.br +0 -0
  128. package/dist/web/assets/git-log-panel-gw5_a6j3.js.gz +0 -0
  129. package/dist/web/assets/{git-repo-store-DSypNj19.js → git-repo-store-BpPnah5l.js} +1 -1
  130. package/dist/web/assets/git-repo-store-BpPnah5l.js.br +0 -0
  131. package/dist/web/assets/git-repo-store-BpPnah5l.js.gz +0 -0
  132. package/dist/web/assets/{glide-data-grid-R4PcAntf.js → glide-data-grid-Db2Cl26B.js} +5 -5
  133. package/dist/web/assets/glide-data-grid-Db2Cl26B.js.br +0 -0
  134. package/dist/web/assets/glide-data-grid-Db2Cl26B.js.gz +0 -0
  135. package/dist/web/assets/group-chat-tab-B4etmYTR.js +1 -0
  136. package/dist/web/assets/group-chat-tab-B4etmYTR.js.br +0 -0
  137. package/dist/web/assets/group-chat-tab-B4etmYTR.js.gz +0 -0
  138. package/dist/web/assets/{image-preview-CGdZrmLo.js → image-preview-CjNhpfWw.js} +1 -1
  139. package/dist/web/assets/index-CtAvmybi.js +52 -0
  140. package/dist/web/assets/index-CtAvmybi.js.br +0 -0
  141. package/dist/web/assets/index-CtAvmybi.js.gz +0 -0
  142. package/dist/web/assets/index-DeCJasyy.css +1 -0
  143. package/dist/web/assets/index-DeCJasyy.css.br +0 -0
  144. package/dist/web/assets/index-DeCJasyy.css.gz +0 -0
  145. package/dist/web/assets/{jira-watcher-section-DHRoyWcG.js → jira-watcher-section-CKSI1Alo.js} +1 -1
  146. package/dist/web/assets/keybindings-store-C4_yyU4u.js +1 -0
  147. package/dist/web/assets/{keyboard-shortcuts-section-BKej4mUf.js → keyboard-shortcuts-section-CEaVUc9a.js} +1 -1
  148. package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.br +0 -0
  149. package/dist/web/assets/keyboard-shortcuts-section-CEaVUc9a.js.gz +0 -0
  150. package/dist/web/assets/language-servers-section-ePtEpnDc.js +2 -0
  151. package/dist/web/assets/language-servers-section-ePtEpnDc.js.br +0 -0
  152. package/dist/web/assets/language-servers-section-ePtEpnDc.js.gz +0 -0
  153. package/dist/web/assets/lsp-client-XzmR3Brr.js +1 -0
  154. package/dist/web/assets/lsp-client-XzmR3Brr.js.br +0 -0
  155. package/dist/web/assets/lsp-client-XzmR3Brr.js.gz +0 -0
  156. package/dist/web/assets/markdown-renderer-CTtDap-l.js +1 -0
  157. package/dist/web/assets/{markdown-renderer-BHtYqkYZ.js → markdown-renderer-D05fAr57.js} +2 -2
  158. package/dist/web/assets/markdown-renderer-D05fAr57.js.br +0 -0
  159. package/dist/web/assets/markdown-renderer-D05fAr57.js.gz +0 -0
  160. package/dist/web/assets/{media-url-CzUJrREv.js → media-url-C6NumuN5.js} +1 -1
  161. package/dist/web/assets/metric-chart-canvas-DHJe0VER.js +1 -0
  162. package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.br +0 -0
  163. package/dist/web/assets/metric-chart-canvas-DHJe0VER.js.gz +0 -0
  164. package/dist/web/assets/{mobile-bottom-sheet-CuNi2FRv.js → mobile-bottom-sheet-D4UyOatB.js} +1 -1
  165. package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.br +0 -0
  166. package/dist/web/assets/mobile-bottom-sheet-D4UyOatB.js.gz +0 -0
  167. package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js +1 -0
  168. package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.br +0 -0
  169. package/dist/web/assets/mobile-explorer-sheet-CcfGdGL8.js.gz +0 -0
  170. package/dist/web/assets/{new-design-dialog-DS_XrpTG.js → new-design-dialog-BgmQopJM.js} +1 -1
  171. package/dist/web/assets/new-design-dialog-BgmQopJM.js.br +0 -0
  172. package/dist/web/assets/new-design-dialog-BgmQopJM.js.gz +0 -0
  173. package/dist/web/assets/notification-store-q5QBklKA.js +1 -0
  174. package/dist/web/assets/{notifications-settings-section-C05WYqcE.js → notifications-settings-section-BBJ0r9OS.js} +1 -1
  175. package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.br +0 -0
  176. package/dist/web/assets/notifications-settings-section-BBJ0r9OS.js.gz +0 -0
  177. package/dist/web/assets/{onboarding-entry-CmUqv1kl.js → onboarding-entry-BYOYswsi.js} +1 -1
  178. package/dist/web/assets/onboarding-entry-BYOYswsi.js.br +0 -0
  179. package/dist/web/assets/onboarding-entry-BYOYswsi.js.gz +0 -0
  180. package/dist/web/assets/{onboarding-quick-orientation-DIhWv1CN.js → onboarding-quick-orientation-DPHYFMbA.js} +1 -1
  181. package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.br +0 -0
  182. package/dist/web/assets/onboarding-quick-orientation-DPHYFMbA.js.gz +0 -0
  183. package/dist/web/assets/overview-panel-pkPs44Tv.js +1 -0
  184. package/dist/web/assets/overview-panel-pkPs44Tv.js.br +0 -0
  185. package/dist/web/assets/overview-panel-pkPs44Tv.js.gz +0 -0
  186. package/dist/web/assets/{pdf-preview-qdXmMkOR.js → pdf-preview-c-L_kDAs.js} +1 -1
  187. package/dist/web/assets/pdf-preview-c-L_kDAs.js.br +0 -0
  188. package/dist/web/assets/pdf-preview-c-L_kDAs.js.gz +0 -0
  189. package/dist/web/assets/performance-panel-yPrq0DJV.js +3 -0
  190. package/dist/web/assets/performance-panel-yPrq0DJV.js.br +0 -0
  191. package/dist/web/assets/performance-panel-yPrq0DJV.js.gz +0 -0
  192. package/dist/web/assets/{postgres-viewer-Xvlun_n5.js → postgres-viewer-CnwDCMNd.js} +1 -1
  193. package/dist/web/assets/postgres-viewer-CnwDCMNd.js.br +0 -0
  194. package/dist/web/assets/postgres-viewer-CnwDCMNd.js.gz +0 -0
  195. package/dist/web/assets/{ppmbot-settings-section-D8AES1BA.js → ppmbot-settings-section-BDXoSIDp.js} +1 -1
  196. package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.br +0 -0
  197. package/dist/web/assets/ppmbot-settings-section-BDXoSIDp.js.gz +0 -0
  198. package/dist/web/assets/{pptx-export-CG6MRNok.js → pptx-export-D0RDY48h.js} +4 -4
  199. package/dist/web/assets/pptx-export-D0RDY48h.js.br +0 -0
  200. package/dist/web/assets/pptx-export-D0RDY48h.js.gz +0 -0
  201. package/dist/web/assets/{problems-panel-DTBG4beI.js → problems-panel-BgY8oyo9.js} +1 -1
  202. package/dist/web/assets/problems-panel-BgY8oyo9.js.br +0 -0
  203. package/dist/web/assets/problems-panel-BgY8oyo9.js.gz +0 -0
  204. package/dist/web/assets/process-row-format-CaaMcHzn.js +1 -0
  205. package/dist/web/assets/process-table-BOwDtXuG.js +1 -0
  206. package/dist/web/assets/process-table-BOwDtXuG.js.br +0 -0
  207. package/dist/web/assets/process-table-BOwDtXuG.js.gz +0 -0
  208. package/dist/web/assets/{project-framework-store-XxFXcUpb.js → project-framework-store-UDEMu28U.js} +1 -1
  209. package/dist/web/assets/{project-store-C5gJXkvb.js → project-store-DGa31y5B.js} +1 -1
  210. package/dist/web/assets/project-store-DGa31y5B.js.br +0 -0
  211. package/dist/web/assets/project-store-DGa31y5B.js.gz +0 -0
  212. package/dist/web/assets/{proxy-settings-section-CqtmbeRj.js → proxy-settings-section-Db6Kc6xG.js} +1 -1
  213. package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.br +0 -0
  214. package/dist/web/assets/proxy-settings-section-Db6Kc6xG.js.gz +0 -0
  215. package/dist/web/assets/{query-audit-section-UKG_smyt.js → query-audit-section-C0PAXhfT.js} +1 -1
  216. package/dist/web/assets/query-audit-section-C0PAXhfT.js.br +0 -0
  217. package/dist/web/assets/query-audit-section-C0PAXhfT.js.gz +0 -0
  218. package/dist/web/assets/{remote-desktop-clipboard-notice-Djt6cpNL.js → remote-desktop-clipboard-notice-DOVtobj_.js} +1 -1
  219. package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.br +0 -0
  220. package/dist/web/assets/remote-desktop-clipboard-notice-DOVtobj_.js.gz +0 -0
  221. package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js +2 -0
  222. package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.br +0 -0
  223. package/dist/web/assets/remote-desktop-mobile-sheet-DXlU3msM.js.gz +0 -0
  224. package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js +1 -0
  225. package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.br +0 -0
  226. package/dist/web/assets/remote-desktop-mobile-view-ClV4YTLU.js.gz +0 -0
  227. package/dist/web/assets/{remote-desktop-readiness-gate-DNJF8TcF.js → remote-desktop-readiness-gate-BsfoJzdc.js} +1 -1
  228. package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.br +0 -0
  229. package/dist/web/assets/remote-desktop-readiness-gate-BsfoJzdc.js.gz +0 -0
  230. package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js +1 -0
  231. package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.br +0 -0
  232. package/dist/web/assets/remote-desktop-window-content-kDaXl1_Q.js.gz +0 -0
  233. package/dist/web/assets/{schedules-settings-section-BKoPovy2.js → schedules-settings-section-CvbjQM8z.js} +1 -1
  234. package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.br +0 -0
  235. package/dist/web/assets/schedules-settings-section-CvbjQM8z.js.gz +0 -0
  236. package/dist/web/assets/{scroll-area-XonvWYn_.js → scroll-area-sjOeAfoD.js} +1 -1
  237. package/dist/web/assets/scroll-area-sjOeAfoD.js.br +0 -0
  238. package/dist/web/assets/scroll-area-sjOeAfoD.js.gz +0 -0
  239. package/dist/web/assets/{separator-sQj04Ari.js → separator-9A3PCG1t.js} +1 -1
  240. package/dist/web/assets/services-panel-CimW47P8.js +1 -0
  241. package/dist/web/assets/services-panel-CimW47P8.js.br +0 -0
  242. package/dist/web/assets/services-panel-CimW47P8.js.gz +0 -0
  243. package/dist/web/assets/settings-body-BTXNtpWL.js +2 -0
  244. package/dist/web/assets/settings-body-BTXNtpWL.js.br +0 -0
  245. package/dist/web/assets/settings-body-BTXNtpWL.js.gz +0 -0
  246. package/dist/web/assets/settings-store-DvftLqzy.js +2 -0
  247. package/dist/web/assets/settings-store-DvftLqzy.js.br +0 -0
  248. package/dist/web/assets/settings-store-DvftLqzy.js.gz +0 -0
  249. package/dist/web/assets/settings-tab-CGhaRXjs.js +1 -0
  250. package/dist/web/assets/settings-window-content--Uyg_Psr.js +1 -0
  251. package/dist/web/assets/sortable-header-DUW9T1Hz.js +1 -0
  252. package/dist/web/assets/sortable-header-DUW9T1Hz.js.br +0 -0
  253. package/dist/web/assets/sortable-header-DUW9T1Hz.js.gz +0 -0
  254. package/dist/web/assets/{sql-query-editor-BjIMi9Wk.js → sql-query-editor-Dn-cgDrW.js} +1 -1
  255. package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.br +0 -0
  256. package/dist/web/assets/sql-query-editor-Dn-cgDrW.js.gz +0 -0
  257. package/dist/web/assets/{sqlite-viewer-BNcA6Irq.js → sqlite-viewer-B0NfaMjq.js} +1 -1
  258. package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.br +0 -0
  259. package/dist/web/assets/sqlite-viewer-B0NfaMjq.js.gz +0 -0
  260. package/dist/web/assets/system-monitor-body-CxCfRQFb.js +2 -0
  261. package/dist/web/assets/system-monitor-body-CxCfRQFb.js.br +0 -0
  262. package/dist/web/assets/system-monitor-body-CxCfRQFb.js.gz +0 -0
  263. package/dist/web/assets/system-monitor-tab-Cb3EZUdp.js +1 -0
  264. package/dist/web/assets/system-monitor-window-content-51CA-2PH.js +1 -0
  265. package/dist/web/assets/{tab-host-window-content-CIRGNCvi.js → tab-host-window-content-CSrcmKNG.js} +1 -1
  266. package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.br +0 -0
  267. package/dist/web/assets/tab-host-window-content-CSrcmKNG.js.gz +0 -0
  268. package/dist/web/assets/{team-member-sheet-CwXpLi3X.js → team-member-sheet-D4X6nh-x.js} +2 -2
  269. package/dist/web/assets/team-member-sheet-D4X6nh-x.js.br +0 -0
  270. package/dist/web/assets/team-member-sheet-D4X6nh-x.js.gz +0 -0
  271. package/dist/web/assets/{team-member-window-content-4swiiDz7.js → team-member-window-content-BxkbGVIL.js} +1 -1
  272. package/dist/web/assets/team-member-window-content-BxkbGVIL.js.br +0 -0
  273. package/dist/web/assets/team-member-window-content-BxkbGVIL.js.gz +0 -0
  274. package/dist/web/assets/{terminal-tab-BGcdtMMT.js → terminal-tab-BYo34IqU.js} +3 -3
  275. package/dist/web/assets/terminal-tab-BYo34IqU.js.br +0 -0
  276. package/dist/web/assets/terminal-tab-BYo34IqU.js.gz +0 -0
  277. package/dist/web/assets/{tool-cards-D0-krtA2.js → tool-cards-DvXjOped.js} +4 -4
  278. package/dist/web/assets/tool-cards-DvXjOped.js.br +0 -0
  279. package/dist/web/assets/tool-cards-DvXjOped.js.gz +0 -0
  280. package/dist/web/assets/{use-blob-url-CmavyEP8.js → use-blob-url-CISBWKG5.js} +1 -1
  281. package/dist/web/assets/use-inline-blame-Br6mheS4.js +16 -0
  282. package/dist/web/assets/use-inline-blame-Br6mheS4.js.br +0 -0
  283. package/dist/web/assets/use-inline-blame-Br6mheS4.js.gz +0 -0
  284. package/dist/web/assets/use-lsp-BpJmvQ0n.js +6 -0
  285. package/dist/web/assets/use-lsp-BpJmvQ0n.js.br +0 -0
  286. package/dist/web/assets/use-lsp-BpJmvQ0n.js.gz +0 -0
  287. package/dist/web/assets/{use-monaco-theme-C88KphGx.js → use-monaco-theme-UGOzyIhv.js} +1 -1
  288. package/dist/web/assets/use-process-kill-CyiiUD1E.js +1 -0
  289. package/dist/web/assets/use-process-kill-CyiiUD1E.js.br +0 -0
  290. package/dist/web/assets/use-process-kill-CyiiUD1E.js.gz +0 -0
  291. package/dist/web/assets/{use-websocket-Chk9guIU.js → use-websocket-Dpl21cHG.js} +1 -1
  292. package/dist/web/assets/{vendor-ui-BHh12_0v.js → vendor-ui-P9Ym7hCv.js} +1 -1
  293. package/dist/web/assets/vendor-ui-P9Ym7hCv.js.br +0 -0
  294. package/dist/web/assets/vendor-ui-P9Ym7hCv.js.gz +0 -0
  295. package/dist/web/assets/video-preview-D6Jw-IZK.js +1 -0
  296. package/dist/web/assets/video-preview-D6Jw-IZK.js.br +0 -0
  297. package/dist/web/assets/video-preview-D6Jw-IZK.js.gz +0 -0
  298. package/dist/web/assets/voice-settings-section-CcHQDYzN.js +1 -0
  299. package/dist/web/assets/voice-settings-section-CcHQDYzN.js.br +0 -0
  300. package/dist/web/assets/voice-settings-section-CcHQDYzN.js.gz +0 -0
  301. package/dist/web/assets/ws-auth-CqI8-aoA.js +1 -0
  302. package/dist/web/index.html +20 -20
  303. package/dist/web/index.html.br +0 -0
  304. package/dist/web/index.html.gz +0 -0
  305. package/dist/web/sw.js +1 -1
  306. package/dist/web/sw.js.br +0 -0
  307. package/dist/web/sw.js.gz +0 -0
  308. package/docs/deployment-guide.md +23 -0
  309. package/package.json +1 -1
  310. package/release-from-worktree.sh +224 -0
  311. package/src/cli/commands/config-cmd.ts +12 -0
  312. package/src/providers/claude-agent-sdk.ts +65 -2
  313. package/src/providers/codex-app-server/codex-jsonrpc-client.ts +16 -1
  314. package/src/providers/codex-app-server/codex-provider.ts +39 -7
  315. package/src/providers/provider-probe.ts +63 -0
  316. package/src/providers/registry.ts +109 -29
  317. package/src/server/index.ts +9 -0
  318. package/src/server/middleware/auth.ts +5 -1
  319. package/src/server/routes/cross-origin-guard.ts +20 -0
  320. package/src/server/routes/git.ts +40 -4
  321. package/src/server/routes/lsp.ts +97 -4
  322. package/src/server/routes/resources.ts +72 -9
  323. package/src/server/routes/settings.ts +19 -1
  324. package/src/server/routes/speech.ts +66 -0
  325. package/src/server/routes/system-services.ts +76 -0
  326. package/src/server/routes/tunnel.ts +33 -1
  327. package/src/server/ws/chat.ts +74 -3
  328. package/src/services/codex-account-login.ts +26 -2
  329. package/src/services/codex-reset-credit.service.ts +16 -3
  330. package/src/services/compaction-savings.ts +127 -0
  331. package/src/services/db.service.ts +123 -8
  332. package/src/services/fs-ops/fs-ops-trash.service.ts +22 -9
  333. package/src/services/git-refs/for-each-ref.ts +118 -0
  334. package/src/services/git.service.ts +25 -2
  335. package/src/services/host-info/spawn-runner.ts +48 -4
  336. package/src/services/jsonl-transcript-parser.ts +7 -42
  337. package/src/services/lsp/lsp-install.ts +289 -0
  338. package/src/services/lsp/lsp-manager.ts +160 -29
  339. package/src/services/lsp/server-registry.ts +120 -4
  340. package/src/services/named-tunnel/named-tunnel-config.ts +8 -2
  341. package/src/services/named-tunnel/named-tunnel-setup.service.ts +4 -0
  342. package/src/services/read-lines.ts +54 -0
  343. package/src/services/speech-to-text/whisper-catalog.ts +142 -0
  344. package/src/services/speech-to-text/whisper-download.ts +113 -0
  345. package/src/services/speech-to-text/whisper-hallucinations.ts +51 -0
  346. package/src/services/speech-to-text/whisper-install.service.ts +247 -0
  347. package/src/services/speech-to-text/whisper-paths.ts +62 -0
  348. package/src/services/speech-to-text/whisper-transcribe.service.ts +117 -0
  349. package/src/services/supervisor.ts +94 -11
  350. package/src/services/system-metrics/cpu-details-linux.ts +252 -0
  351. package/src/services/system-metrics/cpu-memory-collector.ts +140 -18
  352. package/src/services/system-metrics/device-collector-linux.ts +31 -0
  353. package/src/services/system-metrics/device-collector-types.ts +40 -0
  354. package/src/services/system-metrics/disk-devices-linux.ts +156 -0
  355. package/src/services/system-metrics/disk-inventory-linux.ts +150 -0
  356. package/src/services/system-metrics/fans-linux.ts +51 -0
  357. package/src/services/system-metrics/gpu-api-versions.ts +120 -0
  358. package/src/services/system-metrics/gpu-devices-linux.ts +370 -0
  359. package/src/services/system-metrics/gpu-fdinfo-linux.ts +253 -0
  360. package/src/services/system-metrics/hardware-inventory.ts +50 -0
  361. package/src/services/system-metrics/linux-fs.ts +43 -0
  362. package/src/services/system-metrics/memory-darwin.ts +91 -0
  363. package/src/services/system-metrics/memory-linux.ts +156 -0
  364. package/src/services/system-metrics/net-devices-linux.ts +114 -0
  365. package/src/services/system-metrics/net-inventory-linux.ts +100 -0
  366. package/src/services/system-metrics/partitions-linux.ts +158 -0
  367. package/src/services/system-metrics/process-collector-linux.ts +58 -6
  368. package/src/services/system-metrics/process-collector-types.ts +8 -1
  369. package/src/services/system-metrics/process-details-darwin.ts +166 -0
  370. package/src/services/system-metrics/process-details-linux.ts +150 -0
  371. package/src/services/system-metrics/process-grouping.ts +2 -1
  372. package/src/services/system-metrics/process-rows-builder.ts +2 -0
  373. package/src/services/system-metrics/process-swap-linux.ts +37 -0
  374. package/src/services/system-metrics/signal-executor.ts +84 -0
  375. package/src/services/system-metrics/signal-request-handler.ts +92 -0
  376. package/src/services/system-metrics/system-metrics-platform.ts +30 -4
  377. package/src/services/system-metrics/system-metrics-tick.ts +73 -4
  378. package/src/services/system-metrics/system-metrics.service.ts +87 -2
  379. package/src/services/system-metrics/udev-db.ts +40 -0
  380. package/src/services/system-services/app-cgroup-linux.ts +115 -0
  381. package/src/services/system-services/app-icon-service.ts +31 -0
  382. package/src/services/system-services/app-icons-linux.ts +124 -0
  383. package/src/services/system-services/apps-linux.ts +174 -0
  384. package/src/services/system-services/desktop-entry.ts +103 -0
  385. package/src/services/system-services/service-guard.ts +124 -0
  386. package/src/services/system-services/systemd-collector.ts +203 -0
  387. package/src/services/system-services/systemd-parse.ts +162 -0
  388. package/src/shared/prompt-cache-idle.ts +197 -0
  389. package/src/shared/turn-usage.ts +85 -1
  390. package/src/types/chat.ts +27 -0
  391. package/src/types/config.ts +14 -0
  392. package/src/types/git.ts +41 -0
  393. package/src/types/system-hardware.ts +137 -0
  394. package/src/types/system-metrics.ts +231 -2
  395. package/src/types/system-services.ts +73 -0
  396. package/src/web/components/branch-review/branch-review-tab.tsx +20 -20
  397. package/src/web/components/branch-review/branch-review-tree-row.tsx +1 -13
  398. package/src/web/components/chat/chat-tab.tsx +3 -0
  399. package/src/web/components/chat/compaction-divider.tsx +48 -0
  400. package/src/web/components/chat/idle-cache-notice.tsx +67 -0
  401. package/src/web/components/chat/message-input.tsx +48 -13
  402. package/src/web/components/chat/message-list.tsx +15 -0
  403. package/src/web/components/chat/prompt-cache-chip.tsx +74 -0
  404. package/src/web/components/editor/code-editor.tsx +1 -0
  405. package/src/web/components/editor/editor-language-service.tsx +11 -3
  406. package/src/web/components/editor/lsp-status.tsx +115 -13
  407. package/src/web/components/git/branch-picker.tsx +419 -0
  408. package/src/web/components/git/branch-select.tsx +34 -0
  409. package/src/web/components/git/create-worktree-dialog.tsx +17 -16
  410. package/src/web/components/git/git-repo-picker.tsx +28 -40
  411. package/src/web/components/layout/status-bar.tsx +42 -19
  412. package/src/web/components/settings/accounts/account-card.tsx +5 -1
  413. package/src/web/components/settings/ai-settings-section.tsx +67 -3
  414. package/src/web/components/settings/appearance-settings-section.tsx +2 -28
  415. package/src/web/components/settings/language-servers-section.tsx +362 -0
  416. package/src/web/components/settings/settings-categories.ts +8 -3
  417. package/src/web/components/settings/settings-section-content.tsx +2 -0
  418. package/src/web/components/settings/voice-settings-section.tsx +283 -0
  419. package/src/web/components/system/apps/app-row.tsx +110 -0
  420. package/src/web/components/system/apps/app-rows.ts +140 -0
  421. package/src/web/components/system/apps/apps-panel.tsx +129 -0
  422. package/src/web/components/system/metric-chart-canvas.tsx +79 -3
  423. package/src/web/components/system/overview-cards/card-shell.tsx +54 -0
  424. package/src/web/components/system/overview-cards/cpu-card.tsx +11 -6
  425. package/src/web/components/system/overview-cards/disk-card.tsx +11 -6
  426. package/src/web/components/system/overview-cards/gpu-card.tsx +16 -6
  427. package/src/web/components/system/overview-cards/mem-card.tsx +11 -6
  428. package/src/web/components/system/overview-cards/net-card.tsx +11 -6
  429. package/src/web/components/system/overview-device-target.ts +69 -0
  430. package/src/web/components/system/overview-panel.tsx +15 -1
  431. package/src/web/components/system/performance/cpu-core-grid.tsx +74 -0
  432. package/src/web/components/system/performance/cpu-detail.tsx +220 -0
  433. package/src/web/components/system/performance/detail-parts.tsx +149 -0
  434. package/src/web/components/system/performance/device-list.ts +139 -0
  435. package/src/web/components/system/performance/disk-detail.tsx +64 -0
  436. package/src/web/components/system/performance/fans-detail.tsx +35 -0
  437. package/src/web/components/system/performance/gpu-detail.tsx +116 -0
  438. package/src/web/components/system/performance/memory-detail.tsx +109 -0
  439. package/src/web/components/system/performance/nic-detail.tsx +55 -0
  440. package/src/web/components/system/performance/partition-list.tsx +79 -0
  441. package/src/web/components/system/performance/performance-panel.tsx +206 -0
  442. package/src/web/components/system/performance/use-hardware-inventory.ts +48 -0
  443. package/src/web/components/system/process-columns-grid.ts +5 -3
  444. package/src/web/components/system/process-details-dialog.tsx +116 -0
  445. package/src/web/components/system/process-group-row.tsx +6 -1
  446. package/src/web/components/system/process-row-format.ts +6 -0
  447. package/src/web/components/system/process-row-menu.tsx +72 -0
  448. package/src/web/components/system/process-row.tsx +7 -1
  449. package/src/web/components/system/process-table-model.ts +1 -1
  450. package/src/web/components/system/process-table-sort.ts +8 -4
  451. package/src/web/components/system/process-table-toolbar.tsx +10 -2
  452. package/src/web/components/system/process-table-totals.ts +3 -0
  453. package/src/web/components/system/process-table.tsx +25 -2
  454. package/src/web/components/system/services/service-action-confirm.tsx +100 -0
  455. package/src/web/components/system/services/service-columns.ts +103 -0
  456. package/src/web/components/system/services/service-details-sheet.tsx +97 -0
  457. package/src/web/components/system/services/service-resources.ts +105 -0
  458. package/src/web/components/system/services/service-row.tsx +146 -0
  459. package/src/web/components/system/services/service-rows.ts +92 -0
  460. package/src/web/components/system/services/service-sort.ts +90 -0
  461. package/src/web/components/system/services/services-header.tsx +51 -0
  462. package/src/web/components/system/services/services-panel.tsx +207 -0
  463. package/src/web/components/system/services/use-services.ts +92 -0
  464. package/src/web/components/system/sortable-header.tsx +13 -8
  465. package/src/web/components/system/sysmon-preferences.tsx +85 -0
  466. package/src/web/components/system/system-monitor-body.tsx +101 -43
  467. package/src/web/components/system/system-monitor-window-content.tsx +2 -3
  468. package/src/web/components/system/use-process-signal.ts +87 -0
  469. package/src/web/components/tunnels/public-tunnel-switch.tsx +82 -0
  470. package/src/web/components/tunnels/tunnel-manager-tab.tsx +4 -0
  471. package/src/web/components/ui/dialog.tsx +14 -1
  472. package/src/web/components/ui/search-select.tsx +279 -0
  473. package/src/web/components/ui/start-ellipsis.tsx +18 -0
  474. package/src/web/hooks/use-chat.ts +28 -0
  475. package/src/web/hooks/use-global-keybindings.ts +7 -5
  476. package/src/web/hooks/use-lsp.ts +23 -2
  477. package/src/web/hooks/use-minute-clock.ts +20 -0
  478. package/src/web/hooks/use-whisper-voice-input.ts +113 -0
  479. package/src/web/lib/api-tunnels.ts +19 -0
  480. package/src/web/lib/branch-select-items.ts +29 -0
  481. package/src/web/lib/cpu-graph-mode.ts +90 -0
  482. package/src/web/lib/format-bytes.ts +14 -0
  483. package/src/web/lib/git-ref-picker.ts +120 -0
  484. package/src/web/lib/lsp/lsp-client.ts +32 -0
  485. package/src/web/lib/search-select-rows.ts +55 -0
  486. package/src/web/lib/temperature.ts +27 -0
  487. package/src/web/lib/voice-wav.ts +69 -0
  488. package/src/web/stores/git-status-store.ts +31 -17
  489. package/src/web/stores/keybindings-store.ts +14 -1
  490. package/src/web/stores/settings-store.ts +65 -0
  491. package/src/web/styles/globals.css +11 -0
  492. package/dist/web/assets/accounts-settings-section-DUVO32SQ.js +0 -1
  493. package/dist/web/assets/accounts-settings-section-DUVO32SQ.js.br +0 -0
  494. package/dist/web/assets/accounts-settings-section-DUVO32SQ.js.gz +0 -0
  495. package/dist/web/assets/ai-resource-editor-Dn_wB-o5.js.br +0 -0
  496. package/dist/web/assets/ai-resource-editor-Dn_wB-o5.js.gz +0 -0
  497. package/dist/web/assets/ai-settings-section-CEbW8jRy.js +0 -1
  498. package/dist/web/assets/ai-settings-section-CEbW8jRy.js.br +0 -0
  499. package/dist/web/assets/ai-settings-section-CEbW8jRy.js.gz +0 -0
  500. package/dist/web/assets/ai-settings-section-D-mwEYFZ.js +0 -1
  501. package/dist/web/assets/api-client-BgedDTvo.js +0 -1
  502. package/dist/web/assets/api-client-c8YOpTlT.js.br +0 -0
  503. package/dist/web/assets/api-client-c8YOpTlT.js.gz +0 -0
  504. package/dist/web/assets/api-settings-BmvNoCbn.js.br +0 -0
  505. package/dist/web/assets/api-settings-BmvNoCbn.js.gz +0 -0
  506. package/dist/web/assets/api-settings-Bti1-Zn3.js +0 -1
  507. package/dist/web/assets/appearance-settings-section-tw6TpFb6.js +0 -1
  508. package/dist/web/assets/appearance-settings-section-tw6TpFb6.js.br +0 -0
  509. package/dist/web/assets/appearance-settings-section-tw6TpFb6.js.gz +0 -0
  510. package/dist/web/assets/audio-preview-vaG2cB-k.js.br +0 -0
  511. package/dist/web/assets/audio-preview-vaG2cB-k.js.gz +0 -0
  512. package/dist/web/assets/branch-review-tab-MBuMWp_i.js +0 -1
  513. package/dist/web/assets/branch-review-tab-MBuMWp_i.js.br +0 -0
  514. package/dist/web/assets/branch-review-tab-MBuMWp_i.js.gz +0 -0
  515. package/dist/web/assets/button-Ci9EUgqd.js.br +0 -0
  516. package/dist/web/assets/button-Ci9EUgqd.js.gz +0 -0
  517. package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.br +0 -0
  518. package/dist/web/assets/chat-preparation-cache-BSIQGiWx.js.gz +0 -0
  519. package/dist/web/assets/chat-tab-DVvnqhw6.js +0 -1
  520. package/dist/web/assets/chat-tab-DVvnqhw6.js.br +0 -0
  521. package/dist/web/assets/chat-tab-DVvnqhw6.js.gz +0 -0
  522. package/dist/web/assets/chat-tab-DaEHva22.js +0 -15
  523. package/dist/web/assets/chat-tab-DaEHva22.js.br +0 -0
  524. package/dist/web/assets/chat-tab-DaEHva22.js.gz +0 -0
  525. package/dist/web/assets/code-editor-Bu9lhTVp.js +0 -7
  526. package/dist/web/assets/code-editor-Bu9lhTVp.js.br +0 -0
  527. package/dist/web/assets/code-editor-Bu9lhTVp.js.gz +0 -0
  528. package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js +0 -1
  529. package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js.br +0 -0
  530. package/dist/web/assets/codex-reset-credit-button-CbmE5mRX.js.gz +0 -0
  531. package/dist/web/assets/conflict-editor-BA3y-qSH.js.br +0 -0
  532. package/dist/web/assets/conflict-editor-BA3y-qSH.js.gz +0 -0
  533. package/dist/web/assets/context-menu-CjYTq8DI.js +0 -1
  534. package/dist/web/assets/context-menu-CjYTq8DI.js.br +0 -0
  535. package/dist/web/assets/context-menu-CjYTq8DI.js.gz +0 -0
  536. package/dist/web/assets/csv-preview-BioxkrQF.js.br +0 -0
  537. package/dist/web/assets/csv-preview-BioxkrQF.js.gz +0 -0
  538. package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.br +0 -0
  539. package/dist/web/assets/data-grid-overlay-editor-CQRVKr7y.js.gz +0 -0
  540. package/dist/web/assets/database-viewer-BSoJ0E6p.js.br +0 -0
  541. package/dist/web/assets/database-viewer-BSoJ0E6p.js.gz +0 -0
  542. package/dist/web/assets/design-export-client-ChMcMoqW.js.br +0 -0
  543. package/dist/web/assets/design-export-client-ChMcMoqW.js.gz +0 -0
  544. package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.br +0 -0
  545. package/dist/web/assets/design-responsive-dialog-DNBhJJLf.js.gz +0 -0
  546. package/dist/web/assets/design-tab-iU2CviE3.js +0 -33
  547. package/dist/web/assets/design-tab-iU2CviE3.js.br +0 -0
  548. package/dist/web/assets/design-tab-iU2CviE3.js.gz +0 -0
  549. package/dist/web/assets/designs-sidebar-panel-DHh5QsH9.js.br +0 -0
  550. package/dist/web/assets/designs-sidebar-panel-DHh5QsH9.js.gz +0 -0
  551. package/dist/web/assets/dialog-B8clVkyi.js +0 -1
  552. package/dist/web/assets/dialog-B8clVkyi.js.br +0 -0
  553. package/dist/web/assets/dialog-B8clVkyi.js.gz +0 -0
  554. package/dist/web/assets/diff-viewer-lctWoSmG.js.br +0 -0
  555. package/dist/web/assets/diff-viewer-lctWoSmG.js.gz +0 -0
  556. package/dist/web/assets/docx-preview-C9XdKEj1.js.br +0 -0
  557. package/dist/web/assets/docx-preview-C9XdKEj1.js.gz +0 -0
  558. package/dist/web/assets/editor-language-service-fPG56hQO.js +0 -1
  559. package/dist/web/assets/editor-language-service-fPG56hQO.js.br +0 -0
  560. package/dist/web/assets/editor-language-service-fPG56hQO.js.gz +0 -0
  561. package/dist/web/assets/explorer-body-BgF7FsxI.js +0 -2
  562. package/dist/web/assets/explorer-body-BgF7FsxI.js.br +0 -0
  563. package/dist/web/assets/explorer-body-BgF7FsxI.js.gz +0 -0
  564. package/dist/web/assets/explorer-window-content-C21w_7lf.js +0 -1
  565. package/dist/web/assets/explorer-window-content-C21w_7lf.js.br +0 -0
  566. package/dist/web/assets/explorer-window-content-C21w_7lf.js.gz +0 -0
  567. package/dist/web/assets/extension-manager-section-rbkXsZVR.js.br +0 -0
  568. package/dist/web/assets/extension-manager-section-rbkXsZVR.js.gz +0 -0
  569. package/dist/web/assets/extension-webview-uPO0WgCq.js.br +0 -0
  570. package/dist/web/assets/extension-webview-uPO0WgCq.js.gz +0 -0
  571. package/dist/web/assets/file-icons-gx_FBOXY.js.br +0 -0
  572. package/dist/web/assets/file-icons-gx_FBOXY.js.gz +0 -0
  573. package/dist/web/assets/file-store-D9KE0kQC.js.br +0 -0
  574. package/dist/web/assets/file-store-D9KE0kQC.js.gz +0 -0
  575. package/dist/web/assets/files-settings-section-CT7mDb0L.js.br +0 -0
  576. package/dist/web/assets/files-settings-section-CT7mDb0L.js.gz +0 -0
  577. package/dist/web/assets/format-bytes-DmSHAKFe.js +0 -1
  578. package/dist/web/assets/format-file-meta-mQwA6SuY.js.br +0 -0
  579. package/dist/web/assets/format-file-meta-mQwA6SuY.js.gz +0 -0
  580. package/dist/web/assets/fs-api-DL36slbd.js.br +0 -0
  581. package/dist/web/assets/fs-api-DL36slbd.js.gz +0 -0
  582. package/dist/web/assets/general-settings-section-DANPfMRN.js.br +0 -0
  583. package/dist/web/assets/general-settings-section-DANPfMRN.js.gz +0 -0
  584. package/dist/web/assets/git-log-panel-BJPkLiEw.js.br +0 -0
  585. package/dist/web/assets/git-log-panel-BJPkLiEw.js.gz +0 -0
  586. package/dist/web/assets/git-repo-store-DSypNj19.js.br +0 -0
  587. package/dist/web/assets/git-repo-store-DSypNj19.js.gz +0 -0
  588. package/dist/web/assets/glide-data-grid-R4PcAntf.js.br +0 -0
  589. package/dist/web/assets/glide-data-grid-R4PcAntf.js.gz +0 -0
  590. package/dist/web/assets/group-chat-tab-BXMdo8w9.js +0 -1
  591. package/dist/web/assets/group-chat-tab-BXMdo8w9.js.br +0 -0
  592. package/dist/web/assets/group-chat-tab-BXMdo8w9.js.gz +0 -0
  593. package/dist/web/assets/index-C8nGqkKN.js +0 -52
  594. package/dist/web/assets/index-C8nGqkKN.js.br +0 -0
  595. package/dist/web/assets/index-C8nGqkKN.js.gz +0 -0
  596. package/dist/web/assets/index-DvClbTQx.css +0 -1
  597. package/dist/web/assets/index-DvClbTQx.css.br +0 -0
  598. package/dist/web/assets/index-DvClbTQx.css.gz +0 -0
  599. package/dist/web/assets/keybindings-store-BGKlQQAv.js +0 -1
  600. package/dist/web/assets/keyboard-shortcuts-section-BKej4mUf.js.br +0 -0
  601. package/dist/web/assets/keyboard-shortcuts-section-BKej4mUf.js.gz +0 -0
  602. package/dist/web/assets/markdown-renderer-BHtYqkYZ.js.br +0 -0
  603. package/dist/web/assets/markdown-renderer-BHtYqkYZ.js.gz +0 -0
  604. package/dist/web/assets/markdown-renderer-vDNuKjel.js +0 -1
  605. package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.br +0 -0
  606. package/dist/web/assets/mobile-bottom-sheet-CuNi2FRv.js.gz +0 -0
  607. package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js +0 -1
  608. package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js.br +0 -0
  609. package/dist/web/assets/mobile-explorer-sheet-DtvxS7-r.js.gz +0 -0
  610. package/dist/web/assets/new-design-dialog-DS_XrpTG.js.br +0 -0
  611. package/dist/web/assets/new-design-dialog-DS_XrpTG.js.gz +0 -0
  612. package/dist/web/assets/notification-store-Dnnj20Ky.js +0 -1
  613. package/dist/web/assets/notifications-settings-section-C05WYqcE.js.br +0 -0
  614. package/dist/web/assets/notifications-settings-section-C05WYqcE.js.gz +0 -0
  615. package/dist/web/assets/onboarding-entry-CmUqv1kl.js.br +0 -0
  616. package/dist/web/assets/onboarding-entry-CmUqv1kl.js.gz +0 -0
  617. package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.br +0 -0
  618. package/dist/web/assets/onboarding-quick-orientation-DIhWv1CN.js.gz +0 -0
  619. package/dist/web/assets/overview-panel-BZAW_nag.js +0 -1
  620. package/dist/web/assets/overview-panel-BZAW_nag.js.br +0 -0
  621. package/dist/web/assets/overview-panel-BZAW_nag.js.gz +0 -0
  622. package/dist/web/assets/pdf-preview-qdXmMkOR.js.br +0 -0
  623. package/dist/web/assets/pdf-preview-qdXmMkOR.js.gz +0 -0
  624. package/dist/web/assets/postgres-viewer-Xvlun_n5.js.br +0 -0
  625. package/dist/web/assets/postgres-viewer-Xvlun_n5.js.gz +0 -0
  626. package/dist/web/assets/ppmbot-settings-section-D8AES1BA.js.br +0 -0
  627. package/dist/web/assets/ppmbot-settings-section-D8AES1BA.js.gz +0 -0
  628. package/dist/web/assets/pptx-export-CG6MRNok.js.br +0 -0
  629. package/dist/web/assets/pptx-export-CG6MRNok.js.gz +0 -0
  630. package/dist/web/assets/problems-panel-DTBG4beI.js.br +0 -0
  631. package/dist/web/assets/problems-panel-DTBG4beI.js.gz +0 -0
  632. package/dist/web/assets/process-table-D_gR2XA6.js +0 -1
  633. package/dist/web/assets/process-table-D_gR2XA6.js.br +0 -0
  634. package/dist/web/assets/process-table-D_gR2XA6.js.gz +0 -0
  635. package/dist/web/assets/project-store-C5gJXkvb.js.br +0 -0
  636. package/dist/web/assets/project-store-C5gJXkvb.js.gz +0 -0
  637. package/dist/web/assets/proxy-settings-section-CqtmbeRj.js.br +0 -0
  638. package/dist/web/assets/proxy-settings-section-CqtmbeRj.js.gz +0 -0
  639. package/dist/web/assets/query-audit-section-UKG_smyt.js.br +0 -0
  640. package/dist/web/assets/query-audit-section-UKG_smyt.js.gz +0 -0
  641. package/dist/web/assets/remote-desktop-clipboard-notice-Djt6cpNL.js.br +0 -0
  642. package/dist/web/assets/remote-desktop-clipboard-notice-Djt6cpNL.js.gz +0 -0
  643. package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js +0 -2
  644. package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js.br +0 -0
  645. package/dist/web/assets/remote-desktop-mobile-sheet-BQxhJUkm.js.gz +0 -0
  646. package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js +0 -1
  647. package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js.br +0 -0
  648. package/dist/web/assets/remote-desktop-mobile-view-DGnT8RY7.js.gz +0 -0
  649. package/dist/web/assets/remote-desktop-readiness-gate-DNJF8TcF.js.br +0 -0
  650. package/dist/web/assets/remote-desktop-readiness-gate-DNJF8TcF.js.gz +0 -0
  651. package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js +0 -1
  652. package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js.br +0 -0
  653. package/dist/web/assets/remote-desktop-window-content-Ds0DKmM0.js.gz +0 -0
  654. package/dist/web/assets/schedules-settings-section-BKoPovy2.js.br +0 -0
  655. package/dist/web/assets/schedules-settings-section-BKoPovy2.js.gz +0 -0
  656. package/dist/web/assets/scroll-area-XonvWYn_.js.br +0 -0
  657. package/dist/web/assets/scroll-area-XonvWYn_.js.gz +0 -0
  658. package/dist/web/assets/settings-body-k2qPgRFe.js +0 -2
  659. package/dist/web/assets/settings-body-k2qPgRFe.js.br +0 -0
  660. package/dist/web/assets/settings-body-k2qPgRFe.js.gz +0 -0
  661. package/dist/web/assets/settings-store-Br5c1efC.js +0 -2
  662. package/dist/web/assets/settings-store-Br5c1efC.js.br +0 -0
  663. package/dist/web/assets/settings-store-Br5c1efC.js.gz +0 -0
  664. package/dist/web/assets/settings-tab-Bb23VdBu.js +0 -1
  665. package/dist/web/assets/settings-window-content-ClarWusz.js +0 -1
  666. package/dist/web/assets/sql-query-editor-BjIMi9Wk.js.br +0 -0
  667. package/dist/web/assets/sql-query-editor-BjIMi9Wk.js.gz +0 -0
  668. package/dist/web/assets/sqlite-viewer-BNcA6Irq.js.br +0 -0
  669. package/dist/web/assets/sqlite-viewer-BNcA6Irq.js.gz +0 -0
  670. package/dist/web/assets/system-monitor-body-D0T3ggt2.js +0 -2
  671. package/dist/web/assets/system-monitor-body-D0T3ggt2.js.br +0 -0
  672. package/dist/web/assets/system-monitor-body-D0T3ggt2.js.gz +0 -0
  673. package/dist/web/assets/system-monitor-tab-I1Igmoey.js +0 -1
  674. package/dist/web/assets/system-monitor-window-content-C5SeUv1H.js +0 -1
  675. package/dist/web/assets/tab-host-window-content-CIRGNCvi.js.br +0 -0
  676. package/dist/web/assets/tab-host-window-content-CIRGNCvi.js.gz +0 -0
  677. package/dist/web/assets/team-member-sheet-CwXpLi3X.js.br +0 -0
  678. package/dist/web/assets/team-member-sheet-CwXpLi3X.js.gz +0 -0
  679. package/dist/web/assets/team-member-window-content-4swiiDz7.js.br +0 -0
  680. package/dist/web/assets/team-member-window-content-4swiiDz7.js.gz +0 -0
  681. package/dist/web/assets/terminal-tab-BGcdtMMT.js.br +0 -0
  682. package/dist/web/assets/terminal-tab-BGcdtMMT.js.gz +0 -0
  683. package/dist/web/assets/tool-cards-D0-krtA2.js.br +0 -0
  684. package/dist/web/assets/tool-cards-D0-krtA2.js.gz +0 -0
  685. package/dist/web/assets/use-inline-blame-pKaXyGU-.js +0 -16
  686. package/dist/web/assets/use-inline-blame-pKaXyGU-.js.br +0 -0
  687. package/dist/web/assets/use-inline-blame-pKaXyGU-.js.gz +0 -0
  688. package/dist/web/assets/use-lsp-71azTXQz.js +0 -6
  689. package/dist/web/assets/use-lsp-71azTXQz.js.br +0 -0
  690. package/dist/web/assets/use-lsp-71azTXQz.js.gz +0 -0
  691. package/dist/web/assets/vendor-ui-BHh12_0v.js.br +0 -0
  692. package/dist/web/assets/vendor-ui-BHh12_0v.js.gz +0 -0
  693. package/dist/web/assets/video-preview-DxEX-uGo.js +0 -1
  694. package/dist/web/assets/video-preview-DxEX-uGo.js.br +0 -0
  695. package/dist/web/assets/video-preview-DxEX-uGo.js.gz +0 -0
  696. package/dist/web/assets/ws-auth-kXgsX2Js.js +0 -1
  697. /package/dist/web/assets/{__vite-browser-external-BpSQWxcq.js → __vite-browser-external-BILfYaAs.js} +0 -0
  698. /package/dist/web/assets/{run-in-terminal-HIdNgYim.js → run-in-terminal-2pSiup8e.js} +0 -0
  699. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js → vendor-xterm-DF1JTfsy.js} +0 -0
  700. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.br → vendor-xterm-DF1JTfsy.js.br} +0 -0
  701. /package/dist/web/assets/{vendor-xterm-DLDtzLib.js.gz → vendor-xterm-DF1JTfsy.js.gz} +0 -0
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Sending one signal to a process — Mission Center's "Send Signal" submenu.
3
+ *
4
+ * Separate from `useProcessKill` because the two mean different things: a kill
5
+ * escalates TERM to KILL, while asking for SIGSTOP must send SIGSTOP and nothing
6
+ * else. The server enforces the SAME guard for both, so a process the kill button
7
+ * refuses cannot be suspended either.
8
+ */
9
+ import { useCallback, useState } from "react";
10
+ import { toast } from "sonner";
11
+ import { getAuthToken } from "@/lib/api-client";
12
+ import type {
13
+ ProcessInfo, ProcessSignal, SignalProcessRequest, SignalProcessResult,
14
+ } from "../../../types/system-metrics";
15
+
16
+ /** Human wording for the menu, in the order Mission Center lists them. */
17
+ export const SIGNAL_LABELS: Record<ProcessSignal, string> = {
18
+ STOP: "Suspend (SIGSTOP)",
19
+ CONT: "Continue (SIGCONT)",
20
+ TERM: "Terminate (SIGTERM)",
21
+ KILL: "Kill (SIGKILL)",
22
+ HUP: "Hang up (SIGHUP)",
23
+ INT: "Interrupt (SIGINT)",
24
+ USR1: "User signal 1",
25
+ USR2: "User signal 2",
26
+ };
27
+
28
+ /** The two that cannot be caught or ignored, so the UI can warn before sending. */
29
+ export const UNCATCHABLE_SIGNALS: readonly ProcessSignal[] = ["KILL", "STOP"];
30
+
31
+ /** `api.post` has no way to add the `X-PPM-Request` header the route requires,
32
+ * so this mirrors `killProcess` exactly — one Error on any failure. */
33
+ export async function signalProcess(request: SignalProcessRequest): Promise<SignalProcessResult> {
34
+ const token = getAuthToken();
35
+ const headers: Record<string, string> = {
36
+ "Content-Type": "application/json",
37
+ "X-PPM-Request": "1",
38
+ };
39
+ if (token) headers.Authorization = `Bearer ${token}`;
40
+
41
+ const res = await fetch("/api/system/resources/signal", {
42
+ method: "POST",
43
+ headers,
44
+ body: JSON.stringify(request),
45
+ });
46
+ let json: { ok: boolean; data?: SignalProcessResult; error?: string };
47
+ try {
48
+ json = await res.json();
49
+ } catch {
50
+ throw new Error(res.ok ? "Empty response from server" : `Server error (HTTP ${res.status})`);
51
+ }
52
+ if (json.ok === false) throw new Error(json.error ?? `HTTP ${res.status}`);
53
+ return json.data as SignalProcessResult;
54
+ }
55
+
56
+ export function buildSignalRequest(
57
+ proc: ProcessInfo,
58
+ signal: ProcessSignal,
59
+ tree: boolean,
60
+ ): SignalProcessRequest {
61
+ // `startedAt` is the identity guard: a recycled pid is a 409, never a signal
62
+ // delivered to whatever took the number over.
63
+ return { pid: proc.pid, startedAt: proc.startedAt, signal, tree };
64
+ }
65
+
66
+ export function useProcessSignal() {
67
+ const [pending, setPending] = useState<number | null>(null);
68
+
69
+ const send = useCallback(async (proc: ProcessInfo, signal: ProcessSignal, tree = false) => {
70
+ setPending(proc.pid);
71
+ try {
72
+ const result = await signalProcess(buildSignalRequest(proc, signal, tree));
73
+ const count = result.signalled.length;
74
+ toast.success(
75
+ count > 1
76
+ ? `Sent SIG${signal} to ${proc.name} and ${count - 1} child processes`
77
+ : `Sent SIG${signal} to ${proc.name} (${proc.pid})`,
78
+ );
79
+ } catch (e) {
80
+ toast.error(e instanceof Error ? e.message : `Could not signal ${proc.name}`);
81
+ } finally {
82
+ setPending(null);
83
+ }
84
+ }, []);
85
+
86
+ return { send, pending };
87
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Master on/off switch for PPM's own public tunnel.
3
+ *
4
+ * The switch only writes config — the supervisor owns the cloudflared process
5
+ * and picks the change up as a `retunnel` — so "switched on" and "actually
6
+ * reachable" are a few seconds apart. The row reports both rather than
7
+ * pretending the toggle is instant, and polls on the same 10s cadence as the
8
+ * tunnel list below it.
9
+ */
10
+ import { useCallback, useEffect, useState } from "react";
11
+ import { Globe, Loader2 } from "@/lib/icons";
12
+ import { Switch } from "@/components/ui/switch";
13
+ import { toast } from "sonner";
14
+ import { publicTunnelApi, type PublicTunnelStatus } from "@/lib/api-tunnels";
15
+
16
+ export function PublicTunnelSwitch() {
17
+ const [status, setStatus] = useState<PublicTunnelStatus | null>(null);
18
+ const [pending, setPending] = useState(false);
19
+
20
+ const refresh = useCallback(async () => {
21
+ try {
22
+ setStatus(await publicTunnelApi.status());
23
+ } catch {
24
+ // Keep the last known state — a failed poll is not a state change.
25
+ }
26
+ }, []);
27
+
28
+ useEffect(() => {
29
+ refresh();
30
+ const interval = setInterval(refresh, 10_000);
31
+ return () => clearInterval(interval);
32
+ }, [refresh]);
33
+
34
+ // Nothing to toggle until the first read lands; rendering a default-on switch
35
+ // first would flicker to off on every load of a machine that has it off.
36
+ if (!status) return null;
37
+
38
+ // Absent on a server that predates the switch, where the tunnel was
39
+ // unconditional — so absent reads as on, never off.
40
+ const enabled = status.enabled ?? true;
41
+ const starting = enabled && !status.active;
42
+
43
+ async function toggle(next: boolean) {
44
+ setPending(true);
45
+ setStatus((s) => (s ? { ...s, enabled: next } : s));
46
+ try {
47
+ await publicTunnelApi.setEnabled(next);
48
+ await refresh();
49
+ } catch (e) {
50
+ setStatus((s) => (s ? { ...s, enabled: !next } : s));
51
+ toast.error(e instanceof Error ? e.message : "Could not change the tunnel setting");
52
+ } finally {
53
+ setPending(false);
54
+ }
55
+ }
56
+
57
+ return (
58
+ <div className="flex items-center gap-3 p-3 border-b border-border bg-surface">
59
+ <Globe className="size-4 shrink-0 text-text-secondary" />
60
+ <div className="flex-1 min-w-0">
61
+ <div className="text-sm font-medium text-text-primary">Public tunnel</div>
62
+ <p className="text-xs text-text-secondary leading-relaxed truncate">
63
+ {!enabled
64
+ ? "Off — PPM stays reachable on this network only"
65
+ : starting
66
+ ? "Starting…"
67
+ : status.url ?? "On — waiting for a public URL"}
68
+ </p>
69
+ </div>
70
+ {(pending || starting) && <Loader2 className="size-4 shrink-0 animate-spin text-text-subtle" />}
71
+ {/* The control is 20x36; the pseudo-element takes its hit area to 44x60
72
+ so it is tappable on a phone without changing the row's layout. */}
73
+ <Switch
74
+ checked={enabled}
75
+ onCheckedChange={toggle}
76
+ disabled={pending}
77
+ aria-label="Public tunnel"
78
+ className="relative shrink-0 before:absolute before:-inset-3 before:content-['']"
79
+ />
80
+ </div>
81
+ );
82
+ }
@@ -4,6 +4,7 @@ import { tunnelsApi, type TunnelEntry } from "@/lib/api-tunnels";
4
4
  import { copyToClipboard } from "@/lib/clipboard";
5
5
  import { toast } from "sonner";
6
6
  import { NamedTunnelSection } from "@/components/tunnels/named-tunnel/named-tunnel-section";
7
+ import { PublicTunnelSwitch } from "@/components/tunnels/public-tunnel-switch";
7
8
 
8
9
  /** Badge label + style per tunnel source. */
9
10
  const SOURCE_META: Record<TunnelEntry["source"], { label: string; cls: string }> = {
@@ -92,6 +93,9 @@ export function TunnelManagerTab() {
92
93
 
93
94
  return (
94
95
  <div className="flex flex-col h-full w-full bg-background">
96
+ {/* Master switch first: everything below it is moot while the tunnel is off */}
97
+ <PublicTunnelSwitch />
98
+
95
99
  {/* Named tunnel status + setup entry point, above the quick-forward form */}
96
100
  <NamedTunnelSection />
97
101
 
@@ -68,7 +68,20 @@ function DialogContent({
68
68
  <DialogPrimitive.Content
69
69
  data-slot="dialog-content"
70
70
  className={cn(
71
- "fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background text-foreground p-6 shadow-lg duration-200 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg",
71
+ // `grid-cols-[minmax(0,1fr)]` rather than the implicit `auto` column: an
72
+ // auto track's base size is its items' MIN-CONTENT contribution, so one
73
+ // unbreakable string anywhere inside — a systemd unit name, a log line,
74
+ // a path — widens the column past the dialog and every child with it,
75
+ // drawing outside the panel. `overflow-wrap: break-word` does not help,
76
+ // because by specification it does not affect min-content size.
77
+ "fixed top-[50%] left-[50%] z-50 grid grid-cols-[minmax(0,1fr)] w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background text-foreground p-6 shadow-lg duration-200 outline-none data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 sm:max-w-lg",
78
+ // The close button is absolutely positioned over the top-right corner,
79
+ // which is the header's first line — so a title long enough to reach it
80
+ // renders underneath it. Reserve the corner, but only when the button is
81
+ // actually there.
82
+ // A descendant selector, not a child one: several dialogs put the header
83
+ // inside a flex/scroll wrapper.
84
+ showCloseButton && "[&_[data-slot=dialog-header]]:pr-8",
72
85
  className
73
86
  )}
74
87
  {...props}
@@ -0,0 +1,279 @@
1
+ /**
2
+ * A select whose list can be searched: a trigger showing the current choice,
3
+ * and a panel with a filter box over the options.
4
+ *
5
+ * It exists because the lists it serves are the case a native `<select>` or a
6
+ * plain menu handles worst — dozens to hundreds of names that agree for most of
7
+ * their length (`fix/NX-1234-…` branches, `nxsys-backend-nx5833` checkouts), where
8
+ * the only way to the one you want is reading past the ones you do not. The shape
9
+ * is the checkout quick pick's, and it shares that picker's keyboard arithmetic
10
+ * (`moveSelection`) and its selection tint.
11
+ *
12
+ * A Radix popover rather than a panel positioned by hand, because the surfaces
13
+ * that mount it are `overflow-hidden`: a dropdown anchored inside one is clipped at
14
+ * its bottom edge, which shows as a list a few rows tall with no scrollbar and no
15
+ * sign that anything was cut. The portal escapes that, and collision detection
16
+ * keeps it on screen when the panel is docked low in the window. Below `md` it is
17
+ * a bottom sheet instead, per the mobile rules.
18
+ */
19
+ import { useCallback, useEffect, useMemo, useRef, useState, type ElementType } from "react";
20
+ import { Popover } from "radix-ui";
21
+ import { Check, ChevronDown, Search } from "@/lib/icons";
22
+ import { cn } from "@/lib/utils";
23
+ import { useIsMobile } from "@/hooks/use-is-mobile";
24
+ import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
25
+ import { usePortalContainer } from "@/components/ui/portal-container-context";
26
+ import { StartEllipsis } from "@/components/ui/start-ellipsis";
27
+ import { firstSelectable, moveSelection } from "@/lib/git-ref-picker";
28
+ import { rowIndexOf, searchRows, type SearchSelectItem } from "@/lib/search-select-rows";
29
+
30
+ export interface SearchSelectProps {
31
+ value: string;
32
+ items: SearchSelectItem[];
33
+ onChange: (value: string) => void;
34
+ /** Names the control for screen readers, and titles the sheet on mobile. */
35
+ label: string;
36
+ /** The filter box's placeholder — "Search branches". */
37
+ searchPlaceholder: string;
38
+ /** What an empty result says — "No matching branches". */
39
+ emptyText: string;
40
+ /** Leading icon on the trigger, if the surroundings do not already carry one. */
41
+ icon?: ElementType;
42
+ /** Trigger text while `value` names none of the items. */
43
+ placeholder?: string;
44
+ testId?: string;
45
+ /** Width and look, from the caller — the trigger shares a row with everything else. */
46
+ className?: string;
47
+ /**
48
+ * Set this inside a Radix dialog, and only there.
49
+ *
50
+ * A modal dialog traps focus, and the popover is portalled outside it: the
51
+ * dialog's focus scope sees focus land on an element it does not contain and
52
+ * pulls it straight back, so the filter box cannot be typed in at all. A
53
+ * modal popover has a trapped scope of its own, which pushes onto Radix's
54
+ * scope stack and pauses the dialog's — the one arrangement where both
55
+ * behave. It costs a scroll lock and `aria-hidden` on everything behind,
56
+ * which is why it is not the default out in a panel.
57
+ */
58
+ modal?: boolean;
59
+ }
60
+
61
+ export function SearchSelect({
62
+ value, items, onChange, label, searchPlaceholder, emptyText, icon: Icon, placeholder,
63
+ testId, className, modal,
64
+ }: SearchSelectProps) {
65
+ const isMobile = useIsMobile();
66
+ const portalContainer = usePortalContainer();
67
+ const [open, setOpen] = useState(false);
68
+ const [query, setQuery] = useState("");
69
+ const [selected, setSelected] = useState(-1);
70
+ const inputRef = useRef<HTMLInputElement>(null);
71
+ const listRef = useRef<HTMLDivElement>(null);
72
+
73
+ const rows = useMemo(() => searchRows(items, query), [items, query]);
74
+ const current = items.find((i) => i.value === value);
75
+
76
+ /*
77
+ * Highlight the choice already in force when it survives the filter, and the
78
+ * first match otherwise. Opening on row zero instead would put Enter on an
79
+ * option nobody asked for, and on a list this long it hides where you
80
+ * currently are behind several screens of scrolling.
81
+ */
82
+ useEffect(() => {
83
+ const at = rowIndexOf(rows, value);
84
+ setSelected(at >= 0 ? at : firstSelectable(rows));
85
+ }, [rows, value]);
86
+
87
+ // A filter is a question about this opening, not a setting.
88
+ useEffect(() => { if (!open) setQuery(""); }, [open]);
89
+
90
+ useEffect(() => {
91
+ if (!open) return;
92
+ listRef.current?.querySelector<HTMLElement>('[data-active="true"]')?.scrollIntoView?.({ block: "nearest" });
93
+ }, [open, selected]);
94
+
95
+ const pick = useCallback((next: string) => {
96
+ onChange(next);
97
+ setOpen(false);
98
+ }, [onChange]);
99
+
100
+ function handleKeyDown(e: React.KeyboardEvent) {
101
+ switch (e.key) {
102
+ case "ArrowDown":
103
+ e.preventDefault();
104
+ setSelected((i) => moveSelection(rows, i, 1));
105
+ break;
106
+ case "ArrowUp":
107
+ e.preventDefault();
108
+ setSelected((i) => moveSelection(rows, i, -1));
109
+ break;
110
+ case "Enter": {
111
+ e.preventDefault();
112
+ const row = rows[selected];
113
+ if (row?.kind === "item") pick(row.item.value);
114
+ break;
115
+ }
116
+ case "Escape":
117
+ e.preventDefault();
118
+ setOpen(false);
119
+ break;
120
+ }
121
+ }
122
+
123
+ const body = (
124
+ <>
125
+ <div className="flex items-center gap-2 border-b border-border px-2.5 py-2 shrink-0">
126
+ <Search className="size-4 shrink-0 text-text-subtle" />
127
+ <input
128
+ ref={inputRef}
129
+ type="text"
130
+ value={query}
131
+ onChange={(e) => setQuery(e.target.value)}
132
+ placeholder={searchPlaceholder}
133
+ aria-label={`Search ${label.toLowerCase()}`}
134
+ className="min-w-0 flex-1 bg-transparent text-sm text-text-primary outline-none placeholder:text-text-subtle"
135
+ />
136
+ </div>
137
+ <div
138
+ ref={listRef}
139
+ role="listbox"
140
+ aria-label={label}
141
+ className="min-h-0 flex-1 overflow-y-auto py-1"
142
+ data-testid={testId && `${testId}-list`}
143
+ >
144
+ {rows.length === 0 ? (
145
+ <p className="px-3 py-4 text-center text-sm text-text-subtle">{emptyText}</p>
146
+ ) : (
147
+ rows.map((row, i) =>
148
+ row.kind === "separator" ? (
149
+ <div
150
+ key={`sep-${row.label}`}
151
+ className="border-t border-border-soft px-3 pt-2 pb-1 text-[10px] uppercase tracking-wide text-text-3 first:border-t-0 first:pt-1"
152
+ >
153
+ {row.label}
154
+ </div>
155
+ ) : (
156
+ <OptionRow
157
+ key={row.item.value}
158
+ item={row.item}
159
+ active={i === selected}
160
+ picked={row.item.value === value}
161
+ mobile={isMobile}
162
+ onPick={() => pick(row.item.value)}
163
+ onHover={() => setSelected(i)}
164
+ />
165
+ ),
166
+ )
167
+ )}
168
+ </div>
169
+ </>
170
+ );
171
+
172
+ const trigger = (
173
+ <button
174
+ type="button"
175
+ aria-expanded={open}
176
+ // A panel with a filter box in it, not a bare list — and `combobox` would
177
+ // be a promise this button cannot keep, since the text input it would
178
+ // have to own does not exist until the panel is open. Radix says the same
179
+ // thing on the desktop trigger; this is for the sheet, which has no Radix
180
+ // under it.
181
+ aria-haspopup="dialog"
182
+ aria-label={label}
183
+ title={current?.title ?? current?.label ?? value}
184
+ data-testid={testId}
185
+ onClick={isMobile ? () => setOpen(true) : undefined}
186
+ // h-10 under a finger: the rows this sits in are compact by design on a
187
+ // desktop, but the trigger is the one thing in them anyone taps.
188
+ className={cn(
189
+ "flex h-10 items-center gap-1 rounded-md border border-border bg-panel px-2 text-xs text-text-primary min-w-0 md:h-7",
190
+ className,
191
+ )}
192
+ >
193
+ {Icon && <Icon className="size-3.5 shrink-0 text-text-3" />}
194
+ <StartEllipsis>{current?.label ?? (value || placeholder || "")}</StartEllipsis>
195
+ <ChevronDown className="size-3.5 shrink-0 text-text-3" />
196
+ </button>
197
+ );
198
+
199
+ if (isMobile) {
200
+ return (
201
+ <>
202
+ {trigger}
203
+ {/*
204
+ No autofocus here, deliberately: the keyboard would cover most of the
205
+ sheet before the list has been seen once, and the filter box is one
206
+ tap away at the top of it.
207
+ */}
208
+ <BottomSheet open={open} onClose={() => setOpen(false)} className="popover-solid flex max-h-[80dvh] flex-col">
209
+ <div className="shrink-0 px-3 pb-1 text-xs font-medium text-text-2">{label}</div>
210
+ <div className="flex min-h-0 flex-1 flex-col" onKeyDown={handleKeyDown}>{body}</div>
211
+ </BottomSheet>
212
+ </>
213
+ );
214
+ }
215
+
216
+ return (
217
+ <Popover.Root open={open} onOpenChange={setOpen} modal={modal}>
218
+ <Popover.Trigger asChild>{trigger}</Popover.Trigger>
219
+ <Popover.Portal container={portalContainer}>
220
+ <Popover.Content
221
+ align="start"
222
+ sideOffset={4}
223
+ collisionPadding={8}
224
+ onKeyDown={handleKeyDown}
225
+ // Radix focuses the first focusable child, which is already the filter
226
+ // box; saying so explicitly keeps it true if a control is ever added
227
+ // above it.
228
+ onOpenAutoFocus={(e) => { e.preventDefault(); inputRef.current?.focus(); }}
229
+ // `popover-solid`, or the glass themes render the list over whatever
230
+ // is behind the panel.
231
+ className="popover-solid z-50 flex w-[min(26rem,calc(100vw-1.5rem))] flex-col overflow-hidden rounded-md border border-border text-popover-foreground shadow-lg max-h-[min(20rem,var(--radix-popover-content-available-height))]"
232
+ >
233
+ {body}
234
+ </Popover.Content>
235
+ </Popover.Portal>
236
+ </Popover.Root>
237
+ );
238
+ }
239
+
240
+ /**
241
+ * One option.
242
+ *
243
+ * The active tint is `primary/15` rather than shadcn's `accent`, for the reason
244
+ * spelled out in `branch-picker.tsx`: `accent` is a hover *surface* in this app
245
+ * and composites to a contrast ratio of about 1.01 over the panel it sits on,
246
+ * i.e. a keyboard selection nobody can see.
247
+ */
248
+ function OptionRow({ item, active, picked, mobile, onPick, onHover }: {
249
+ item: SearchSelectItem;
250
+ active: boolean;
251
+ picked: boolean;
252
+ mobile: boolean;
253
+ onPick: () => void;
254
+ onHover: () => void;
255
+ }) {
256
+ const Icon = item.icon;
257
+ return (
258
+ <button
259
+ type="button"
260
+ role="option"
261
+ aria-selected={picked}
262
+ data-active={active || undefined}
263
+ data-value={item.value}
264
+ title={item.title}
265
+ onClick={onPick}
266
+ onMouseEnter={onHover}
267
+ className={cn(
268
+ "flex w-full items-center gap-2 px-3 text-left text-sm",
269
+ mobile ? "min-h-11 py-2" : "py-1",
270
+ active ? "bg-primary/15 text-text-primary" : "text-text-2",
271
+ )}
272
+ >
273
+ {Icon && <Icon className="size-3.5 shrink-0 text-text-3" />}
274
+ <StartEllipsis>{item.label}</StartEllipsis>
275
+ {item.hint && <span className="shrink-0 text-[10px] text-text-3">{item.hint}</span>}
276
+ {picked && <Check className="size-3.5 shrink-0 text-primary" />}
277
+ </button>
278
+ );
279
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Ellipsize from the start, so the end of a string — the part that differs —
3
+ * survives.
4
+ *
5
+ * A right-to-left box cuts at its left edge, and `<bdi>` keeps the name itself
6
+ * reading left to right; the isolate is load-bearing rather than tidy, because
7
+ * outside one a leading `.` takes the paragraph's direction and `.gitignore`
8
+ * renders as `gitignore.`. Used for file paths, where the filename is the
9
+ * distinguishing part, and for branch names, where a repository's branches all
10
+ * begin `fix/NX-`.
11
+ */
12
+ export function StartEllipsis({ children }: { children: string }) {
13
+ return (
14
+ <span dir="rtl" className="truncate text-left min-w-0 flex-1">
15
+ <bdi>{children}</bdi>
16
+ </span>
17
+ );
18
+ }
@@ -10,6 +10,8 @@ import { playNotificationSound } from "@/lib/notification-sounds";
10
10
  import { toast } from "sonner";
11
11
  import type { ChatMessage, ChatEvent } from "../../types/chat";
12
12
  import type { BackgroundAgentStatus } from "../../shared/background-agent-status";
13
+ import type { PromptCacheState } from "../../shared/prompt-cache-idle";
14
+ import { prefixTokens } from "../../shared/turn-usage";
13
15
  import type { ChatWsServerMessage, SessionPhase, BackgroundShell, VersionGroup } from "../../types/api";
14
16
  import { useBackgroundOutputStore } from "../stores/background-output-store";
15
17
 
@@ -66,6 +68,8 @@ interface UseChatReturn {
66
68
  pendingApproval: ApprovalRequest | null;
67
69
  contextWindowPct: number | null;
68
70
  compactStatus: "compacting" | null;
71
+ /** Prompt-cache clock for this session; drives the idle re-cache notice. */
72
+ promptCache: PromptCacheState | null;
69
73
  /** MCP servers this session's subprocess reported as needing a sign-in. */
70
74
  mcpNeedsAuth: string[];
71
75
  statusMessage: string | null;
@@ -153,6 +157,7 @@ export function useChat(
153
157
  const [pendingApproval, setPendingApproval] = useState<ApprovalRequest | null>(null);
154
158
  const [contextWindowPct, setContextWindowPct] = useState<number | null>(null);
155
159
  const [compactStatus, setCompactStatus] = useState<"compacting" | null>(null);
160
+ const [promptCache, setPromptCache] = useState<PromptCacheState | null>(null);
156
161
  /** MCP servers this session's subprocess reported as needing a sign-in. */
157
162
  const [mcpNeedsAuth, setMcpNeedsAuth] = useState<string[]>([]);
158
163
  const [backgroundShells, setBackgroundShells] = useState<BackgroundShell[]>([]);
@@ -791,6 +796,25 @@ export function useChat(
791
796
  }
792
797
  return prev;
793
798
  });
799
+ // This turn just rewrote the cache, so the idle clock restarts here. Done locally
800
+ // rather than waiting for the next `session_state`: a tab left open for hours may
801
+ // never reconnect, and that is exactly the case the notice exists for.
802
+ if (doneUsage) {
803
+ setPromptCache((prev) => prev && {
804
+ ...prev,
805
+ lastTurnEndedAt: Date.now(),
806
+ billedPrefixTokens: prefixTokens(doneUsage),
807
+ // Left at its previous value when this turn measured none, rather than cleared:
808
+ // a context does not shrink, so the older figure is still the better answer.
809
+ ...(doneUsage.contextTokens != null && { contextTokens: doneUsage.contextTokens }),
810
+ // Same reason: a turn that only read the cache reports no window, and the one
811
+ // already in hand is still the window this session's cache lives in.
812
+ ...(doneUsage.cacheTtlMs != null && { ttlMs: doneUsage.cacheTtlMs }),
813
+ // Unconditional, unlike the two above: `undefined` here is the turn reporting
814
+ // that it re-cached after a compaction, which has to clear the flag.
815
+ compactedAt: doneUsage.compactedAt,
816
+ });
817
+ }
794
818
  streamingContentRef.current = "";
795
819
  streamingEventsRef.current = [];
796
820
  streamingAccountRef.current = null;
@@ -985,6 +1009,9 @@ export function useChat(
985
1009
  // Sync compact indicator from authoritative server state (covers reconnect).
986
1010
  // state.compactStatus is "compacting" | null — treat undefined as null for back-compat.
987
1011
  setCompactStatus(state.compactStatus === "compacting" ? "compacting" : null);
1012
+ // The server is the only holder of when the cache was last written and how big the
1013
+ // replayed prefix was — neither is in the transcript, so a reload has to be told.
1014
+ setPromptCache((state.promptCache as PromptCacheState | undefined) ?? null);
988
1015
  setMcpNeedsAuth(Array.isArray(state.mcpNeedsAuth) ? state.mcpNeedsAuth : []);
989
1016
  // If idle, refetch history (completed turns) and hide overlay.
990
1017
  // Skip when nothing could have changed: the phase was already idle locally
@@ -1558,6 +1585,7 @@ export function useChat(
1558
1585
  pendingApproval,
1559
1586
  contextWindowPct,
1560
1587
  compactStatus,
1588
+ promptCache,
1561
1589
  mcpNeedsAuth,
1562
1590
  statusMessage,
1563
1591
  sessionTitle,
@@ -3,7 +3,8 @@ import { useTabStore } from "@/stores/tab-store";
3
3
  import { useSettingsStore } from "@/stores/settings-store";
4
4
  import { useProjectStore } from "@/stores/project-store";
5
5
  import { usePanelStore } from "@/stores/panel-store";
6
- import { useKeybindingsStore, parseCombo, eventMatchesCombo } from "@/stores/keybindings-store";
6
+ import { useKeybindingsStore, parseCombo, eventMatchesCombo, matchesDockBacktick } from "@/stores/keybindings-store";
7
+ import { isMobileDevice } from "@/hooks/use-is-mobile";
7
8
  import { useExtensionStore } from "@/stores/extension-store";
8
9
  import { useCompareStore } from "@/stores/compare-store";
9
10
  import { openSettings } from "@/components/settings/open-settings";
@@ -89,9 +90,10 @@ export function useGlobalKeybindings() {
89
90
  const { matchesEvent: m } = useKeybindingsStore.getState();
90
91
  // Mod+S — always prevent browser save dialog
91
92
  if (m(e, "save-prevent")) { e.preventDefault(); }
92
- // toggle-dock (Mod+') fires even when the terminal textarea is focused (VSCode parity).
93
- // It's a modifier combo, so it can't produce a plain quote in the shell.
94
- if (m(e, "toggle-dock")) {
93
+ // toggle-dock (Mod+', and VS Code's Ctrl+` on desktop) fires even when the
94
+ // terminal textarea is focused (VSCode parity). Both are modifier combos, so
95
+ // neither can produce a plain quote or backtick in the shell.
96
+ if (m(e, "toggle-dock") || matchesDockBacktick(e, isMobileDevice())) {
95
97
  e.preventDefault();
96
98
  usePanelStore.getState().toggleDock();
97
99
  }
@@ -126,7 +128,7 @@ export function useGlobalKeybindings() {
126
128
  }
127
129
 
128
130
  // Toggle terminal dock
129
- if (match(e, "toggle-dock")) {
131
+ if (match(e, "toggle-dock") || matchesDockBacktick(e, isMobileDevice())) {
130
132
  e.preventDefault();
131
133
  usePanelStore.getState().toggleDock();
132
134
  return;
@@ -12,11 +12,13 @@
12
12
  * skips, the bridge asks for the whole document back rather than applying a
13
13
  * delta to a copy that is already wrong.
14
14
  */
15
- import { useEffect, useRef, useState } from "react";
15
+ import { useCallback, useEffect, useRef, useState } from "react";
16
16
  import type * as MonacoType from "monaco-editor";
17
+ import { api, projectUrl } from "@/lib/api-client";
17
18
  import {
18
19
  acquireLspConnection,
19
20
  releaseLspConnection,
21
+ retryUnavailableLspDocuments,
20
22
  type LspConnection,
21
23
  type LspDocumentStatus,
22
24
  } from "@/lib/lsp/lsp-client";
@@ -40,6 +42,8 @@ export interface LspState {
40
42
  status: LspDocumentStatus | null;
41
43
  /** Diagnostics for this file, for a Problems view to list. */
42
44
  diagnostics: LspDiagnostic[];
45
+ /** Install the missing server on the host, then take the open files off "not installed". */
46
+ install: (serverId: string) => Promise<void>;
43
47
  }
44
48
 
45
49
  export interface LspDiagnostic {
@@ -166,7 +170,24 @@ export function useLsp({ editor, monaco, projectName, filePath, enabled }: UseLs
166
170
  };
167
171
  }, [active, editor, monaco, projectName, filePath]);
168
172
 
169
- return { status, diagnostics };
173
+ /**
174
+ * The Install button's half in the browser.
175
+ *
176
+ * The retry runs even when the request failed, and deliberately: a long install behind a
177
+ * proxy can time out the fetch while `bun add` finishes anyway, and asking again is how the
178
+ * editor finds out. A real failure costs one extra round trip and the status comes straight
179
+ * back to "not installed", with the error the host gave for it.
180
+ */
181
+ const install = useCallback(async (serverId: string) => {
182
+ if (!projectName) return;
183
+ try {
184
+ await api.post(`${projectUrl(projectName)}/lsp/install`, { serverId });
185
+ } finally {
186
+ retryUnavailableLspDocuments();
187
+ }
188
+ }, [projectName]);
189
+
190
+ return { status, diagnostics, install };
170
191
  }
171
192
 
172
193
  /** Tell the server a save happened, so servers that only analyse on save catch up. */