@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,97 @@
1
+ /** One unit's details and this boot's journal. Bottom sheet below `md`, dialog
2
+ * above — the rule every PPM dialog follows. */
3
+ import { useEffect, useState } from "react";
4
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
5
+ import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
6
+ import { useIsMobile } from "@/hooks/use-is-mobile";
7
+ import { fetchServiceDetails } from "./use-services";
8
+ import { serviceStatusText } from "./service-rows";
9
+ import type { ServiceDetails, ServiceInfo } from "../../../../types/system-services";
10
+
11
+ export interface ServiceDetailsSheetProps {
12
+ target: ServiceInfo | null;
13
+ onClose: () => void;
14
+ }
15
+
16
+ export function ServiceDetailsSheet({ target, onClose }: ServiceDetailsSheetProps) {
17
+ const isMobile = useIsMobile();
18
+ const [details, setDetails] = useState<ServiceDetails | null>(null);
19
+ const [error, setError] = useState<string | null>(null);
20
+
21
+ useEffect(() => {
22
+ if (!target) {
23
+ setDetails(null);
24
+ setError(null);
25
+ return;
26
+ }
27
+ let live = true;
28
+ setDetails(null);
29
+ setError(null);
30
+ fetchServiceDetails(target.scope, target.unit)
31
+ .then((d) => { if (live) setDetails(d); })
32
+ .catch((e: unknown) => { if (live) setError(e instanceof Error ? e.message : "Could not read the unit"); });
33
+ return () => { live = false; };
34
+ }, [target]);
35
+
36
+ if (!target) return null;
37
+
38
+ const body = (
39
+ <div className="space-y-3" data-testid="sysmon-service-details" data-unit={target.unit}>
40
+ <p className="text-xs text-text-subtle">{details?.description || target.description || serviceStatusText(target)}</p>
41
+ <dl className="grid grid-cols-2 gap-x-4 gap-y-2 text-xs">
42
+ <Field label="State" value={serviceStatusText(details ?? target)} />
43
+ <Field label="Main PID" value={(details ?? target).mainPid ?? "—"} />
44
+ <Field label="User" value={details?.user ?? "—"} />
45
+ <Field label="Group" value={details?.group ?? "—"} />
46
+ <Field label="Scope" value={target.scope} />
47
+ <Field label="Unit file" value={details?.fragmentPath ?? "—"} />
48
+ </dl>
49
+ <div className="space-y-1">
50
+ <h4 className="text-xs font-medium text-text-secondary">Log (this boot)</h4>
51
+ <div className="rounded-md border border-border bg-surface-hover/40 max-h-64 overflow-y-auto p-2">
52
+ {error && <p className="text-xs text-error">{error}</p>}
53
+ {!error && details === null && <p className="text-xs text-text-subtle">Reading the journal…</p>}
54
+ {details?.logs.length === 0 && <p className="text-xs text-text-subtle">No entries this boot.</p>}
55
+ {details?.logs.map((line, i) => (
56
+ <p key={`${line.ts}-${i}`} className="text-[11px] font-mono whitespace-pre-wrap break-words">
57
+ <span className="text-text-subtle">{new Date(line.ts).toLocaleTimeString()} </span>
58
+ {line.message}
59
+ </p>
60
+ ))}
61
+ </div>
62
+ </div>
63
+ </div>
64
+ );
65
+
66
+ if (isMobile) {
67
+ return (
68
+ <BottomSheet open onClose={onClose}>
69
+ <div className="px-4 pb-4 space-y-3">
70
+ <h2 className="text-base font-semibold break-all">{target.unit}</h2>
71
+ {body}
72
+ </div>
73
+ </BottomSheet>
74
+ );
75
+ }
76
+ return (
77
+ <Dialog open onOpenChange={(open) => !open && onClose()}>
78
+ {/* `sm:` because the primitive caps at `sm:max-w-lg`: a bare `max-w-2xl`
79
+ loses to it at every width where it would have mattered. */}
80
+ <DialogContent className="sm:max-w-2xl">
81
+ <DialogHeader>
82
+ <DialogTitle className="break-all">{target.unit}</DialogTitle>
83
+ </DialogHeader>
84
+ {body}
85
+ </DialogContent>
86
+ </Dialog>
87
+ );
88
+ }
89
+
90
+ function Field({ label, value }: { label: string; value: string | number }) {
91
+ return (
92
+ <div className="min-w-0">
93
+ <dt className="text-text-subtle">{label}</dt>
94
+ <dd className="truncate" title={String(value)}>{value}</dd>
95
+ </div>
96
+ );
97
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Live figures per unit for the Services page — Mission Center's PID, CPU,
3
+ * Memory, Swap, Drive, GPU and GPU Memory columns.
4
+ *
5
+ * The roll-up is done HERE, from the metrics stream's process rows, rather than
6
+ * server-side in the Services route. The route is two `systemctl` spawns on a 3 s
7
+ * poll with no counter state of its own, so computing CPU% there would mean a
8
+ * second set of deltas over a second interval — and the same process would then
9
+ * report two different CPU figures on two pages of the same window. Every figure
10
+ * below is the one the Processes tab is already showing, summed.
11
+ *
12
+ * Pure and React-free; relative imports only.
13
+ */
14
+ import type { ProcessInfo } from "../../../../types/system-metrics";
15
+ import type { ServiceInfo } from "../../../../types/system-services";
16
+
17
+ export interface UnitResources {
18
+ /** Processes in the unit's cgroup, which is not the same as its `MainPID`:
19
+ * a unit with forked workers has one main pid and many processes. */
20
+ count: number;
21
+ cpu: number;
22
+ ramMB: number;
23
+ /** Optional exactly as on `ProcessInfo`: the sum over members that HAVE a
24
+ * value, `undefined` when none does — so an unmeasurable column stays an em
25
+ * dash instead of collapsing to a confident 0. */
26
+ swapMB?: number;
27
+ diskReadBps?: number;
28
+ diskWriteBps?: number;
29
+ gpuPct?: number;
30
+ gpuMemMB?: number;
31
+ }
32
+
33
+ function addOptional(sum: number | undefined, value: number | undefined): number | undefined {
34
+ if (value === undefined) return sum;
35
+ return (sum ?? 0) + value;
36
+ }
37
+
38
+ /** `"<scope>:<unit>"` → summed figures. Rows with no `unitKey` — kernel threads,
39
+ * anything outside a unit — are simply not in any bucket. */
40
+ export function rollUpByUnit(processes: readonly ProcessInfo[]): Map<string, UnitResources> {
41
+ const byUnit = new Map<string, UnitResources>();
42
+ for (const p of processes) {
43
+ if (!p.unitKey) continue;
44
+ const row = byUnit.get(p.unitKey) ?? { count: 0, cpu: 0, ramMB: 0 };
45
+ row.count += 1;
46
+ row.cpu += p.cpu;
47
+ row.ramMB += p.ramMB;
48
+ row.swapMB = addOptional(row.swapMB, p.swapMB);
49
+ row.diskReadBps = addOptional(row.diskReadBps, p.diskReadBps);
50
+ row.diskWriteBps = addOptional(row.diskWriteBps, p.diskWriteBps);
51
+ row.gpuPct = addOptional(row.gpuPct, p.gpuPct);
52
+ row.gpuMemMB = addOptional(row.gpuMemMB, p.gpuMemMB);
53
+ byUnit.set(p.unitKey, row);
54
+ }
55
+ // A GPU engine can only be busy for the interval that passed, however many of
56
+ // a unit's processes were queueing work on it.
57
+ for (const row of byUnit.values()) {
58
+ row.cpu = Math.round(row.cpu * 10) / 10;
59
+ row.ramMB = Math.round(row.ramMB * 10) / 10;
60
+ if (row.gpuPct !== undefined) row.gpuPct = Math.min(100, Math.round(row.gpuPct * 10) / 10);
61
+ }
62
+ return byUnit;
63
+ }
64
+
65
+ export function unitKeyOf(service: ServiceInfo): string {
66
+ return `${service.scope}:${service.unit}`;
67
+ }
68
+
69
+ /** What a unit with no processes gets: zeros, not dashes. Owning nothing really
70
+ * is using nothing, which is a reading — the em dash is reserved for a figure
71
+ * this host cannot measure at all. */
72
+ export const IDLE_UNIT: UnitResources = Object.freeze({
73
+ count: 0, cpu: 0, ramMB: 0, swapMB: 0, diskReadBps: 0, diskWriteBps: 0, gpuPct: 0, gpuMemMB: 0,
74
+ });
75
+
76
+ /** Unit types that can hold processes at all. Everything else on this page —
77
+ * `.socket`, `.mount` — owns nothing by construction: a socket's processes live
78
+ * in the *service* it activates, and the socket itself has no `MainPID` and
79
+ * `TasksCurrent=0` even while systemd calls it `running`. */
80
+ const PROCESS_OWNING_SUFFIXES = [".service", ".scope"] as const;
81
+
82
+ /**
83
+ * `ActiveState` cannot decide whether a unit ought to have processes, and using
84
+ * it puts an em dash on 97 of this host's 222 rows: systemd reports a mount as
85
+ * `active (mounted)`, a socket as `active (listening)` and a finished oneshot as
86
+ * `active (exited)`, and every one of those owns nothing by construction. Those
87
+ * are real zeros.
88
+ *
89
+ * `SubState` is most of the discriminator — only `running` asserts there are live
90
+ * processes — but not all of it, because a LISTENING socket is also reported as
91
+ * `running`: `systemctl show -p SubState docker.socket` answers `running` beside
92
+ * an empty `MainPID` and `TasksCurrent=0`. That accounted for 14 of the 15 rows
93
+ * still dashed after the `SubState` fix, so the unit's own type has to agree.
94
+ */
95
+ export function resourcesFor(
96
+ service: ServiceInfo,
97
+ byUnit: ReadonlyMap<string, UnitResources> | null,
98
+ ): UnitResources | undefined {
99
+ if (!byUnit) return undefined;
100
+ const found = byUnit.get(unitKeyOf(service));
101
+ if (found) return found;
102
+ const couldHaveProcesses = service.subState === "running"
103
+ && PROCESS_OWNING_SUFFIXES.some((suffix) => service.unit.endsWith(suffix));
104
+ return couldHaveProcesses ? undefined : IDLE_UNIT;
105
+ }
@@ -0,0 +1,146 @@
1
+ /**
2
+ * One unit in the Services list.
3
+ *
4
+ * The row's tap opens the details; the actions live in an adaptive context menu
5
+ * (right-click on a mouse, long-press on a touch screen). The tap target is a
6
+ * real button INSIDE the trigger, because the adaptive menu only suppresses the
7
+ * click that follows a long press — it has no tap handler of its own.
8
+ *
9
+ * The row is a CSS grid on the same template as the header above it, so a cell
10
+ * and its column name line up. Every figure it shows is `undefined` when this
11
+ * host or this tick could not measure it, and renders as an em dash: a unit that
12
+ * owns no processes is a real zero, a unit whose processes have not been sampled
13
+ * yet is not.
14
+ */
15
+ import {
16
+ ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger,
17
+ } from "@/components/ui/adaptive-context-menu";
18
+ import { cn } from "@/lib/utils";
19
+ import { formatDiskCell } from "../process-row-format";
20
+ import { formatRam } from "@/lib/format-bytes";
21
+ import { serviceStatusText, serviceTone, type ServiceTone } from "./service-rows";
22
+ import { SERVICE_COLUMNS, SERVICE_ROW_GRID_CLASS, columnVisibilityClass } from "./service-columns";
23
+ import type { UnitResources } from "./service-resources";
24
+ import type { ServiceColumnKey } from "./service-columns";
25
+ import type { ServiceAction, ServiceInfo } from "../../../../types/system-services";
26
+ import { SERVICE_ACTIONS } from "../../../../types/system-services";
27
+
28
+ const TONE_CLASS: Record<ServiceTone, string> = {
29
+ failed: "bg-error",
30
+ running: "bg-success",
31
+ busy: "bg-warning animate-pulse",
32
+ idle: "bg-text-subtle/40",
33
+ };
34
+
35
+ const ACTION_LABELS: Record<ServiceAction, string> = {
36
+ start: "Start",
37
+ stop: "Stop",
38
+ restart: "Restart",
39
+ enable: "Enable at boot",
40
+ disable: "Disable at boot",
41
+ };
42
+
43
+ /** Stopping something is destructive in the menu's sense; starting it is not. */
44
+ const DESTRUCTIVE: readonly ServiceAction[] = ["stop", "disable"];
45
+
46
+ /** Visibility per column key, taken from the same table the grid template is
47
+ * built from so a cell cannot be shown at a width that has no track for it. */
48
+ const CELL_CLASS: Record<ServiceColumnKey, string> = Object.fromEntries(
49
+ SERVICE_COLUMNS.map((c) => [c.key, columnVisibilityClass(c)]),
50
+ ) as Record<ServiceColumnKey, string>;
51
+
52
+ /** `undefined` is "not measured", never 0 — the rule every cell on this page
53
+ * follows, and the reason these are not `?? 0`. */
54
+ const ramCell = (mb?: number) => (mb === undefined ? "—" : formatRam(mb));
55
+ const pctCell = (pct: number | undefined, digits: number) =>
56
+ pct === undefined ? "—" : `${pct.toFixed(digits)}%`;
57
+
58
+ function Cell({ column, children }: { column: ServiceColumnKey; children: React.ReactNode }) {
59
+ return (
60
+ <span className={cn("text-right text-[11px] tabular-nums text-text-subtle truncate", CELL_CLASS[column])}>
61
+ {children}
62
+ </span>
63
+ );
64
+ }
65
+
66
+ export interface ServiceRowProps {
67
+ service: ServiceInfo;
68
+ /** Live roll-up over the unit's cgroup. Undefined = not measured this tick,
69
+ * which renders as em dashes rather than as an idle unit. */
70
+ resources?: UnitResources;
71
+ onOpen: (service: ServiceInfo) => void;
72
+ onAction: (service: ServiceInfo, action: ServiceAction) => void;
73
+ }
74
+
75
+ export function ServiceRow({ service, resources, onOpen, onAction }: ServiceRowProps) {
76
+ const tone = serviceTone(service);
77
+ const allowed = SERVICE_ACTIONS.filter((a) => service.refused?.[a] === undefined);
78
+ // Every reason is the same sentence when a unit is refused wholesale, so the
79
+ // footer shows it once rather than repeating it per hidden item.
80
+ const reason = SERVICE_ACTIONS.map((a) => service.refused?.[a]).find(Boolean);
81
+
82
+ return (
83
+ <ContextMenu>
84
+ <ContextMenuTrigger asChild>
85
+ <div className="select-none">
86
+ <button
87
+ type="button"
88
+ onClick={() => onOpen(service)}
89
+ data-testid="sysmon-service-row"
90
+ data-unit={service.unit}
91
+ data-tone={tone}
92
+ data-cpu={resources?.cpu}
93
+ data-ram-mb={resources?.ramMB}
94
+ className={cn(
95
+ "w-full min-h-11 px-3 py-2 items-center text-left hover:bg-surface-hover transition-colors",
96
+ SERVICE_ROW_GRID_CLASS,
97
+ )}
98
+ >
99
+ <span className="flex items-center gap-2 min-w-0">
100
+ <span className={cn("size-2 rounded-full shrink-0", TONE_CLASS[tone])} aria-hidden />
101
+ <span className="flex-1 min-w-0">
102
+ <span className="flex items-center gap-1.5 min-w-0">
103
+ <span className="text-sm truncate">{service.unit}</span>
104
+ {/* Beside the name rather than in a column of its own: it is a
105
+ property of the unit file, not a measurement, and a ninth
106
+ track would cost the name column 60px on every row. */}
107
+ {service.enabled && (
108
+ <span className="shrink-0 text-[10px] px-1 py-px rounded bg-surface-hover text-text-subtle">
109
+ enabled
110
+ </span>
111
+ )}
112
+ </span>
113
+ <span className="block text-[11px] text-text-subtle truncate">
114
+ {service.description || serviceStatusText(service)}
115
+ </span>
116
+ </span>
117
+ </span>
118
+ <Cell column="pid">{service.mainPid ?? "—"}</Cell>
119
+ <Cell column="cpu">{pctCell(resources?.cpu, 1)}</Cell>
120
+ <Cell column="ram">{ramCell(resources?.ramMB)}</Cell>
121
+ <Cell column="swap">{ramCell(resources?.swapMB)}</Cell>
122
+ <Cell column="disk">{formatDiskCell(resources?.diskReadBps, resources?.diskWriteBps)}</Cell>
123
+ <Cell column="gpu">{pctCell(resources?.gpuPct, 0)}</Cell>
124
+ <Cell column="gpuMem">{ramCell(resources?.gpuMemMB)}</Cell>
125
+ </button>
126
+ </div>
127
+ </ContextMenuTrigger>
128
+ <ContextMenuContent>
129
+ {allowed.map((action) => (
130
+ <ContextMenuItem
131
+ key={action}
132
+ variant={DESTRUCTIVE.includes(action) ? "destructive" : undefined}
133
+ onSelect={() => onAction(service, action)}
134
+ >
135
+ {ACTION_LABELS[action]}
136
+ </ContextMenuItem>
137
+ ))}
138
+ {allowed.length > 0 && <ContextMenuSeparator />}
139
+ <ContextMenuItem onSelect={() => onOpen(service)}>Details and log</ContextMenuItem>
140
+ {reason && (
141
+ <p className="px-2 py-1.5 text-[11px] text-text-subtle max-w-64">{reason}</p>
142
+ )}
143
+ </ContextMenuContent>
144
+ </ContextMenu>
145
+ );
146
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * The Services page's list shaping - search, filter, ordering and the header
3
+ * counts. Pure and React-free; relative imports only.
4
+ *
5
+ * Mission Center shows one flat list per scope with a search box. PPM keeps the
6
+ * two scopes as sections because a user unit and a system unit of the same name
7
+ * are different units with very different consequences, and a flat list gives no
8
+ * way to tell them apart.
9
+ */
10
+ import type { ServiceInfo, ServiceScope } from "../../../../types/system-services";
11
+
12
+ export type ServiceFilter = "all" | "running" | "failed" | "enabled";
13
+
14
+ export const SERVICE_FILTERS: readonly ServiceFilter[] = ["all", "running", "failed", "enabled"];
15
+
16
+ export function matchesFilter(service: ServiceInfo, filter: ServiceFilter): boolean {
17
+ switch (filter) {
18
+ case "running": return service.running;
19
+ case "failed": return service.failed;
20
+ case "enabled": return service.enabled;
21
+ default: return true;
22
+ }
23
+ }
24
+
25
+ /** Matches the unit name and the description, which is where a user looks for
26
+ * "bluetooth" when the unit is called `bluez`. */
27
+ export function matchesQuery(service: ServiceInfo, query: string): boolean {
28
+ const needle = query.trim().toLowerCase();
29
+ if (!needle) return true;
30
+ return service.unit.toLowerCase().includes(needle)
31
+ || service.description.toLowerCase().includes(needle);
32
+ }
33
+
34
+ /**
35
+ * Failed first, then running, then everything else, alphabetically within each
36
+ * band. The point of the page is usually a unit that is not doing what it should,
37
+ * so it must not be hundreds of rows down.
38
+ */
39
+ export function compareServices(a: ServiceInfo, b: ServiceInfo): number {
40
+ const band = (s: ServiceInfo) => (s.failed ? 0 : s.running ? 1 : 2);
41
+ const diff = band(a) - band(b);
42
+ return diff !== 0 ? diff : a.unit.localeCompare(b.unit);
43
+ }
44
+
45
+ export function shapeServices(
46
+ services: readonly ServiceInfo[],
47
+ scope: ServiceScope,
48
+ filter: ServiceFilter,
49
+ query: string,
50
+ ): ServiceInfo[] {
51
+ return services
52
+ .filter((s) => s.scope === scope && matchesFilter(s, filter) && matchesQuery(s, query))
53
+ .sort(compareServices);
54
+ }
55
+
56
+ export interface ServiceCounts {
57
+ total: number;
58
+ running: number;
59
+ failed: number;
60
+ }
61
+
62
+ export function serviceCounts(services: readonly ServiceInfo[], scope?: ServiceScope): ServiceCounts {
63
+ const scoped = scope ? services.filter((s) => s.scope === scope) : services;
64
+ return {
65
+ total: scoped.length,
66
+ running: scoped.filter((s) => s.running).length,
67
+ failed: scoped.filter((s) => s.failed).length,
68
+ };
69
+ }
70
+
71
+ /** The dot beside a row. `activating` and `reloading` are deliberately neither
72
+ * running nor failed, so they get their own colour rather than borrowing one. */
73
+ export type ServiceTone = "failed" | "running" | "busy" | "idle";
74
+
75
+ export function serviceTone(service: ServiceInfo): ServiceTone {
76
+ if (service.failed) return "failed";
77
+ if (service.running) return "running";
78
+ if (service.activeState === "activating" || service.activeState === "deactivating"
79
+ || service.activeState === "reloading") return "busy";
80
+ return "idle";
81
+ }
82
+
83
+ /** What the row says under the unit name when there is no description. */
84
+ export function serviceStatusText(service: ServiceInfo): string {
85
+ const state = `${service.activeState} (${service.subState})`;
86
+ return service.unitFileState ? `${state} · ${service.unitFileState}` : state;
87
+ }
88
+
89
+ /** True when every action is refused, so the row's menu is offered at all. */
90
+ export function hasAnyAction(service: ServiceInfo, actions: readonly string[]): boolean {
91
+ return actions.some((a) => service.refused?.[a as keyof typeof service.refused] === undefined);
92
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Ordering for the Services table.
3
+ *
4
+ * Separate from `process-table-sort.ts` rather than sharing it, for two reasons
5
+ * that are both about this page's data and not about tidiness. A service row's
6
+ * figures are `UnitResources | undefined` — the WHOLE row can be unmeasured,
7
+ * where a process row always has a CPU and a memory number — and `SortableFields`
8
+ * types those two as required, so sharing it would mean passing 0 for "not
9
+ * measured" and losing exactly the distinction the sort has to respect. And the
10
+ * Services table sorts on `pid`, which is a systemd property rather than a
11
+ * metric and is not in `SortKey` at all.
12
+ *
13
+ * The rule it does share, deliberately: **an unmeasured value sorts last in
14
+ * either direction**. It is not a small value, it is the absence of one, and a
15
+ * column of em dashes at the top of an ascending sort would read as "these units
16
+ * use the least".
17
+ *
18
+ * Pure, React-free, relative imports only.
19
+ */
20
+ import { compareServices } from "./service-rows";
21
+ import type { UnitResources } from "./service-resources";
22
+ import type { ServiceColumnKey } from "./service-columns";
23
+ import type { ServiceInfo } from "../../../../types/system-services";
24
+ import type { SortDir } from "../../../../types/system-metrics";
25
+
26
+ export type ServiceSortKey = ServiceColumnKey;
27
+
28
+ /** A unit paired with the roll-up over its cgroup for this tick. */
29
+ export interface ServiceListRow {
30
+ service: ServiceInfo;
31
+ resources?: UnitResources;
32
+ }
33
+
34
+ /** `undefined` only when NEITHER half is measured — the same rule the Drive cell
35
+ * formats by, so the column sorts on the number it is showing. */
36
+ function sumPair(a?: number, b?: number): number | undefined {
37
+ if (a === undefined && b === undefined) return undefined;
38
+ return (a ?? 0) + (b ?? 0);
39
+ }
40
+
41
+ /** The comparable number behind a column, or `undefined` for "not measured".
42
+ * `name` is not here because it compares as text. */
43
+ export function sortValueOf(row: ServiceListRow, key: Exclude<ServiceSortKey, "name">): number | undefined {
44
+ const r = row.resources;
45
+ switch (key) {
46
+ // A unit with no main process is not a unit with pid 0.
47
+ case "pid": return row.service.mainPid ?? undefined;
48
+ case "cpu": return r?.cpu;
49
+ case "ram": return r?.ramMB;
50
+ case "swap": return r?.swapMB;
51
+ case "disk": return sumPair(r?.diskReadBps, r?.diskWriteBps);
52
+ case "gpu": return r?.gpuPct;
53
+ case "gpuMem": return r?.gpuMemMB;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * `key === null` is the page's own default — failed first, then running, then
59
+ * alphabetically — which is what the third click of a column header returns to.
60
+ * That default is the reason the page is usually opened at all, so it has to
61
+ * remain reachable rather than being replaced by whichever column was last used.
62
+ *
63
+ * Ties break on the unit name in every branch. Without it the list is re-sorted
64
+ * from a fresh array on each 2 s tick, and the hundred-odd units that all read
65
+ * 0% would swap places on every one of them.
66
+ */
67
+ export function sortServiceRows(
68
+ rows: readonly ServiceListRow[],
69
+ key: ServiceSortKey | null,
70
+ dir: SortDir,
71
+ ): ServiceListRow[] {
72
+ if (key === null) return [...rows].sort((a, b) => compareServices(a.service, b.service));
73
+
74
+ if (key === "name") {
75
+ return [...rows].sort((a, b) => {
76
+ const cmp = a.service.unit.localeCompare(b.service.unit);
77
+ return dir === "asc" ? cmp : -cmp;
78
+ });
79
+ }
80
+
81
+ return [...rows].sort((a, b) => {
82
+ const av = sortValueOf(a, key);
83
+ const bv = sortValueOf(b, key);
84
+ if (av === undefined && bv === undefined) return a.service.unit.localeCompare(b.service.unit);
85
+ if (av === undefined) return 1;
86
+ if (bv === undefined) return -1;
87
+ if (av === bv) return a.service.unit.localeCompare(b.service.unit);
88
+ return dir === "asc" ? av - bv : bv - av;
89
+ });
90
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The Services table's header row: the column names, and the click that sorts by
3
+ * them.
4
+ *
5
+ * It is `sticky` rather than a fixed band above the scroller because the list is
6
+ * one scroll container shared with the rows — a header that scrolls away on a
7
+ * 222-unit list stops answering the only question it exists to answer, which is
8
+ * what the fourth number along is.
9
+ */
10
+ import { cn } from "@/lib/utils";
11
+ import { SortableHeader } from "../sortable-header";
12
+ import {
13
+ SERVICE_COLUMNS, SERVICE_ROW_GRID_CLASS, columnVisibilityClass,
14
+ } from "./service-columns";
15
+ import type { ServiceSortKey } from "./service-sort";
16
+ import type { SortDir } from "../../../../types/system-metrics";
17
+
18
+ export interface ServicesHeaderProps {
19
+ sortKey: ServiceSortKey | null;
20
+ sortDir: SortDir;
21
+ onSort: (key: ServiceSortKey) => void;
22
+ }
23
+
24
+ export function ServicesHeader({ sortKey, sortDir, onSort }: ServicesHeaderProps) {
25
+ return (
26
+ <div
27
+ role="row"
28
+ data-testid="sysmon-services-header"
29
+ className={cn(
30
+ "sticky top-0 z-10 px-3 bg-background border-b border-border text-[11px] text-text-subtle",
31
+ SERVICE_ROW_GRID_CLASS,
32
+ )}
33
+ >
34
+ {SERVICE_COLUMNS.map((column) => (
35
+ <SortableHeader
36
+ key={column.key}
37
+ label={column.label}
38
+ field={column.key}
39
+ activeKey={sortKey}
40
+ activeDir={sortDir}
41
+ onClick={onSort}
42
+ align={column.align}
43
+ testId={`sysmon-services-sort-${column.key}`}
44
+ // `px-0` beats the header's own `px-2`: the cells below have none, and
45
+ // 8px of padding on one of the two is how a column stops lining up.
46
+ className={cn("px-0", columnVisibilityClass(column))}
47
+ />
48
+ ))}
49
+ </div>
50
+ );
51
+ }